Subversion Repositories Applications.annuaire

Compare Revisions

No changes between revisions

Ignore whitespace Rev 41 → Rev 42

/trunk/composants/openid/Auth/OpenID/URINorm.php
New file
0,0 → 1,231
<?php
 
/**
* URI normalization routines.
*
* @package OpenID
* @author JanRain, Inc. <openid@janrain.com>
* @copyright 2005 Janrain, Inc.
* @license http://www.gnu.org/copyleft/lesser.html LGPL
*/
 
require_once 'Services/Yadis/Misc.php';
 
// from appendix B of rfc 3986 (http://www.ietf.org/rfc/rfc3986.txt)
function Auth_OpenID_getURIPattern()
{
return '&^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?&';
}
 
function Auth_OpenID_getAuthorityPattern()
{
return '/^([^@]*@)?([^:]*)(:.*)?/';
}
 
function Auth_OpenID_getEncodedPattern()
{
return '/%([0-9A-Fa-f]{2})/';
}
 
function Auth_OpenID_getUnreserved()
{
$_unreserved = array();
for ($i = 0; $i < 256; $i++) {
$_unreserved[$i] = false;
}
 
for ($i = ord('A'); $i <= ord('Z'); $i++) {
$_unreserved[$i] = true;
}
 
for ($i = ord('0'); $i <= ord('9'); $i++) {
$_unreserved[$i] = true;
}
 
for ($i = ord('a'); $i <= ord('z'); $i++) {
$_unreserved[$i] = true;
}
 
$_unreserved[ord('-')] = true;
$_unreserved[ord('.')] = true;
$_unreserved[ord('_')] = true;
$_unreserved[ord('~')] = true;
 
return $_unreserved;
}
 
function Auth_OpenID_getEscapeRE()
{
$parts = array();
foreach (array_merge(Services_Yadis_getUCSChars(),
Services_Yadis_getIPrivateChars()) as $pair) {
list($m, $n) = $pair;
$parts[] = sprintf("%s-%s", chr($m), chr($n));
}
 
return sprintf('[%s]', implode('', $parts));
}
 
function Auth_OpenID_pct_encoded_replace_unreserved($mo)
{
$_unreserved = Auth_OpenID_getUnreserved();
 
$i = intval($mo[1], 16);
if ($_unreserved[$i]) {
return chr($i);
} else {
return strtoupper($mo[0]);
}
 
return $mo[0];
}
 
function Auth_OpenID_pct_encoded_replace($mo)
{
return chr(intval($mo[1], 16));
}
 
function Auth_OpenID_remove_dot_segments($path)
{
$result_segments = array();
while ($path) {
if (Services_Yadis_startswith($path, '../')) {
$path = substr($path, 3);
} else if (Services_Yadis_startswith($path, './')) {
$path = substr($path, 2);
} else if (Services_Yadis_startswith($path, '/./')) {
$path = substr($path, 2);
} else if ($path == '/.') {
$path = '/';
} else if (Services_Yadis_startswith($path, '/../')) {
$path = substr($path, 3);
if ($result_segments) {
array_pop($result_segments);
}
} else if ($path == '/..') {
$path = '/';
if ($result_segments) {
array_pop($result_segments);
}
} else if (($path == '..') ||
($path == '.')) {
$path = '';
} else {
$i = 0;
if ($path[0] == '/') {
$i = 1;
}
$i = strpos($path, '/', $i);
if ($i === false) {
$i = strlen($path);
}
$result_segments[] = substr($path, 0, $i);
$path = substr($path, $i);
}
}
 
return implode('', $result_segments);
}
 
function Auth_OpenID_urinorm($uri)
{
$uri_matches = array();
preg_match(Auth_OpenID_getURIPattern(), $uri, $uri_matches);
 
if (count($uri_matches) < 9) {
for ($i = count($uri_matches); $i <= 9; $i++) {
$uri_matches[] = '';
}
}
 
$scheme = $uri_matches[2];
if ($scheme) {
$scheme = strtolower($scheme);
}
 
$scheme = $uri_matches[2];
if ($scheme === '') {
// No scheme specified
return null;
}
 
$scheme = strtolower($scheme);
if (!in_array($scheme, array('http', 'https'))) {
// Not an absolute HTTP or HTTPS URI
return null;
}
 
$authority = $uri_matches[4];
if ($authority === '') {
// Not an absolute URI
return null;
}
 
$authority_matches = array();
preg_match(Auth_OpenID_getAuthorityPattern(),
$authority, $authority_matches);
if (count($authority_matches) === 0) {
// URI does not have a valid authority
return null;
}
 
if (count($authority_matches) < 4) {
for ($i = count($authority_matches); $i <= 4; $i++) {
$authority_matches[] = '';
}
}
 
list($_whole, $userinfo, $host, $port) = $authority_matches;
 
if ($userinfo === null) {
$userinfo = '';
}
 
if (strpos($host, '%') !== -1) {
$host = strtolower($host);
$host = preg_replace_callback(
Auth_OpenID_getEncodedPattern(),
'Auth_OpenID_pct_encoded_replace', $host);
// NO IDNA.
// $host = unicode($host, 'utf-8').encode('idna');
} else {
$host = strtolower($host);
}
 
if ($port) {
if (($port == ':') ||
($scheme == 'http' && $port == ':80') ||
($scheme == 'https' && $port == ':443')) {
$port = '';
}
} else {
$port = '';
}
 
$authority = $userinfo . $host . $port;
 
$path = $uri_matches[5];
$path = preg_replace_callback(
Auth_OpenID_getEncodedPattern(),
'Auth_OpenID_pct_encoded_replace_unreserved', $path);
 
$path = Auth_OpenID_remove_dot_segments($path);
if (!$path) {
$path = '/';
}
 
$query = $uri_matches[6];
if ($query === null) {
$query = '';
}
 
$fragment = $uri_matches[8];
if ($fragment === null) {
$fragment = '';
}
 
return $scheme . '://' . $authority . $path . $query . $fragment;
}
 
?>
/trunk/composants/openid/Auth/OpenID/Consumer.php
New file
0,0 → 1,1186
<?php
 
/**
* This module documents the main interface with the OpenID consumer
* library. The only part of the library which has to be used and
* isn't documented in full here is the store required to create an
* Auth_OpenID_Consumer instance. More on the abstract store type and
* concrete implementations of it that are provided in the
* documentation for the Auth_OpenID_Consumer constructor.
*
* OVERVIEW
*
* The OpenID identity verification process most commonly uses the
* following steps, as visible to the user of this library:
*
* 1. The user enters their OpenID into a field on the consumer's
* site, and hits a login button.
* 2. The consumer site discovers the user's OpenID server using the
* YADIS protocol.
* 3. The consumer site sends the browser a redirect to the identity
* server. This is the authentication request as described in
* the OpenID specification.
* 4. The identity server's site sends the browser a redirect back
* to the consumer site. This redirect contains the server's
* response to the authentication request.
*
* The most important part of the flow to note is the consumer's site
* must handle two separate HTTP requests in order to perform the full
* identity check.
*
* LIBRARY DESIGN
*
* This consumer library is designed with that flow in mind. The goal
* is to make it as easy as possible to perform the above steps
* securely.
*
* At a high level, there are two important parts in the consumer
* library. The first important part is this module, which contains
* the interface to actually use this library. The second is the
* Auth_OpenID_Interface class, which describes the interface to use
* if you need to create a custom method for storing the state this
* library needs to maintain between requests.
*
* In general, the second part is less important for users of the
* library to know about, as several implementations are provided
* which cover a wide variety of situations in which consumers may use
* the library.
*
* This module contains a class, Auth_OpenID_Consumer, with methods
* corresponding to the actions necessary in each of steps 2, 3, and 4
* described in the overview. Use of this library should be as easy
* as creating an Auth_OpenID_Consumer instance and calling the
* methods appropriate for the action the site wants to take.
*
* STORES AND DUMB MODE
*
* OpenID is a protocol that works best when the consumer site is able
* to store some state. This is the normal mode of operation for the
* protocol, and is sometimes referred to as smart mode. There is
* also a fallback mode, known as dumb mode, which is available when
* the consumer site is not able to store state. This mode should be
* avoided when possible, as it leaves the implementation more
* vulnerable to replay attacks.
*
* The mode the library works in for normal operation is determined by
* the store that it is given. The store is an abstraction that
* handles the data that the consumer needs to manage between http
* requests in order to operate efficiently and securely.
*
* Several store implementation are provided, and the interface is
* fully documented so that custom stores can be used as well. See
* the documentation for the Auth_OpenID_Consumer class for more
* information on the interface for stores. The implementations that
* are provided allow the consumer site to store the necessary data in
* several different ways, including several SQL databases and normal
* files on disk.
*
* There is an additional concrete store provided that puts the system
* in dumb mode. This is not recommended, as it removes the library's
* ability to stop replay attacks reliably. It still uses time-based
* checking to make replay attacks only possible within a small
* window, but they remain possible within that window. This store
* should only be used if the consumer site has no way to retain data
* between requests at all.
*
* IMMEDIATE MODE
*
* In the flow described above, the user may need to confirm to the
* lidentity server that it's ok to authorize his or her identity.
* The server may draw pages asking for information from the user
* before it redirects the browser back to the consumer's site. This
* is generally transparent to the consumer site, so it is typically
* ignored as an implementation detail.
*
* There can be times, however, where the consumer site wants to get a
* response immediately. When this is the case, the consumer can put
* the library in immediate mode. In immediate mode, there is an
* extra response possible from the server, which is essentially the
* server reporting that it doesn't have enough information to answer
* the question yet. In addition to saying that, the identity server
* provides a URL to which the user can be sent to provide the needed
* information and let the server finish handling the original
* request.
*
* USING THIS LIBRARY
*
* Integrating this library into an application is usually a
* relatively straightforward process. The process should basically
* follow this plan:
*
* Add an OpenID login field somewhere on your site. When an OpenID
* is entered in that field and the form is submitted, it should make
* a request to the your site which includes that OpenID URL.
*
* First, the application should instantiate the Auth_OpenID_Consumer
* class using the store of choice (Auth_OpenID_FileStore or one of
* the SQL-based stores). If the application has any sort of session
* framework that provides per-client state management, a dict-like
* object to access the session should be passed as the optional
* second parameter. (The default behavior is to use PHP's standard
* session machinery.)
*
* Next, the application should call the Auth_OpenID_Consumer object's
* 'begin' method. This method takes the OpenID URL. The 'begin'
* method returns an Auth_OpenID_AuthRequest object.
*
* Next, the application should call the 'redirectURL' method of the
* Auth_OpenID_AuthRequest object. The 'return_to' URL parameter is
* the URL that the OpenID server will send the user back to after
* attempting to verify his or her identity. The 'trust_root' is the
* URL (or URL pattern) that identifies your web site to the user when
* he or she is authorizing it. Send a redirect to the resulting URL
* to the user's browser.
*
* That's the first half of the authentication process. The second
* half of the process is done after the user's ID server sends the
* user's browser a redirect back to your site to complete their
* login.
*
* When that happens, the user will contact your site at the URL given
* as the 'return_to' URL to the Auth_OpenID_AuthRequest::redirectURL
* call made above. The request will have several query parameters
* added to the URL by the identity server as the information
* necessary to finish the request.
*
* Lastly, instantiate an Auth_OpenID_Consumer instance as above and
* call its 'complete' method, passing in all the received query
* arguments.
*
* There are multiple possible return types possible from that
* method. These indicate the whether or not the login was successful,
* and include any additional information appropriate for their type.
*
* 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 utility classes and functions for the consumer.
*/
require_once "Auth/OpenID.php";
require_once "Auth/OpenID/HMACSHA1.php";
require_once "Auth/OpenID/Association.php";
require_once "Auth/OpenID/CryptUtil.php";
require_once "Auth/OpenID/DiffieHellman.php";
require_once "Auth/OpenID/KVForm.php";
require_once "Auth/OpenID/Discover.php";
require_once "Services/Yadis/Manager.php";
require_once "Services/Yadis/XRI.php";
 
/**
* This is the status code returned when the complete method returns
* successfully.
*/
define('Auth_OpenID_SUCCESS', 'success');
 
/**
* Status to indicate cancellation of OpenID authentication.
*/
define('Auth_OpenID_CANCEL', 'cancel');
 
/**
* This is the status code completeAuth returns when the value it
* received indicated an invalid login.
*/
define('Auth_OpenID_FAILURE', 'failure');
 
/**
* This is the status code completeAuth returns when the
* {@link Auth_OpenID_Consumer} instance is in immediate mode, and the
* identity server sends back a URL to send the user to to complete his
* or her login.
*/
define('Auth_OpenID_SETUP_NEEDED', 'setup needed');
 
/**
* This is the status code beginAuth returns when the page fetched
* from the entered OpenID URL doesn't contain the necessary link tags
* to function as an identity page.
*/
define('Auth_OpenID_PARSE_ERROR', 'parse error');
 
/**
* This is the characters that the nonces are made from.
*/
define('Auth_OpenID_DEFAULT_NONCE_CHRS',"abcdefghijklmnopqrstuvwxyz" .
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
 
/**
* An OpenID consumer implementation that performs discovery and does
* session management. See the Consumer.php file documentation for
* more information.
*
* @package OpenID
*/
class Auth_OpenID_Consumer {
 
/**
* @access private
*/
var $session_key_prefix = "_openid_consumer_";
 
/**
* @access private
*/
var $_token_suffix = "last_token";
 
/**
* Initialize a Consumer instance.
*
* You should create a new instance of the Consumer object with
* every HTTP request that handles OpenID transactions.
*
* @param Auth_OpenID_OpenIDStore $store This must be an object
* that implements the interface in {@link
* Auth_OpenID_OpenIDStore}. Several concrete implementations are
* provided, to cover most common use cases. For stores backed by
* MySQL, PostgreSQL, or SQLite, see the {@link
* Auth_OpenID_SQLStore} class and its sublcasses. For a
* filesystem-backed store, see the {@link Auth_OpenID_FileStore}
* module. As a last resort, if it isn't possible for the server
* to store state at all, an instance of {@link
* Auth_OpenID_DumbStore} can be used.
*
* @param mixed session An object which implements the interface
* of the Services_Yadis_Session class. Particularly, this object
* is expected to have these methods: get($key), set($key,
* $value), and del($key). This defaults to a session object
* which wraps PHP's native session machinery. You should only
* need to pass something here if you have your own sessioning
* implementation.
*/
function Auth_OpenID_Consumer(&$store, $session = null)
{
if ($session === null) {
$session = new Services_Yadis_PHPSession();
}
 
$this->session =& $session;
$this->consumer =& new Auth_OpenID_GenericConsumer($store);
$this->_token_key = $this->session_key_prefix . $this->_token_suffix;
}
 
/**
* Start the OpenID authentication process. See steps 1-2 in the
* overview at the top of this file.
*
* @param User_url: Identity URL given by the user. This method
* performs a textual transformation of the URL to try and make
* sure it is normalized. For example, a user_url of example.com
* will be normalized to http://example.com/ normalizing and
* resolving any redirects the server might issue.
*
* @return Auth_OpenID_AuthRequest $auth_request An object
* containing the discovered information will be returned, with a
* method for building a redirect URL to the server, as described
* in step 3 of the overview. This object may also be used to add
* extension arguments to the request, using its 'addExtensionArg'
* method.
*/
function begin($user_url)
{
$discoverMethod = '_Auth_OpenID_discoverServiceList';
$openid_url = $user_url;
 
if (Services_Yadis_identifierScheme($user_url) == 'XRI') {
$discoverMethod = '_Auth_OpenID_discoverXRIServiceList';
} else {
$openid_url = Auth_OpenID::normalizeUrl($user_url);
}
 
$disco =& new Services_Yadis_Discovery($this->session,
$openid_url,
$this->session_key_prefix);
 
// Set the 'stale' attribute of the manager. If discovery
// fails in a fatal way, the stale flag will cause the manager
// to be cleaned up next time discovery is attempted.
 
$m = $disco->getManager();
$loader = new Services_Yadis_ManagerLoader();
 
if ($m) {
if ($m->stale) {
$disco->destroyManager();
} else {
$m->stale = true;
$disco->session->set($disco->session_key,
serialize($loader->toSession($m)));
}
}
 
$endpoint = $disco->getNextService($discoverMethod,
$this->consumer->fetcher);
 
// Reset the 'stale' attribute of the manager.
$m =& $disco->getManager();
if ($m) {
$m->stale = false;
$disco->session->set($disco->session_key,
serialize($loader->toSession($m)));
}
 
if ($endpoint === null) {
return null;
} else {
return $this->beginWithoutDiscovery($endpoint);
}
}
 
/**
* Start OpenID verification without doing OpenID server
* discovery. This method is used internally by Consumer.begin
* after discovery is performed, and exists to provide an
* interface for library users needing to perform their own
* discovery.
*
* @param Auth_OpenID_ServiceEndpoint $endpoint an OpenID service
* endpoint descriptor.
*
* @return Auth_OpenID_AuthRequest $auth_request An OpenID
* authentication request object.
*/
function &beginWithoutDiscovery($endpoint)
{
$loader = new Auth_OpenID_ServiceEndpointLoader();
$auth_req = $this->consumer->begin($endpoint);
$this->session->set($this->_token_key,
$loader->toSession($auth_req->endpoint));
return $auth_req;
}
 
/**
* Called to interpret the server's response to an OpenID
* request. It is called in step 4 of the flow described in the
* consumer overview.
*
* @param array $query An array of the query parameters (key =>
* value pairs) for this HTTP request.
*
* @return Auth_OpenID_ConsumerResponse $response A instance of an
* Auth_OpenID_ConsumerResponse subclass. The type of response is
* indicated by the status attribute, which will be one of
* SUCCESS, CANCEL, FAILURE, or SETUP_NEEDED.
*/
function complete($query)
{
$query = Auth_OpenID::fixArgs($query);
 
$loader = new Auth_OpenID_ServiceEndpointLoader();
$endpoint_data = $this->session->get($this->_token_key);
$endpoint =
$loader->fromSession($endpoint_data);
 
if ($endpoint === null) {
$response = new Auth_OpenID_FailureResponse(null,
'No session state found');
} else {
$response = $this->consumer->complete($query, $endpoint);
$this->session->del($this->_token_key);
}
 
if (in_array($response->status, array(Auth_OpenID_SUCCESS,
Auth_OpenID_CANCEL))) {
if ($response->identity_url !== null) {
$disco = new Services_Yadis_Discovery($this->session,
$response->identity_url,
$this->session_key_prefix);
$disco->cleanup();
}
}
 
return $response;
}
}
 
class Auth_OpenID_DiffieHellmanConsumerSession {
var $session_type = 'DH-SHA1';
 
function Auth_OpenID_DiffieHellmanConsumerSession($dh = null)
{
if ($dh === null) {
$dh = new Auth_OpenID_DiffieHellman();
}
 
$this->dh = $dh;
}
 
function getRequest()
{
$math =& Auth_OpenID_getMathLib();
 
$cpub = $math->longToBase64($this->dh->public);
 
$args = array('openid.dh_consumer_public' => $cpub);
 
if (!$this->dh->usingDefaultValues()) {
$args = array_merge($args, array(
'openid.dh_modulus' =>
$math->longToBase64($this->dh->mod),
'openid.dh_gen' =>
$math->longToBase64($this->dh->gen)));
}
 
return $args;
}
 
function extractSecret($response)
{
if (!array_key_exists('dh_server_public', $response)) {
return null;
}
 
if (!array_key_exists('enc_mac_key', $response)) {
return null;
}
 
$math =& Auth_OpenID_getMathLib();
$spub = $math->base64ToLong($response['dh_server_public']);
$enc_mac_key = base64_decode($response['enc_mac_key']);
 
return $this->dh->xorSecret($spub, $enc_mac_key);
}
}
 
class Auth_OpenID_PlainTextConsumerSession {
var $session_type = null;
 
function getRequest()
{
return array();
}
 
function extractSecret($response)
{
if (!array_key_exists('mac_key', $response)) {
return null;
}
 
return base64_decode($response['mac_key']);
}
}
 
/**
* This class is the interface to the OpenID consumer logic.
* Instances of it maintain no per-request state, so they can be
* reused (or even used by multiple threads concurrently) as needed.
*
* @package OpenID
* @access private
*/
class Auth_OpenID_GenericConsumer {
/**
* This consumer's store object.
*/
var $store;
 
/**
* @access private
*/
var $_use_assocs;
 
/**
* This is the number of characters in the generated nonce for
* each transaction.
*/
var $nonce_len = 8;
 
/**
* What characters are allowed in nonces
*/
var $nonce_chrs = Auth_OpenID_DEFAULT_NONCE_CHRS;
 
/**
* This method initializes a new {@link Auth_OpenID_Consumer}
* instance to access the library.
*
* @param Auth_OpenID_OpenIDStore $store This must be an object
* that implements the interface in {@link Auth_OpenID_OpenIDStore}.
* Several concrete implementations are provided, to cover most common use
* cases. For stores backed by MySQL, PostgreSQL, or SQLite, see
* the {@link Auth_OpenID_SQLStore} class and its sublcasses. For a
* filesystem-backed store, see the {@link Auth_OpenID_FileStore} module.
* As a last resort, if it isn't possible for the server to store
* state at all, an instance of {@link Auth_OpenID_DumbStore} can be used.
*
* @param bool $immediate This is an optional boolean value. It
* controls whether the library uses immediate mode, as explained
* in the module description. The default value is False, which
* disables immediate mode.
*/
function Auth_OpenID_GenericConsumer(&$store)
{
$this->store =& $store;
$this->_use_assocs =
!(defined('Auth_OpenID_NO_MATH_SUPPORT') ||
($this->store && $this->store->isDumb()));
 
$this->fetcher = Services_Yadis_Yadis::getHTTPFetcher();
}
 
function begin($service_endpoint)
{
$nonce = $this->_createNonce();
$assoc = $this->_getAssociation($service_endpoint->server_url);
$r = new Auth_OpenID_AuthRequest($assoc, $service_endpoint);
$r->return_to_args['nonce'] = $nonce;
return $r;
}
 
function complete($query, $endpoint)
{
$mode = Auth_OpenID::arrayGet($query, 'openid.mode',
'<no mode specified>');
 
if ($mode == Auth_OpenID_CANCEL) {
return new Auth_OpenID_CancelResponse($endpoint);
} else if ($mode == 'error') {
$error = Auth_OpenID::arrayGet($query, 'openid.error');
return new Auth_OpenID_FailureResponse($endpoint, $error);
} else if ($mode == 'id_res') {
if ($endpoint->identity_url === null) {
return new Auth_OpenID_FailureResponse($identity_url,
"No session state found");
}
 
$response = $this->_doIdRes($query, $endpoint);
 
if ($response === null) {
return new Auth_OpenID_FailureResponse($endpoint,
"HTTP request failed");
}
if ($response->status == Auth_OpenID_SUCCESS) {
return $this->_checkNonce($response,
Auth_OpenID::arrayGet($query,
'nonce'));
} else {
return $response;
}
} else {
return new Auth_OpenID_FailureResponse($endpoint,
sprintf("Invalid openid.mode '%s'",
$mode));
}
}
 
/**
* @access private
*/
function _doIdRes($query, $endpoint)
{
$user_setup_url = Auth_OpenID::arrayGet($query,
'openid.user_setup_url');
 
if ($user_setup_url !== null) {
return new Auth_OpenID_SetupNeededResponse($endpoint,
$user_setup_url);
}
 
$return_to = Auth_OpenID::arrayGet($query, 'openid.return_to', null);
$server_id2 = Auth_OpenID::arrayGet($query, 'openid.identity', null);
$assoc_handle = Auth_OpenID::arrayGet($query,
'openid.assoc_handle', null);
 
if (($return_to === null) ||
($server_id2 === null) ||
($assoc_handle === null)) {
return new Auth_OpenID_FailureResponse($endpoint,
"Missing required field");
}
 
if ($endpoint->getServerID() != $server_id2) {
return new Auth_OpenID_FailureResponse($endpoint,
"Server ID (delegate) mismatch");
}
 
$signed = Auth_OpenID::arrayGet($query, 'openid.signed');
 
$assoc = $this->store->getAssociation($endpoint->server_url,
$assoc_handle);
 
if ($assoc === null) {
// It's not an association we know about. Dumb mode is
// our only possible path for recovery.
if ($this->_checkAuth($query, $endpoint->server_url)) {
return new Auth_OpenID_SuccessResponse($endpoint, $query,
$signed);
} else {
return new Auth_OpenID_FailureResponse($endpoint,
"Server denied check_authentication");
}
}
 
if ($assoc->getExpiresIn() <= 0) {
$msg = sprintf("Association with %s expired",
$endpoint->server_url);
return new Auth_OpenID_FailureResponse($endpoint, $msg);
}
 
// Check the signature
$sig = Auth_OpenID::arrayGet($query, 'openid.sig', null);
if (($sig === null) ||
($signed === null)) {
return new Auth_OpenID_FailureResponse($endpoint,
"Missing argument signature");
}
 
$signed_list = explode(",", $signed);
 
//Fail if the identity field is present but not signed
if (($endpoint->identity_url !== null) &&
(!in_array('identity', $signed_list))) {
$msg = '"openid.identity" not signed';
return new Auth_OpenID_FailureResponse($endpoint, $msg);
}
 
$v_sig = $assoc->signDict($signed_list, $query);
 
if ($v_sig != $sig) {
return new Auth_OpenID_FailureResponse($endpoint,
"Bad signature");
}
 
return Auth_OpenID_SuccessResponse::fromQuery($endpoint,
$query, $signed);
}
 
/**
* @access private
*/
function _checkAuth($query, $server_url)
{
$request = $this->_createCheckAuthRequest($query);
if ($request === null) {
return false;
}
 
$response = $this->_makeKVPost($request, $server_url);
if ($response == null) {
return false;
}
 
return $this->_processCheckAuthResponse($response, $server_url);
}
 
/**
* @access private
*/
function _createCheckAuthRequest($query)
{
$signed = Auth_OpenID::arrayGet($query, 'openid.signed', null);
if ($signed === null) {
return null;
}
 
$whitelist = array('assoc_handle', 'sig',
'signed', 'invalidate_handle');
 
$signed = array_merge(explode(",", $signed), $whitelist);
 
$check_args = array();
 
foreach ($query as $key => $value) {
if (in_array(substr($key, 7), $signed)) {
$check_args[$key] = $value;
}
}
 
$check_args['openid.mode'] = 'check_authentication';
return $check_args;
}
 
/**
* @access private
*/
function _processCheckAuthResponse($response, $server_url)
{
$is_valid = Auth_OpenID::arrayGet($response, 'is_valid', 'false');
 
$invalidate_handle = Auth_OpenID::arrayGet($response,
'invalidate_handle');
 
if ($invalidate_handle !== null) {
$this->store->removeAssociation($server_url,
$invalidate_handle);
}
 
if ($is_valid == 'true') {
return true;
}
 
return false;
}
 
/**
* @access private
*/
function _makeKVPost($args, $server_url)
{
$mode = $args['openid.mode'];
 
$pairs = array();
foreach ($args as $k => $v) {
$v = urlencode($v);
$pairs[] = "$k=$v";
}
 
$body = implode("&", $pairs);
 
$resp = $this->fetcher->post($server_url, $body);
 
if ($resp === null) {
return null;
}
 
$response = Auth_OpenID_KVForm::toArray($resp->body);
 
if ($resp->status == 400) {
return null;
} else if ($resp->status != 200) {
return null;
}
 
return $response;
}
 
/**
* @access private
*/
function _checkNonce($response, $nonce)
{
$parsed_url = parse_url($response->getReturnTo());
$query_str = @$parsed_url['query'];
$query = array();
parse_str($query_str, $query);
 
$found = false;
 
foreach ($query as $k => $v) {
if ($k == 'nonce') {
if ($v != $nonce) {
return new Auth_OpenID_FailureResponse($response,
"Nonce mismatch");
} else {
$found = true;
break;
}
}
}
 
if (!$found) {
return new Auth_OpenID_FailureResponse($response,
sprintf("Nonce missing from return_to: %s",
$response->getReturnTo()));
}
 
if (!$this->store->useNonce($nonce)) {
return new Auth_OpenID_FailureResponse($response,
"Nonce missing from store");
}
 
return $response;
}
 
/**
* @access private
*/
function _createNonce()
{
$nonce = Auth_OpenID_CryptUtil::randomString($this->nonce_len,
$this->nonce_chrs);
$this->store->storeNonce($nonce);
return $nonce;
}
 
/**
* @access protected
*/
function _createDiffieHellman()
{
return new Auth_OpenID_DiffieHellman();
}
 
/**
* @access private
*/
function _getAssociation($server_url)
{
if (!$this->_use_assocs) {
return null;
}
 
$assoc = $this->store->getAssociation($server_url);
 
if (($assoc === null) ||
($assoc->getExpiresIn() <= 0)) {
 
$parts = $this->_createAssociateRequest($server_url);
 
if ($parts === null) {
return null;
}
 
list($assoc_session, $args) = $parts;
 
$response = $this->_makeKVPost($args, $server_url);
 
if ($response === null) {
$assoc = null;
} else {
$assoc = $this->_parseAssociation($response, $assoc_session,
$server_url);
}
}
 
return $assoc;
}
 
function _createAssociateRequest($server_url)
{
$parts = parse_url($server_url);
 
if ($parts === false) {
return null;
}
 
if (array_key_exists('scheme', $parts)) {
$proto = $parts['scheme'];
} else {
$proto = 'http';
}
 
if ($proto == 'https') {
$assoc_session = new Auth_OpenID_PlainTextConsumerSession();
} else {
$assoc_session = new Auth_OpenID_DiffieHellmanConsumerSession();
}
 
$args = array(
'openid.mode' => 'associate',
'openid.assoc_type' => 'HMAC-SHA1');
 
if ($assoc_session->session_type !== null) {
$args['openid.session_type'] = $assoc_session->session_type;
}
 
$args = array_merge($args, $assoc_session->getRequest());
return array($assoc_session, $args);
}
 
/**
* @access private
*/
function _parseAssociation($results, $assoc_session, $server_url)
{
$required_keys = array('assoc_type', 'assoc_handle',
'expires_in');
 
foreach ($required_keys as $key) {
if (!array_key_exists($key, $results)) {
return null;
}
}
 
$assoc_type = $results['assoc_type'];
$assoc_handle = $results['assoc_handle'];
$expires_in_str = $results['expires_in'];
 
if ($assoc_type != 'HMAC-SHA1') {
return null;
}
 
$expires_in = intval($expires_in_str);
 
if ($expires_in <= 0) {
return null;
}
 
$session_type = Auth_OpenID::arrayGet($results, 'session_type');
if ($session_type != $assoc_session->session_type) {
if ($session_type === null) {
$assoc_session = new Auth_OpenID_PlainTextConsumerSession();
} else {
return null;
}
}
 
$secret = $assoc_session->extractSecret($results);
 
if (!$secret) {
return null;
}
 
$assoc = Auth_OpenID_Association::fromExpiresIn(
$expires_in, $assoc_handle, $secret, $assoc_type);
$this->store->storeAssociation($server_url, $assoc);
 
return $assoc;
}
}
 
/**
* This class represents an authentication request from a consumer to
* an OpenID server.
*
* @package OpenID
*/
class Auth_OpenID_AuthRequest {
 
/**
* Initialize an authentication request with the specified token,
* association, and endpoint.
*
* Users of this library should not create instances of this
* class. Instances of this class are created by the library when
* needed.
*/
function Auth_OpenID_AuthRequest($assoc, $endpoint)
{
$this->assoc = $assoc;
$this->endpoint = $endpoint;
$this->extra_args = array();
$this->return_to_args = array();
}
 
/**
* Add an extension argument to this OpenID authentication
* request.
*
* Use caution when adding arguments, because they will be
* URL-escaped and appended to the redirect URL, which can easily
* get quite long.
*
* @param string $namespace The namespace for the extension. For
* example, the simple registration extension uses the namespace
* 'sreg'.
*
* @param string $key The key within the extension namespace. For
* example, the nickname field in the simple registration
* extension's key is 'nickname'.
*
* @param string $value The value to provide to the server for
* this argument.
*/
function addExtensionArg($namespace, $key, $value)
{
$arg_name = implode('.', array('openid', $namespace, $key));
$this->extra_args[$arg_name] = $value;
}
 
/**
* Compute the appropriate redirection URL for this request based
* on a specified trust root and return-to.
*
* @param string $trust_root The trust root URI for your
* application.
*
* @param string$ $return_to The return-to URL to be used when the
* OpenID server redirects the user back to your site.
*
* @return string $redirect_url The resulting redirect URL that
* you should send to the user agent.
*/
function redirectURL($trust_root, $return_to, $immediate=false)
{
if ($immediate) {
$mode = 'checkid_immediate';
} else {
$mode = 'checkid_setup';
}
 
$return_to = Auth_OpenID::appendArgs($return_to, $this->return_to_args);
 
$redir_args = array(
'openid.mode' => $mode,
'openid.identity' => $this->endpoint->getServerID(),
'openid.return_to' => $return_to,
'openid.trust_root' => $trust_root);
 
if ($this->assoc) {
$redir_args['openid.assoc_handle'] = $this->assoc->handle;
}
 
$redir_args = array_merge($redir_args, $this->extra_args);
 
return Auth_OpenID::appendArgs($this->endpoint->server_url,
$redir_args);
}
}
 
/**
* The base class for responses from the Auth_OpenID_Consumer.
*
* @package OpenID
*/
class Auth_OpenID_ConsumerResponse {
var $status = null;
}
 
/**
* A response with a status of Auth_OpenID_SUCCESS. Indicates that
* this request is a successful acknowledgement from the OpenID server
* that the supplied URL is, indeed controlled by the requesting
* agent. This has three relevant attributes:
*
* identity_url - The identity URL that has been authenticated
*
* signed_args - The arguments in the server's response that were
* signed and verified.
*
* status - Auth_OpenID_SUCCESS.
*
* @package OpenID
*/
class Auth_OpenID_SuccessResponse extends Auth_OpenID_ConsumerResponse {
var $status = Auth_OpenID_SUCCESS;
 
/**
* @access private
*/
function Auth_OpenID_SuccessResponse($endpoint, $signed_args)
{
$this->endpoint = $endpoint;
$this->identity_url = $endpoint->identity_url;
$this->signed_args = $signed_args;
}
 
/**
* @access private
*/
function fromQuery($endpoint, $query, $signed)
{
$signed_args = array();
foreach (explode(",", $signed) as $field_name) {
$field_name = 'openid.' . $field_name;
$signed_args[$field_name] = Auth_OpenID::arrayGet($query,
$field_name, '');
}
return new Auth_OpenID_SuccessResponse($endpoint, $signed_args);
}
 
/**
* Extract signed extension data from the server's response.
*
* @param string $prefix The extension namespace from which to
* extract the extension data.
*/
function extensionResponse($prefix)
{
$response = array();
$prefix = sprintf('openid.%s.', $prefix);
$prefix_len = strlen($prefix);
foreach ($this->signed_args as $k => $v) {
if (strpos($k, $prefix) === 0) {
$response_key = substr($k, $prefix_len);
$response[$response_key] = $v;
}
}
 
return $response;
}
 
/**
* Get the openid.return_to argument from this response.
*
* This is useful for verifying that this request was initiated by
* this consumer.
*
* @return string $return_to The return_to URL supplied to the
* server on the initial request, or null if the response did not
* contain an 'openid.return_to' argument.
*/
function getReturnTo()
{
return Auth_OpenID::arrayGet($this->signed_args, 'openid.return_to');
}
}
 
/**
* A response with a status of Auth_OpenID_FAILURE. Indicates that the
* OpenID protocol has failed. This could be locally or remotely
* triggered. This has three relevant attributes:
*
* identity_url - The identity URL for which authentication was
* attempted, if it can be determined. Otherwise, null.
*
* message - A message indicating why the request failed, if one is
* supplied. Otherwise, null.
*
* status - Auth_OpenID_FAILURE.
*
* @package OpenID
*/
class Auth_OpenID_FailureResponse extends Auth_OpenID_ConsumerResponse {
var $status = Auth_OpenID_FAILURE;
 
function Auth_OpenID_FailureResponse($endpoint, $message = null)
{
$this->endpoint = $endpoint;
if ($endpoint !== null) {
$this->identity_url = $endpoint->identity_url;
} else {
$this->identity_url = null;
}
$this->message = $message;
}
}
 
/**
* A response with a status of Auth_OpenID_CANCEL. Indicates that the
* user cancelled the OpenID authentication request. This has two
* relevant attributes:
*
* identity_url - The identity URL for which authentication was
* attempted, if it can be determined. Otherwise, null.
*
* status - Auth_OpenID_SUCCESS.
*
* @package OpenID
*/
class Auth_OpenID_CancelResponse extends Auth_OpenID_ConsumerResponse {
var $status = Auth_OpenID_CANCEL;
 
function Auth_OpenID_CancelResponse($endpoint)
{
$this->endpoint = $endpoint;
$this->identity_url = $endpoint->identity_url;
}
}
 
/**
* A response with a status of Auth_OpenID_SETUP_NEEDED. Indicates
* that the request was in immediate mode, and the server is unable to
* authenticate the user without further interaction.
*
* identity_url - The identity URL for which authentication was
* attempted.
*
* setup_url - A URL that can be used to send the user to the server
* to set up for authentication. The user should be redirected in to
* the setup_url, either in the current window or in a new browser
* window.
*
* status - Auth_OpenID_SETUP_NEEDED.
*
* @package OpenID
*/
class Auth_OpenID_SetupNeededResponse extends Auth_OpenID_ConsumerResponse {
var $status = Auth_OpenID_SETUP_NEEDED;
 
function Auth_OpenID_SetupNeededResponse($endpoint,
$setup_url = null)
{
$this->endpoint = $endpoint;
$this->identity_url = $endpoint->identity_url;
$this->setup_url = $setup_url;
}
}
 
?>
/trunk/composants/openid/Auth/OpenID/FileStore.php
New file
0,0 → 1,674
<?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 Janrain, Inc.
* @license http://www.gnu.org/copyleft/lesser.html LGPL
*
*/
 
/**
* Require base class for creating a new interface.
*/
require_once 'Auth/OpenID.php';
require_once 'Auth/OpenID/Interface.php';
require_once 'Auth/OpenID/HMACSHA1.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 and the $directory containing the auth key file.
$this->temp_dir = $directory . DIRECTORY_SEPARATOR . 'temp';
 
$this->auth_key_name = $directory . DIRECTORY_SEPARATOR . 'auth_key';
 
$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(dirname($this->auth_key_name)) &&
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->auth_key_name and $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);
}
}
 
/**
* Read the auth key from the auth key file. Will return None if
* there is currently no key.
*
* @return mixed
*/
function readAuthKey()
{
if (!$this->active) {
trigger_error("FileStore no longer active", E_USER_ERROR);
return null;
}
 
$auth_key_file = @fopen($this->auth_key_name, 'rb');
if ($auth_key_file === false) {
return null;
}
 
$key = fread($auth_key_file, filesize($this->auth_key_name));
fclose($auth_key_file);
 
return $key;
}
 
/**
* Generate a new random auth key and safely store it in the
* location specified by $this->auth_key_name.
*
* @return string $key
*/
function createAuthKey()
{
if (!$this->active) {
trigger_error("FileStore no longer active", E_USER_ERROR);
return null;
}
 
$auth_key = Auth_OpenID_CryptUtil::randomString($this->AUTH_KEY_LEN);
 
list($file_obj, $tmp) = $this->_mktemp();
 
fwrite($file_obj, $auth_key);
fflush($file_obj);
fclose($file_obj);
 
if (function_exists('link')) {
// Posix filesystem
$saved = link($tmp, $this->auth_key_name);
Auth_OpenID_FileStore::_removeIfPresent($tmp);
} else {
// Windows filesystem
$saved = rename($tmp, $this->auth_key_name);
}
 
if (!$saved) {
// The link failed, either because we lack the permission,
// or because the file already exists; try to read the key
// in case the file already existed.
$auth_key = $this->readAuthKey();
}
 
return $auth_key;
}
 
/**
* Retrieve the auth key from the file specified by
* $this->auth_key_name, creating it if it does not exist.
*
* @return string $key
*/
function getAuthKey()
{
if (!$this->active) {
trigger_error("FileStore no longer active", E_USER_ERROR);
return null;
}
 
$auth_key = $this->readAuthKey();
if ($auth_key === null) {
$auth_key = $this->createAuthKey();
 
if (strlen($auth_key) != $this->AUTH_KEY_LEN) {
$fmt = 'Got an invalid auth key from %s. Expected '.
'%d-byte string. Got: %s';
$msg = sprintf($fmt, $this->auth_key_name, $this->AUTH_KEY_LEN,
$auth_key);
trigger_error($msg, E_USER_WARNING);
return null;
}
}
return $auth_key;
}
 
/**
* 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) {
if (strpos($association_file, $name) === 0) {
$matching_files[] = $association_file;
}
}
 
$matching_associations = array();
// read the matching files and sort by time issued
foreach ($matching_files as $name) {
$full_name = $this->association_dir . DIRECTORY_SEPARATOR .
$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;
}
 
$assoc_file = @fopen($filename, 'rb');
 
if ($assoc_file === false) {
return null;
}
 
$assoc_s = fread($assoc_file, filesize($filename));
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);
}
}
 
/**
* Mark this nonce as present.
*/
function storeNonce($nonce)
{
if (!$this->active) {
trigger_error("FileStore no longer active", E_USER_ERROR);
return null;
}
 
$filename = $this->nonce_dir . DIRECTORY_SEPARATOR . $nonce;
$nonce_file = fopen($filename, 'w');
if ($nonce_file === false) {
return false;
}
fclose($nonce_file);
return true;
}
 
/**
* Return whether this nonce is present. As a side effect, mark it
* as no longer present.
*
* @return bool $present
*/
function useNonce($nonce)
{
if (!$this->active) {
trigger_error("FileStore no longer active", E_USER_ERROR);
return null;
}
 
$filename = $this->nonce_dir . DIRECTORY_SEPARATOR . $nonce;
$st = @stat($filename);
 
if ($st === false) {
return false;
}
 
// Either it is too old or we are using it. Either way, we
// must remove the file.
if (!unlink($filename)) {
return false;
}
 
$now = time();
$nonce_age = $now - $st[9];
 
// We can us it if the age of the file is less than the
// expiration time.
return $nonce_age <= $this->max_nonce_age;
}
 
/**
* Remove expired entries from the database. This is potentially
* expensive, so only run when it is acceptable to take time.
*/
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) {
$filename = $this->nonce_dir . DIRECTORY_SEPARATOR . $nonce;
$st = @stat($filename);
 
if ($st !== false) {
// Remove the nonce if it has expired
$nonce_age = $now - $st[9];
if ($nonce_age > $this->max_nonce_age) {
Auth_OpenID_FileStore::_removeIfPresent($filename);
}
}
}
 
$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) {
Auth_OpenID_FileStore::_removeIfPresent(
$association_filename);
}
}
}
}
}
 
/**
* @access private
*/
function _rmtree($dir)
{
if ($dir[strlen($dir) - 1] != DIRECTORY_SEPARATOR) {
$dir .= DIRECTORY_SEPARATOR;
}
 
if ($handle = opendir($dir)) {
while ($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
*/
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))) {
$files[] = $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 = "";
for ($i = 0; $i < strlen($str); $i++) {
$c = $str[$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);
}
}
 
?>
/trunk/composants/openid/Auth/OpenID/CryptUtil.php
New file
0,0 → 1,109
<?php
 
/**
* CryptUtil: A suite of wrapper utility functions 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 Janrain, Inc.
* @license http://www.gnu.org/copyleft/lesser.html LGPL
*/
 
if (!defined('Auth_OpenID_RAND_SOURCE')) {
/**
* The filename for a source of random bytes. Define this yourself
* if you have a different source of randomness.
*/
define('Auth_OpenID_RAND_SOURCE', '/dev/urandom');
}
 
class Auth_OpenID_CryptUtil {
/**
* Get the specified number of random bytes.
*
* Attempts to use a cryptographically secure (not predictable)
* source of randomness if available. If there is no high-entropy
* randomness source available, it will fail. As a last resort,
* for non-critical systems, define
* <code>Auth_OpenID_RAND_SOURCE</code> as <code>null</code>, and
* the code will fall back on a pseudo-random number generator.
*
* @param int $num_bytes The length of the return value
* @return string $bytes random bytes
*/
function getBytes($num_bytes)
{
static $f = null;
$bytes = '';
if ($f === null) {
if (Auth_OpenID_RAND_SOURCE === null) {
$f = false;
} else {
$f = @fopen(Auth_OpenID_RAND_SOURCE, "r");
if ($f === false) {
$msg = 'Define Auth_OpenID_RAND_SOURCE as null to ' .
' continue with an insecure random number generator.';
trigger_error($msg, E_USER_ERROR);
}
}
}
if ($f === false) {
// pseudorandom used
$bytes = '';
for ($i = 0; $i < $num_bytes; $i += 4) {
$bytes .= pack('L', mt_rand());
}
$bytes = substr($bytes, 0, $num_bytes);
} else {
$bytes = fread($f, $num_bytes);
}
return $bytes;
}
 
/**
* Produce a string of length random bytes, chosen from chrs. If
* $chrs is null, the resulting string may contain any characters.
*
* @param integer $length The length of the resulting
* randomly-generated string
* @param string $chrs A string of characters from which to choose
* to build the new string
* @return string $result A string of randomly-chosen characters
* from $chrs
*/
function randomString($length, $population = null)
{
if ($population === null) {
return Auth_OpenID_CryptUtil::getBytes($length);
}
 
$popsize = strlen($population);
 
if ($popsize > 256) {
$msg = 'More than 256 characters supplied to ' . __FUNCTION__;
trigger_error($msg, E_USER_ERROR);
}
 
$duplicate = 256 % $popsize;
 
$str = "";
for ($i = 0; $i < $length; $i++) {
do {
$n = ord(Auth_OpenID_CryptUtil::getBytes(1));
} while ($n < $duplicate);
 
$n %= $popsize;
$str .= $population[$n];
}
 
return $str;
}
}
 
?>
/trunk/composants/openid/Auth/OpenID/Interface.php
New file
0,0 → 1,188
<?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 Janrain, Inc.
* @license http://www.gnu.org/copyleft/lesser.html LGPL
*/
 
/**
* 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.
*
* @package OpenID
* @author JanRain, Inc. <openid@janrain.com>
*/
class Auth_OpenID_OpenIDStore {
/**
* @var integer The length of the auth key that should be returned
* by the getAuthKey method.
*/
var $AUTH_KEY_LEN = 20;
 
/**
* 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);
}
 
/**
* 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
* that will remain valid for the longest duration.
*
* 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);
}
 
/**
* Stores a nonce. This is used by the consumer to prevent replay
* attacks.
*
* @param string $nonce The nonce to store.
*
* @return null
*/
function storeNonce($nonce)
{
trigger_error("Auth_OpenID_OpenIDStore::storeNonce ".
"not implemented", E_USER_ERROR);
}
 
/**
* This method is called when the library is attempting to use a
* nonce. If the nonce is in the store, this method removes it and
* returns a value which evaluates as true. Otherwise it returns a
* value which evaluates as false.
*
* This method is allowed and encouraged to treat nonces older
* than some period (a very conservative window would be 6 hours,
* for example) as no longer existing, and return False and remove
* them.
*
* @param string $nonce The nonce to use.
*
* @return bool Whether or not the nonce was valid.
*/
function useNonce($nonce)
{
trigger_error("Auth_OpenID_OpenIDStore::useNonce ".
"not implemented", E_USER_ERROR);
}
 
/**
* This method returns a key used to sign the tokens, to ensure
* that they haven't been tampered with in transit. It should
* return the same key every time it is called. The key returned
* should be {@link AUTH_KEY_LEN} bytes long.
*
* @return string The key. It should be {@link AUTH_KEY_LEN} bytes in
* length, and use the full range of byte values. That is, it
* should be treated as a lump of binary data stored in a string.
*/
function getAuthKey()
{
trigger_error("Auth_OpenID_OpenIDStore::getAuthKey ".
"not implemented", E_USER_ERROR);
}
 
/**
* This method must return true if the store is a dumb-mode-style
* store. Unlike all other methods in this class, this one
* provides a default implementation, which returns false.
*
* In general, any custom subclass of {@link Auth_OpenID_OpenIDStore}
* won't override this method, as custom subclasses are only likely to
* be created when the store is fully functional.
*
* @return bool true if the store works fully, false if the
* consumer will have to use dumb mode to use this store.
*/
function isDumb()
{
return false;
}
 
/**
* Removes all entries from the store; implementation is optional.
*/
function reset()
{
}
 
}
?>
/trunk/composants/openid/Auth/OpenID/DumbStore.php
New file
0,0 → 1,116
<?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 Janrain, Inc.
* @license http://www.gnu.org/copyleft/lesser.html LGPL
*/
 
/**
* Import the interface for creating a new store class.
*/
require_once 'Auth/OpenID/Interface.php';
require_once 'Auth/OpenID/HMACSHA1.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;
}
 
/**
* This implementation does nothing.
*/
function storeNonce($nonce)
{
}
 
/**
* 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($nonce)
{
return true;
}
 
/**
* This method returns the auth key generated by the constructor.
*/
function getAuthKey()
{
return $this->auth_key;
}
 
/**
* This store is a dumb mode store, so this method is overridden
* to return true.
*/
function isDumb()
{
return true;
}
}
 
?>
/trunk/composants/openid/Auth/OpenID/KVForm.php
New file
0,0 → 1,112
<?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 Janrain, Inc.
* @license http://www.gnu.org/copyleft/lesser.html LGPL
*/
 
/**
* 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
*/
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
*/
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;
}
}
 
?>
/trunk/composants/openid/Auth/OpenID/Server.php
New file
0,0 → 1,1307
<?php
 
/**
* OpenID server protocol and logic.
*
* Overview
*
* An OpenID server must perform three tasks:
*
* 1. Examine the incoming request to determine its nature and validity.
* 2. Make a decision about how to respond to this request.
* 3. Format the response according to the protocol.
*
* The first and last of these tasks may performed by the
* 'decodeRequest' and 'encodeResponse' methods of the
* Auth_OpenID_Server object. Who gets to do the intermediate task --
* deciding how to respond to the request -- will depend on what type
* of request it is.
*
* If it's a request to authenticate a user (a 'checkid_setup' or
* 'checkid_immediate' request), you need to decide if you will assert
* that this user may claim the identity in question. Exactly how you
* do that is a matter of application policy, but it generally
* involves making sure the user has an account with your system and
* is logged in, checking to see if that identity is hers to claim,
* and verifying with the user that she does consent to releasing that
* information to the party making the request.
*
* Examine the properties of the Auth_OpenID_CheckIDRequest object,
* and if and when you've come to a decision, form a response by
* calling Auth_OpenID_CheckIDRequest::answer.
*
* Other types of requests relate to establishing associations between
* client and server and verifing the authenticity of previous
* communications. Auth_OpenID_Server contains all the logic and data
* necessary to respond to such requests; just pass it to
* Auth_OpenID_Server::handleRequest.
*
* OpenID Extensions
*
* Do you want to provide other information for your users in addition
* to authentication? Version 1.2 of the OpenID protocol allows
* consumers to add extensions to their requests. For example, with
* sites using the Simple Registration
* Extension
* (http://www.openidenabled.com/openid/simple-registration-extension/),
* a user can agree to have their nickname and e-mail address sent to
* a site when they sign up.
*
* Since extensions do not change the way OpenID authentication works,
* code to handle extension requests may be completely separate from
* the Auth_OpenID_Request class here. But you'll likely want data
* sent back by your extension to be signed. Auth_OpenID_Response
* provides methods with which you can add data to it which can be
* signed with the other data in the OpenID signature.
*
* For example:
*
* // when request is a checkid_* request
* response = request.answer(True)
* // this will a signed 'openid.sreg.timezone' parameter to the response
* response.addField('sreg', 'timezone', 'America/Los_Angeles')
*
* Stores
*
* The OpenID server needs to maintain state between requests in order
* to function. Its mechanism for doing this is called a store. The
* store interface is defined in Interface.php. Additionally, several
* concrete store implementations are provided, so that most sites
* won't need to implement a custom store. For a store backed by flat
* files on disk, see Auth_OpenID_FileStore. For stores based on
* MySQL, SQLite, or PostgreSQL, see the Auth_OpenID_SQLStore
* subclasses.
*
* Upgrading
*
* The keys by which a server looks up associations in its store have
* changed in version 1.2 of this library. If your store has entries
* created from version 1.0 code, you should empty it.
*
* 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
*/
 
/**
* Required imports
*/
require_once "Auth/OpenID.php";
require_once "Auth/OpenID/Association.php";
require_once "Auth/OpenID/CryptUtil.php";
require_once "Auth/OpenID/BigMath.php";
require_once "Auth/OpenID/DiffieHellman.php";
require_once "Auth/OpenID/KVForm.php";
require_once "Auth/OpenID/TrustRoot.php";
require_once "Auth/OpenID/ServerRequest.php";
 
define('AUTH_OPENID_HTTP_OK', 200);
define('AUTH_OPENID_HTTP_REDIRECT', 302);
define('AUTH_OPENID_HTTP_ERROR', 400);
 
global $_Auth_OpenID_Request_Modes,
$_Auth_OpenID_OpenID_Prefix,
$_Auth_OpenID_Encode_Kvform,
$_Auth_OpenID_Encode_Url;
 
/**
* @access private
*/
$_Auth_OpenID_Request_Modes = array('checkid_setup',
'checkid_immediate');
 
/**
* @access private
*/
$_Auth_OpenID_OpenID_Prefix = "openid.";
 
/**
* @access private
*/
$_Auth_OpenID_Encode_Kvform = array('kfvorm');
 
/**
* @access private
*/
$_Auth_OpenID_Encode_Url = array('URL/redirect');
 
/**
* @access private
*/
function _isError($obj, $cls = 'Auth_OpenID_ServerError')
{
return is_a($obj, $cls);
}
 
/**
* An error class which gets instantiated and returned whenever an
* OpenID protocol error occurs. Be prepared to use this in place of
* an ordinary server response.
*
* @package OpenID
*/
class Auth_OpenID_ServerError {
/**
* @access private
*/
function Auth_OpenID_ServerError($query = null, $message = null)
{
$this->message = $message;
$this->query = $query;
}
 
/**
* Returns the return_to URL for the request which caused this
* error.
*/
function hasReturnTo()
{
global $_Auth_OpenID_OpenID_Prefix;
if ($this->query) {
return array_key_exists($_Auth_OpenID_OpenID_Prefix .
'return_to', $this->query);
} else {
return false;
}
}
 
/**
* Encodes this error's response as a URL suitable for
* redirection. If the response has no return_to, another
* Auth_OpenID_ServerError is returned.
*/
function encodeToURL()
{
global $_Auth_OpenID_OpenID_Prefix;
$return_to = Auth_OpenID::arrayGet($this->query,
$_Auth_OpenID_OpenID_Prefix .
'return_to');
if (!$return_to) {
return new Auth_OpenID_ServerError(null, "no return_to URL");
}
 
return Auth_OpenID::appendArgs($return_to,
array('openid.mode' => 'error',
'openid.error' => $this->toString()));
}
 
/**
* Encodes the response to key-value form. This is a
* machine-readable format used to respond to messages which came
* directly from the consumer and not through the user-agent. See
* the OpenID specification.
*/
function encodeToKVForm()
{
return Auth_OpenID_KVForm::fromArray(
array('mode' => 'error',
'error' => $this->toString()));
}
 
/**
* Returns one of $_Auth_OpenID_Encode_Url,
* $_Auth_OpenID_Encode_Kvform, or null, depending on the type of
* encoding expected for this error's payload.
*/
function whichEncoding()
{
global $_Auth_OpenID_Encode_Url,
$_Auth_OpenID_Encode_Kvform,
$_Auth_OpenID_Request_Modes;
 
if ($this->hasReturnTo()) {
return $_Auth_OpenID_Encode_Url;
}
 
$mode = Auth_OpenID::arrayGet($this->query, 'openid.mode');
 
if ($mode) {
if (!in_array($mode, $_Auth_OpenID_Request_Modes)) {
return $_Auth_OpenID_Encode_Kvform;
}
}
return null;
}
 
/**
* Returns this error message.
*/
function toString()
{
if ($this->message) {
return $this->message;
} else {
return get_class($this) . " error";
}
}
}
 
/**
* An error indicating that the return_to URL is malformed.
*
* @package OpenID
*/
class Auth_OpenID_MalformedReturnURL extends Auth_OpenID_ServerError {
function Auth_OpenID_MalformedReturnURL($query, $return_to)
{
$this->return_to = $return_to;
parent::Auth_OpenID_ServerError($query, "malformed return_to URL");
}
}
 
/**
* This error is returned when the trust_root value is malformed.
*
* @package OpenID
*/
class Auth_OpenID_MalformedTrustRoot extends Auth_OpenID_ServerError {
function toString()
{
return "Malformed trust root";
}
}
 
/**
* The base class for all server request classes.
*
* @access private
* @package OpenID
*/
class Auth_OpenID_Request {
var $mode = null;
}
 
/**
* A request to verify the validity of a previous response.
*
* @access private
* @package OpenID
*/
class Auth_OpenID_CheckAuthRequest extends Auth_OpenID_Request {
var $mode = "check_authentication";
var $invalidate_handle = null;
 
function Auth_OpenID_CheckAuthRequest($assoc_handle, $sig, $signed,
$invalidate_handle = null)
{
$this->assoc_handle = $assoc_handle;
$this->sig = $sig;
$this->signed = $signed;
if ($invalidate_handle !== null) {
$this->invalidate_handle = $invalidate_handle;
}
}
 
function fromQuery($query)
{
global $_Auth_OpenID_OpenID_Prefix;
 
$required_keys = array('assoc_handle', 'sig', 'signed');
 
foreach ($required_keys as $k) {
if (!array_key_exists($_Auth_OpenID_OpenID_Prefix . $k,
$query)) {
return new Auth_OpenID_ServerError($query,
sprintf("%s request missing required parameter %s from \
query", "check_authentication", $k));
}
}
 
$assoc_handle = $query[$_Auth_OpenID_OpenID_Prefix . 'assoc_handle'];
$sig = $query[$_Auth_OpenID_OpenID_Prefix . 'sig'];
$signed_list = $query[$_Auth_OpenID_OpenID_Prefix . 'signed'];
 
$signed_list = explode(",", $signed_list);
$signed_pairs = array();
 
foreach ($signed_list as $field) {
if ($field == 'mode') {
// XXX KLUDGE HAX WEB PROTOCoL BR0KENNN
//
// openid.mode is currently check_authentication
// because that's the mode of this request. But the
// signature was made on something with a different
// openid.mode.
$value = "id_res";
} else {
if (array_key_exists($_Auth_OpenID_OpenID_Prefix . $field,
$query)) {
$value = $query[$_Auth_OpenID_OpenID_Prefix . $field];
} else {
return new Auth_OpenID_ServerError($query,
sprintf("Couldn't find signed field %r in query %s",
$field, var_export($query, true)));
}
}
$signed_pairs[] = array($field, $value);
}
 
$result = new Auth_OpenID_CheckAuthRequest($assoc_handle, $sig,
$signed_pairs);
$result->invalidate_handle = Auth_OpenID::arrayGet($query,
$_Auth_OpenID_OpenID_Prefix . 'invalidate_handle');
return $result;
}
 
function answer(&$signatory)
{
$is_valid = $signatory->verify($this->assoc_handle, $this->sig,
$this->signed);
 
// Now invalidate that assoc_handle so it this checkAuth
// message cannot be replayed.
$signatory->invalidate($this->assoc_handle, true);
$response = new Auth_OpenID_ServerResponse($this);
$response->fields['is_valid'] = $is_valid ? "true" : "false";
 
if ($this->invalidate_handle) {
$assoc = $signatory->getAssociation($this->invalidate_handle,
false);
if (!$assoc) {
$response->fields['invalidate_handle'] =
$this->invalidate_handle;
}
}
return $response;
}
}
 
class Auth_OpenID_PlainTextServerSession {
/**
* An object that knows how to handle association requests with no
* session type.
*/
var $session_type = 'plaintext';
 
function fromQuery($unused_request)
{
return new Auth_OpenID_PlainTextServerSession();
}
 
function answer($secret)
{
return array('mac_key' => base64_encode($secret));
}
}
 
class Auth_OpenID_DiffieHellmanServerSession {
/**
* An object that knows how to handle association requests with
* the Diffie-Hellman session type.
*/
 
var $session_type = 'DH-SHA1';
 
function Auth_OpenID_DiffieHellmanServerSession($dh, $consumer_pubkey)
{
$this->dh = $dh;
$this->consumer_pubkey = $consumer_pubkey;
}
 
function fromQuery($query)
{
$dh_modulus = Auth_OpenID::arrayGet($query, 'openid.dh_modulus');
$dh_gen = Auth_OpenID::arrayGet($query, 'openid.dh_gen');
 
if ((($dh_modulus === null) && ($dh_gen !== null)) ||
(($dh_gen === null) && ($dh_modulus !== null))) {
 
if ($dh_modulus === null) {
$missing = 'modulus';
} else {
$missing = 'generator';
}
 
return new Auth_OpenID_ServerError(
'If non-default modulus or generator is '.
'supplied, both must be supplied. Missing '.
$missing);
}
 
$lib =& Auth_OpenID_getMathLib();
 
if ($dh_modulus || $dh_gen) {
$dh_modulus = $lib->base64ToLong($dh_modulus);
$dh_gen = $lib->base64ToLong($dh_gen);
if ($lib->cmp($dh_modulus, 0) == 0 ||
$lib->cmp($dh_gen, 0) == 0) {
return new Auth_OpenID_ServerError(
$query, "Failed to parse dh_mod or dh_gen");
}
$dh = new Auth_OpenID_DiffieHellman($dh_modulus, $dh_gen);
} else {
$dh = new Auth_OpenID_DiffieHellman();
}
 
$consumer_pubkey = Auth_OpenID::arrayGet($query,
'openid.dh_consumer_public');
if ($consumer_pubkey === null) {
return new Auth_OpenID_ServerError(
'Public key for DH-SHA1 session '.
'not found in query');
}
 
$consumer_pubkey =
$lib->base64ToLong($consumer_pubkey);
 
if ($consumer_pubkey === false) {
return new Auth_OpenID_ServerError($query,
"dh_consumer_public is not base64");
}
 
return new Auth_OpenID_DiffieHellmanServerSession($dh,
$consumer_pubkey);
}
 
function answer($secret)
{
$lib =& Auth_OpenID_getMathLib();
$mac_key = $this->dh->xorSecret($this->consumer_pubkey, $secret);
return array(
'dh_server_public' =>
$lib->longToBase64($this->dh->public),
'enc_mac_key' => base64_encode($mac_key));
}
}
 
/**
* A request to associate with the server.
*
* @access private
* @package OpenID
*/
class Auth_OpenID_AssociateRequest extends Auth_OpenID_Request {
var $mode = "associate";
var $assoc_type = 'HMAC-SHA1';
 
function Auth_OpenID_AssociateRequest(&$session)
{
$this->session =& $session;
}
 
function fromQuery($query)
{
global $_Auth_OpenID_OpenID_Prefix;
 
$session_classes = array(
'DH-SHA1' => 'Auth_OpenID_DiffieHellmanServerSession',
null => 'Auth_OpenID_PlainTextServerSession');
 
$session_type = null;
 
if (array_key_exists($_Auth_OpenID_OpenID_Prefix . 'session_type',
$query)) {
$session_type = $query[$_Auth_OpenID_OpenID_Prefix .
'session_type'];
}
 
if (!array_key_exists($session_type, $session_classes)) {
return new Auth_OpenID_ServerError($query,
"Unknown session type $session_type");
}
 
$session_cls = $session_classes[$session_type];
$session = call_user_func_array(array($session_cls, 'fromQuery'),
array($query));
 
if (($session === null) || (_isError($session))) {
return new Auth_OpenID_ServerError($query,
"Error parsing $session_type session");
}
 
return new Auth_OpenID_AssociateRequest($session);
}
 
function answer($assoc)
{
$ml =& Auth_OpenID_getMathLib();
$response = new Auth_OpenID_ServerResponse($this);
 
$response->fields = array('expires_in' => $assoc->getExpiresIn(),
'assoc_type' => 'HMAC-SHA1',
'assoc_handle' => $assoc->handle);
 
$r = $this->session->answer($assoc->secret);
foreach ($r as $k => $v) {
$response->fields[$k] = $v;
}
 
if ($this->session->session_type != 'plaintext') {
$response->fields['session_type'] = $this->session->session_type;
}
 
return $response;
}
}
 
/**
* A request to confirm the identity of a user.
*
* @access private
* @package OpenID
*/
class Auth_OpenID_CheckIDRequest extends Auth_OpenID_Request {
var $mode = "checkid_setup"; // or "checkid_immediate"
var $immediate = false;
var $trust_root = null;
 
function make($query, $identity, $return_to, $trust_root = null,
$immediate = false, $assoc_handle = null)
{
if (!Auth_OpenID_TrustRoot::_parse($return_to)) {
return new Auth_OpenID_MalformedReturnURL($query, $return_to);
}
 
$r = new Auth_OpenID_CheckIDRequest($identity, $return_to,
$trust_root, $immediate,
$assoc_handle);
 
if (!$r->trustRootValid()) {
return new Auth_OpenID_UntrustedReturnURL($return_to,
$trust_root);
} else {
return $r;
}
}
 
function Auth_OpenID_CheckIDRequest($identity, $return_to,
$trust_root = null, $immediate = false,
$assoc_handle = null)
{
$this->identity = $identity;
$this->return_to = $return_to;
$this->trust_root = $trust_root;
$this->assoc_handle = $assoc_handle;
 
if ($immediate) {
$this->immediate = true;
$this->mode = "checkid_immediate";
} else {
$this->immediate = false;
$this->mode = "checkid_setup";
}
}
 
function fromQuery($query)
{
global $_Auth_OpenID_OpenID_Prefix;
 
$mode = $query[$_Auth_OpenID_OpenID_Prefix . 'mode'];
$immediate = null;
 
if ($mode == "checkid_immediate") {
$immediate = true;
$mode = "checkid_immediate";
} else {
$immediate = false;
$mode = "checkid_setup";
}
 
$required = array('identity',
'return_to');
 
$optional = array('trust_root',
'assoc_handle');
 
$values = array();
 
foreach ($required as $field) {
if (array_key_exists($_Auth_OpenID_OpenID_Prefix . $field,
$query)) {
$value = $query[$_Auth_OpenID_OpenID_Prefix . $field];
} else {
return new Auth_OpenID_ServerError($query,
sprintf("Missing required field %s from request",
$field));
}
$values[$field] = $value;
}
 
foreach ($optional as $field) {
$value = null;
if (array_key_exists($_Auth_OpenID_OpenID_Prefix . $field,
$query)) {
$value = $query[$_Auth_OpenID_OpenID_Prefix. $field];
}
if ($value) {
$values[$field] = $value;
}
}
 
if (!Auth_OpenID_TrustRoot::_parse($values['return_to'])) {
return new Auth_OpenID_MalformedReturnURL($query,
$values['return_to']);
}
 
$obj = Auth_OpenID_CheckIDRequest::make($query,
$values['identity'],
$values['return_to'],
Auth_OpenID::arrayGet($values,
'trust_root', null),
$immediate);
 
if (is_a($obj, 'Auth_OpenID_ServerError')) {
return $obj;
}
 
if (Auth_OpenID::arrayGet($values, 'assoc_handle')) {
$obj->assoc_handle = $values['assoc_handle'];
}
 
return $obj;
}
 
function trustRootValid()
{
if (!$this->trust_root) {
return true;
}
 
$tr = Auth_OpenID_TrustRoot::_parse($this->trust_root);
if ($tr === false) {
return new Auth_OpenID_MalformedTrustRoot(null, $this->trust_root);
}
 
return Auth_OpenID_TrustRoot::match($this->trust_root,
$this->return_to);
}
 
function answer($allow, $server_url = null)
{
if ($allow || $this->immediate) {
$mode = 'id_res';
} else {
$mode = 'cancel';
}
 
$response = new Auth_OpenID_CheckIDResponse($this, $mode);
 
if ($allow) {
$response->fields['identity'] = $this->identity;
$response->fields['return_to'] = $this->return_to;
if (!$this->trustRootValid()) {
return new Auth_OpenID_UntrustedReturnURL($this->return_to,
$this->trust_root);
}
} else {
$response->signed = array();
if ($this->immediate) {
if (!$server_url) {
return new Auth_OpenID_ServerError(null,
'setup_url is required for $allow=false \
in immediate mode.');
}
 
$setup_request =& new Auth_OpenID_CheckIDRequest(
$this->identity,
$this->return_to,
$this->trust_root,
false,
$this->assoc_handle);
 
$setup_url = $setup_request->encodeToURL($server_url);
 
$response->fields['user_setup_url'] = $setup_url;
}
}
 
return $response;
}
 
function encodeToURL($server_url)
{
global $_Auth_OpenID_OpenID_Prefix;
 
// Imported from the alternate reality where these classes are
// used in both the client and server code, so Requests are
// Encodable too. That's right, code imported from alternate
// realities all for the love of you, id_res/user_setup_url.
 
$q = array('mode' => $this->mode,
'identity' => $this->identity,
'return_to' => $this->return_to);
 
if ($this->trust_root) {
$q['trust_root'] = $this->trust_root;
}
 
if ($this->assoc_handle) {
$q['assoc_handle'] = $this->assoc_handle;
}
 
$_q = array();
 
foreach ($q as $k => $v) {
$_q[$_Auth_OpenID_OpenID_Prefix . $k] = $v;
}
 
return Auth_OpenID::appendArgs($server_url, $_q);
}
 
function getCancelURL()
{
global $_Auth_OpenID_OpenID_Prefix;
 
if ($this->immediate) {
return new Auth_OpenID_ServerError(null,
"Cancel is not an appropriate \
response to immediate mode \
requests.");
}
 
return Auth_OpenID::appendArgs($this->return_to,
array($_Auth_OpenID_OpenID_Prefix . 'mode' =>
'cancel'));
}
}
 
/**
* This class encapsulates the response to an OpenID server request.
*
* @access private
* @package OpenID
*/
class Auth_OpenID_ServerResponse {
 
function Auth_OpenID_ServerResponse($request)
{
$this->request = $request;
$this->fields = array();
}
 
function whichEncoding()
{
global $_Auth_OpenID_Encode_Kvform,
$_Auth_OpenID_Request_Modes,
$_Auth_OpenID_Encode_Url;
 
if (in_array($this->request->mode, $_Auth_OpenID_Request_Modes)) {
return $_Auth_OpenID_Encode_Url;
} else {
return $_Auth_OpenID_Encode_Kvform;
}
}
 
function encodeToURL()
{
global $_Auth_OpenID_OpenID_Prefix;
 
$fields = array();
 
foreach ($this->fields as $k => $v) {
$fields[$_Auth_OpenID_OpenID_Prefix . $k] = $v;
}
 
return Auth_OpenID::appendArgs($this->request->return_to, $fields);
}
 
function encodeToKVForm()
{
return Auth_OpenID_KVForm::fromArray($this->fields);
}
}
 
/**
* A response to a checkid request.
*
* @access private
* @package OpenID
*/
class Auth_OpenID_CheckIDResponse extends Auth_OpenID_ServerResponse {
 
function Auth_OpenID_CheckIDResponse(&$request, $mode = 'id_res')
{
parent::Auth_OpenID_ServerResponse($request);
$this->fields['mode'] = $mode;
$this->signed = array();
 
if ($mode == 'id_res') {
array_push($this->signed, 'mode', 'identity', 'return_to');
}
}
 
function addField($namespace, $key, $value, $signed = true)
{
if ($namespace) {
$key = sprintf('%s.%s', $namespace, $key);
}
$this->fields[$key] = $value;
if ($signed && !in_array($key, $this->signed)) {
$this->signed[] = $key;
}
}
 
function addFields($namespace, $fields, $signed = true)
{
foreach ($fields as $k => $v) {
$this->addField($namespace, $k, $v, $signed);
}
}
 
function update($namespace, $other)
{
$namespaced_fields = array();
 
foreach ($other->fields as $k => $v) {
$name = sprintf('%s.%s', $namespace, $k);
 
$namespaced_fields[$name] = $v;
}
 
$this->fields = array_merge($this->fields, $namespaced_fields);
$this->signed = array_merge($this->signed, $other->signed);
}
}
 
/**
* A web-capable response object which you can use to generate a
* user-agent response.
*
* @package OpenID
*/
class Auth_OpenID_WebResponse {
var $code = AUTH_OPENID_HTTP_OK;
var $body = "";
 
function Auth_OpenID_WebResponse($code = null, $headers = null,
$body = null)
{
if ($code) {
$this->code = $code;
}
 
if ($headers !== null) {
$this->headers = $headers;
} else {
$this->headers = array();
}
 
if ($body !== null) {
$this->body = $body;
}
}
}
 
/**
* Responsible for the signature of query data and the verification of
* OpenID signature values.
*
* @package OpenID
*/
class Auth_OpenID_Signatory {
 
// = 14 * 24 * 60 * 60; # 14 days, in seconds
var $SECRET_LIFETIME = 1209600;
 
// keys have a bogus server URL in them because the filestore
// really does expect that key to be a URL. This seems a little
// silly for the server store, since I expect there to be only one
// server URL.
var $normal_key = 'http://localhost/|normal';
var $dumb_key = 'http://localhost/|dumb';
 
/**
* Create a new signatory using a given store.
*/
function Auth_OpenID_Signatory(&$store)
{
// assert store is not None
$this->store =& $store;
}
 
/**
* Verify, using a given association handle, a signature with
* signed key-value pairs from an HTTP request.
*/
function verify($assoc_handle, $sig, $signed_pairs)
{
$assoc = $this->getAssociation($assoc_handle, true);
if (!$assoc) {
// oidutil.log("failed to get assoc with handle %r to verify sig %r"
// % (assoc_handle, sig))
return false;
}
 
$expected_sig = base64_encode($assoc->sign($signed_pairs));
 
return $sig == $expected_sig;
}
 
/**
* Given a response, sign the fields in the response's 'signed'
* list, and insert the signature into the response.
*/
function sign($response)
{
$signed_response = $response;
$assoc_handle = $response->request->assoc_handle;
 
if ($assoc_handle) {
// normal mode
$assoc = $this->getAssociation($assoc_handle, false);
if (!$assoc) {
// fall back to dumb mode
$signed_response->fields['invalidate_handle'] = $assoc_handle;
$assoc = $this->createAssociation(true);
}
} else {
// dumb mode.
$assoc = $this->createAssociation(true);
}
 
$signed_response->fields['assoc_handle'] = $assoc->handle;
$assoc->addSignature($signed_response->signed,
$signed_response->fields, '');
return $signed_response;
}
 
/**
* Make a new association.
*/
function createAssociation($dumb = true, $assoc_type = 'HMAC-SHA1')
{
$secret = Auth_OpenID_CryptUtil::getBytes(20);
$uniq = base64_encode(Auth_OpenID_CryptUtil::getBytes(4));
$handle = sprintf('{%s}{%x}{%s}', $assoc_type, intval(time()), $uniq);
 
$assoc = Auth_OpenID_Association::fromExpiresIn(
$this->SECRET_LIFETIME, $handle, $secret, $assoc_type);
 
if ($dumb) {
$key = $this->dumb_key;
} else {
$key = $this->normal_key;
}
 
$this->store->storeAssociation($key, $assoc);
return $assoc;
}
 
/**
* Given an association handle, get the association from the
* store, or return a ServerError or null if something goes wrong.
*/
function getAssociation($assoc_handle, $dumb)
{
if ($assoc_handle === null) {
return new Auth_OpenID_ServerError(null,
"assoc_handle must not be null");
}
 
if ($dumb) {
$key = $this->dumb_key;
} else {
$key = $this->normal_key;
}
 
$assoc = $this->store->getAssociation($key, $assoc_handle);
 
if (($assoc !== null) && ($assoc->getExpiresIn() <= 0)) {
$this->store->removeAssociation($key, $assoc_handle);
$assoc = null;
}
 
return $assoc;
}
 
/**
* Invalidate a given association handle.
*/
function invalidate($assoc_handle, $dumb)
{
if ($dumb) {
$key = $this->dumb_key;
} else {
$key = $this->normal_key;
}
$this->store->removeAssociation($key, $assoc_handle);
}
}
 
/**
* Encode an Auth_OpenID_Response to an Auth_OpenID_WebResponse.
*
* @package OpenID
*/
class Auth_OpenID_Encoder {
 
var $responseFactory = 'Auth_OpenID_WebResponse';
 
/**
* Encode an Auth_OpenID_Response and return an
* Auth_OpenID_WebResponse.
*/
function encode(&$response)
{
global $_Auth_OpenID_Encode_Kvform,
$_Auth_OpenID_Encode_Url;
 
$cls = $this->responseFactory;
 
$encode_as = $response->whichEncoding();
if ($encode_as == $_Auth_OpenID_Encode_Kvform) {
$wr = new $cls(null, null, $response->encodeToKVForm());
if (is_a($response, 'Auth_OpenID_ServerError')) {
$wr->code = AUTH_OPENID_HTTP_ERROR;
}
} else if ($encode_as == $_Auth_OpenID_Encode_Url) {
$location = $response->encodeToURL();
$wr = new $cls(AUTH_OPENID_HTTP_REDIRECT,
array('location' => $location));
} else {
return new Auth_OpenID_EncodingError($response);
}
return $wr;
}
}
 
/**
* Returns true if the given response needs a signature.
*
* @access private
*/
function needsSigning($response)
{
return (in_array($response->request->mode, array('checkid_setup',
'checkid_immediate')) &&
$response->signed);
}
 
/**
* An encoder which also takes care of signing fields when required.
*
* @package OpenID
*/
class Auth_OpenID_SigningEncoder extends Auth_OpenID_Encoder {
 
function Auth_OpenID_SigningEncoder(&$signatory)
{
$this->signatory =& $signatory;
}
 
/**
* Sign an Auth_OpenID_Response and return an
* Auth_OpenID_WebResponse.
*/
function encode(&$response)
{
// the isinstance is a bit of a kludge... it means there isn't
// really an adapter to make the interfaces quite match.
if (!is_a($response, 'Auth_OpenID_ServerError') &&
needsSigning($response)) {
 
if (!$this->signatory) {
return new Auth_OpenID_ServerError(null,
"Must have a store to sign request");
}
if (array_key_exists('sig', $response->fields)) {
return new Auth_OpenID_AlreadySigned($response);
}
$response = $this->signatory->sign($response);
}
return parent::encode($response);
}
}
 
/**
* Decode an incoming Auth_OpenID_WebResponse into an
* Auth_OpenID_Request.
*
* @package OpenID
*/
class Auth_OpenID_Decoder {
 
function Auth_OpenID_Decoder()
{
global $_Auth_OpenID_OpenID_Prefix;
$this->prefix = $_Auth_OpenID_OpenID_Prefix;
 
$this->handlers = array(
'checkid_setup' => 'Auth_OpenID_CheckIDRequest',
'checkid_immediate' => 'Auth_OpenID_CheckIDRequest',
'check_authentication' => 'Auth_OpenID_CheckAuthRequest',
'associate' => 'Auth_OpenID_AssociateRequest'
);
}
 
/**
* Given an HTTP query in an array (key-value pairs), decode it
* into an Auth_OpenID_Request object.
*/
function decode($query)
{
if (!$query) {
return null;
}
 
$myquery = array();
 
foreach ($query as $k => $v) {
if (strpos($k, $this->prefix) === 0) {
$myquery[$k] = $v;
}
}
 
if (!$myquery) {
return null;
}
 
$mode = Auth_OpenID::arrayGet($myquery, $this->prefix . 'mode');
if (!$mode) {
return new Auth_OpenID_ServerError($query,
sprintf("No %s mode found in query", $this->prefix));
}
 
$handlerCls = Auth_OpenID::arrayGet($this->handlers, $mode,
$this->defaultDecoder($query));
 
if (!is_a($handlerCls, 'Auth_OpenID_ServerError')) {
return call_user_func_array(array($handlerCls, 'fromQuery'),
array($query));
} else {
return $handlerCls;
}
}
 
function defaultDecoder($query)
{
$mode = $query[$this->prefix . 'mode'];
return new Auth_OpenID_ServerError($query,
sprintf("No decoder for mode %s", $mode));
}
}
 
/**
* An error that indicates an encoding problem occurred.
*
* @package OpenID
*/
class Auth_OpenID_EncodingError {
function Auth_OpenID_EncodingError(&$response)
{
$this->response =& $response;
}
}
 
/**
* An error that indicates that a response was already signed.
*
* @package OpenID
*/
class Auth_OpenID_AlreadySigned extends Auth_OpenID_EncodingError {
// This response is already signed.
}
 
/**
* An error that indicates that the given return_to is not under the
* given trust_root.
*
* @package OpenID
*/
class Auth_OpenID_UntrustedReturnURL extends Auth_OpenID_ServerError {
function Auth_OpenID_UntrustedReturnURL($return_to, $trust_root)
{
global $_Auth_OpenID_OpenID_Prefix;
 
$query = array(
$_Auth_OpenID_OpenID_Prefix . 'return_to' => $return_to,
$_Auth_OpenID_OpenID_Prefix . 'trust_root' => $trust_root);
 
parent::Auth_OpenID_ServerError($query);
}
 
function toString()
{
global $_Auth_OpenID_OpenID_Prefix;
 
$return_to = $this->query[$_Auth_OpenID_OpenID_Prefix . 'return_to'];
$trust_root = $this->query[$_Auth_OpenID_OpenID_Prefix . 'trust_root'];
 
return sprintf("return_to %s not under trust_root %s",
$return_to, $trust_root);
}
}
 
/**
* An object that implements the OpenID protocol for a single URL.
*
* Use this object by calling getOpenIDResponse when you get any
* request for the server URL.
*
* @package OpenID
*/
class Auth_OpenID_Server {
function Auth_OpenID_Server(&$store)
{
$this->store =& $store;
$this->signatory =& new Auth_OpenID_Signatory($this->store);
$this->encoder =& new Auth_OpenID_SigningEncoder($this->signatory);
$this->decoder =& new Auth_OpenID_Decoder();
}
 
/**
* Handle a request. Given an Auth_OpenID_Request object, call
* the appropriate Auth_OpenID_Server method to process the
* request and generate a response.
*
* @param Auth_OpenID_Request $request An Auth_OpenID_Request
* returned by Auth_OpenID_Server::decodeRequest.
*
* @return Auth_OpenID_Response $response A response object
* capable of generating a user-agent reply.
*/
function handleRequest($request)
{
if (method_exists($this, "openid_" . $request->mode)) {
$handler = array($this, "openid_" . $request->mode);
return call_user_func($handler, $request);
}
return null;
}
 
/**
* The callback for 'check_authentication' messages.
*
* @access private
*/
function openid_check_authentication(&$request)
{
return $request->answer($this->signatory);
}
 
/**
* The callback for 'associate' messages.
*
* @access private
*/
function openid_associate(&$request)
{
$assoc = $this->signatory->createAssociation(false);
return $request->answer($assoc);
}
 
/**
* Encodes as response in the appropriate format suitable for
* sending to the user agent.
*/
function encodeResponse(&$response)
{
return $this->encoder->encode($response);
}
 
/**
* Decodes a query args array into the appropriate
* Auth_OpenID_Request object.
*/
function decodeRequest(&$query)
{
return $this->decoder->decode($query);
}
}
 
?>
/trunk/composants/openid/Auth/OpenID/Parse.php
New file
0,0 → 1,308
<?php
 
/**
* This module implements a VERY limited parser that finds <link> tags
* in the head of HTML or XHTML documents and parses out their
* attributes according to the OpenID spec. It is a liberal parser,
* but it requires these things from the data in order to work:
*
* - There must be an open <html> tag
*
* - There must be an open <head> tag inside of the <html> tag
*
* - Only <link>s that are found inside of the <head> tag are parsed
* (this is by design)
*
* - The parser follows the OpenID specification in resolving the
* attributes of the link tags. This means that the attributes DO
* NOT get resolved as they would by an XML or HTML parser. In
* particular, only certain entities get replaced, and href
* attributes do not get resolved relative to a base URL.
*
* From http://openid.net/specs.bml:
*
* - The openid.server URL MUST be an absolute URL. OpenID consumers
* MUST NOT attempt to resolve relative URLs.
*
* - The openid.server URL MUST NOT include entities other than &amp;,
* &lt;, &gt;, and &quot;.
*
* The parser ignores SGML comments and <![CDATA[blocks]]>. Both kinds
* of quoting are allowed for attributes.
*
* The parser deals with invalid markup in these ways:
*
* - Tag names are not case-sensitive
*
* - The <html> tag is accepted even when it is not at the top level
*
* - The <head> tag is accepted even when it is not a direct child of
* the <html> tag, but a <html> tag must be an ancestor of the
* <head> tag
*
* - <link> tags are accepted even when they are not direct children
* of the <head> tag, but a <head> tag must be an ancestor of the
* <link> tag
*
* - If there is no closing tag for an open <html> or <head> tag, the
* remainder of the document is viewed as being inside of the
* tag. If there is no closing tag for a <link> tag, the link tag is
* treated as a short tag. Exceptions to this rule are that <html>
* closes <html> and <body> or <head> closes <head>
*
* - Attributes of the <link> tag are not required to be quoted.
*
* - In the case of duplicated attribute names, the attribute coming
* last in the tag will be the value returned.
*
* - Any text that does not parse as an attribute within a link tag
* will be ignored. (e.g. <link pumpkin rel='openid.server' /> will
* ignore pumpkin)
*
* - If there are more than one <html> or <head> tag, the parser only
* looks inside of the first one.
*
* - The contents of <script> tags are ignored entirely, except
* unclosed <script> tags. Unclosed <script> tags are ignored.
*
* - Any other invalid markup is ignored, including unclosed SGML
* comments and unclosed <![CDATA[blocks.
*
* 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 Janrain, Inc.
* @license http://www.gnu.org/copyleft/lesser.html LGPL
*/
 
/**
* Require Auth_OpenID::arrayGet().
*/
require_once "Auth/OpenID.php";
 
class Auth_OpenID_Parse {
 
/**
* Specify some flags for use with regex matching.
*/
var $_re_flags = "si";
 
/**
* Stuff to remove before we start looking for tags
*/
var $_removed_re =
"<!--.*?-->|<!\[CDATA\[.*?\]\]>|<script\b(?!:)[^>]*>.*?<\/script>";
 
/**
* Starts with the tag name at a word boundary, where the tag name
* is not a namespace
*/
var $_tag_expr = "<%s\b(?!:)([^>]*?)(?:\/>|>(.*?)(?:<\/?%s\s*>|\Z))";
 
var $_attr_find = '\b(\w+)=("[^"]*"|\'[^\']*\'|[^\'"\s\/<>]+)';
 
function Auth_OpenID_Parse()
{
$this->_link_find = sprintf("/<link\b(?!:)([^>]*)(?!<)>/%s",
$this->_re_flags);
 
$this->_entity_replacements = array(
'amp' => '&',
'lt' => '<',
'gt' => '>',
'quot' => '"'
);
 
$this->_attr_find = sprintf("/%s/%s",
$this->_attr_find,
$this->_re_flags);
 
$this->_removed_re = sprintf("/%s/%s",
$this->_removed_re,
$this->_re_flags);
 
$this->_ent_replace =
sprintf("&(%s);", implode("|",
$this->_entity_replacements));
}
 
/**
* Returns a regular expression that will match a given tag in an
* SGML string.
*/
function tagMatcher($tag_name, $close_tags = null)
{
if ($close_tags) {
$options = implode("|", array_merge(array($tag_name), $close_tags));
$closer = sprintf("(?:%s)", $options);
} else {
$closer = $tag_name;
}
 
$expr = sprintf($this->_tag_expr, $tag_name, $closer);
return sprintf("/%s/%s", $expr, $this->_re_flags);
}
 
function htmlFind()
{
return $this->tagMatcher('html');
}
 
function headFind()
{
return $this->tagMatcher('head', array('body'));
}
 
function replaceEntities($str)
{
foreach ($this->_entity_replacements as $old => $new) {
$str = preg_replace(sprintf("/&%s;/", $old), $new, $str);
}
return $str;
}
 
function removeQuotes($str)
{
$matches = array();
$double = '/^"(.*)"$/';
$single = "/^\'(.*)\'$/";
 
if (preg_match($double, $str, $matches)) {
return $matches[1];
} else if (preg_match($single, $str, $matches)) {
return $matches[1];
} else {
return $str;
}
}
 
/**
* Find all link tags in a string representing a HTML document and
* return a list of their attributes.
*
* @param string $html The text to parse
* @return array $list An array of arrays of attributes, one for each
* link tag
*/
function parseLinkAttrs($html)
{
$stripped = preg_replace($this->_removed_re,
"",
$html);
 
// Try to find the <HTML> tag.
$html_re = $this->htmlFind();
$html_matches = array();
if (!preg_match($html_re, $stripped, $html_matches)) {
return array();
}
 
// Try to find the <HEAD> tag.
$head_re = $this->headFind();
$head_matches = array();
if (!preg_match($head_re, $html_matches[0], $head_matches)) {
return array();
}
 
$link_data = array();
$link_matches = array();
 
if (!preg_match_all($this->_link_find, $head_matches[0],
$link_matches)) {
return array();
}
 
foreach ($link_matches[0] as $link) {
$attr_matches = array();
preg_match_all($this->_attr_find, $link, $attr_matches);
$link_attrs = array();
foreach ($attr_matches[0] as $index => $full_match) {
$name = $attr_matches[1][$index];
$value = $this->replaceEntities(
$this->removeQuotes($attr_matches[2][$index]));
 
$link_attrs[strtolower($name)] = $value;
}
$link_data[] = $link_attrs;
}
 
return $link_data;
}
 
function relMatches($rel_attr, $target_rel)
{
// Does this target_rel appear in the rel_str?
// XXX: TESTME
$rels = preg_split("/\s+/", trim($rel_attr));
foreach ($rels as $rel) {
$rel = strtolower($rel);
if ($rel == $target_rel) {
return 1;
}
}
 
return 0;
}
 
function linkHasRel($link_attrs, $target_rel)
{
// Does this link have target_rel as a relationship?
// XXX: TESTME
$rel_attr = Auth_OpeniD::arrayGet($link_attrs, 'rel', null);
return ($rel_attr && $this->relMatches($rel_attr,
$target_rel));
}
 
function findLinksRel($link_attrs_list, $target_rel)
{
// Filter the list of link attributes on whether it has
// target_rel as a relationship.
// XXX: TESTME
$result = array();
foreach ($link_attrs_list as $attr) {
if ($this->linkHasRel($attr, $target_rel)) {
$result[] = $attr;
}
}
 
return $result;
}
 
function findFirstHref($link_attrs_list, $target_rel)
{
// Return the value of the href attribute for the first link
// tag in the list that has target_rel as a relationship.
// XXX: TESTME
$matches = $this->findLinksRel($link_attrs_list,
$target_rel);
if (!$matches) {
return null;
}
$first = $matches[0];
return Auth_OpenID::arrayGet($first, 'href', null);
}
}
 
function Auth_OpenID_legacy_discover($html_text)
{
$p = new Auth_OpenID_Parse();
 
$link_attrs = $p->parseLinkAttrs($html_text);
 
$server_url = $p->findFirstHref($link_attrs,
'openid.server');
 
if ($server_url === null) {
return false;
} else {
$delegate_url = $p->findFirstHref($link_attrs,
'openid.delegate');
return array($delegate_url, $server_url);
}
}
 
?>
/trunk/composants/openid/Auth/OpenID/BigMath.php
New file
0,0 → 1,444
<?php
 
/**
* BigMath: A math library wrapper that abstracts out the underlying
* long integer 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 Janrain, Inc.
* @license http://www.gnu.org/copyleft/lesser.html LGPL
*/
 
/**
* Needed for random number generation
*/
require_once 'Auth/OpenID/CryptUtil.php';
 
/**
* The superclass of all big-integer math implementations
* @access private
* @package OpenID
*/
class Auth_OpenID_MathLibrary {
/**
* Given a long integer, returns the number converted to a binary
* string. This function accepts long integer values of arbitrary
* magnitude and uses the local large-number math library when
* available.
*
* @param integer $long The long number (can be a normal PHP
* integer or a number created by one of the available long number
* libraries)
* @return string $binary The binary version of $long
*/
function longToBinary($long)
{
$cmp = $this->cmp($long, 0);
if ($cmp < 0) {
$msg = __FUNCTION__ . " takes only positive integers.";
trigger_error($msg, E_USER_ERROR);
return null;
}
 
if ($cmp == 0) {
return "\x00";
}
 
$bytes = array();
 
while ($this->cmp($long, 0) > 0) {
array_unshift($bytes, $this->mod($long, 256));
$long = $this->div($long, pow(2, 8));
}
 
if ($bytes && ($bytes[0] > 127)) {
array_unshift($bytes, 0);
}
 
$string = '';
foreach ($bytes as $byte) {
$string .= pack('C', $byte);
}
 
return $string;
}
 
/**
* Given a binary string, returns the binary string converted to a
* long number.
*
* @param string $binary The binary version of a long number,
* probably as a result of calling longToBinary
* @return integer $long The long number equivalent of the binary
* string $str
*/
function binaryToLong($str)
{
if ($str === null) {
return null;
}
 
// Use array_merge to return a zero-indexed array instead of a
// one-indexed array.
$bytes = array_merge(unpack('C*', $str));
 
$n = $this->init(0);
 
if ($bytes && ($bytes[0] > 127)) {
trigger_error("bytesToNum works only for positive integers.",
E_USER_WARNING);
return null;
}
 
foreach ($bytes as $byte) {
$n = $this->mul($n, pow(2, 8));
$n = $this->add($n, $byte);
}
 
return $n;
}
 
function base64ToLong($str)
{
$b64 = base64_decode($str);
 
if ($b64 === false) {
return false;
}
 
return $this->binaryToLong($b64);
}
 
function longToBase64($str)
{
return base64_encode($this->longToBinary($str));
}
 
/**
* Returns a random number in the specified range. This function
* accepts $start, $stop, and $step values of arbitrary magnitude
* and will utilize the local large-number math library when
* available.
*
* @param integer $start The start of the range, or the minimum
* random number to return
* @param integer $stop The end of the range, or the maximum
* random number to return
* @param integer $step The step size, such that $result - ($step
* * N) = $start for some N
* @return integer $result The resulting randomly-generated number
*/
function rand($stop)
{
static $duplicate_cache = array();
 
// Used as the key for the duplicate cache
$rbytes = $this->longToBinary($stop);
 
if (array_key_exists($rbytes, $duplicate_cache)) {
list($duplicate, $nbytes) = $duplicate_cache[$rbytes];
} else {
if ($rbytes[0] == "\x00") {
$nbytes = strlen($rbytes) - 1;
} else {
$nbytes = strlen($rbytes);
}
 
$mxrand = $this->pow(256, $nbytes);
 
// If we get a number less than this, then it is in the
// duplicated range.
$duplicate = $this->mod($mxrand, $stop);
 
if (count($duplicate_cache) > 10) {
$duplicate_cache = array();
}
 
$duplicate_cache[$rbytes] = array($duplicate, $nbytes);
}
 
do {
$bytes = "\x00" . Auth_OpenID_CryptUtil::getBytes($nbytes);
$n = $this->binaryToLong($bytes);
// Keep looping if this value is in the low duplicated range
} while ($this->cmp($n, $duplicate) < 0);
 
return $this->mod($n, $stop);
}
}
 
/**
* Exposes BCmath math library functionality.
*
* {@link Auth_OpenID_BcMathWrapper} wraps the functionality provided
* by the BCMath extension.
*
* @access private
* @package OpenID
*/
class Auth_OpenID_BcMathWrapper extends Auth_OpenID_MathLibrary{
var $type = 'bcmath';
 
function add($x, $y)
{
return bcadd($x, $y);
}
 
function sub($x, $y)
{
return bcsub($x, $y);
}
 
function pow($base, $exponent)
{
return bcpow($base, $exponent);
}
 
function cmp($x, $y)
{
return bccomp($x, $y);
}
 
function init($number, $base = 10)
{
return $number;
}
 
function mod($base, $modulus)
{
return bcmod($base, $modulus);
}
 
function mul($x, $y)
{
return bcmul($x, $y);
}
 
function div($x, $y)
{
return bcdiv($x, $y);
}
 
/**
* Same as bcpowmod when bcpowmod is missing
*
* @access private
*/
function _powmod($base, $exponent, $modulus)
{
$square = $this->mod($base, $modulus);
$result = 1;
while($this->cmp($exponent, 0) > 0) {
if ($this->mod($exponent, 2)) {
$result = $this->mod($this->mul($result, $square), $modulus);
}
$square = $this->mod($this->mul($square, $square), $modulus);
$exponent = $this->div($exponent, 2);
}
return $result;
}
 
function powmod($base, $exponent, $modulus)
{
if (function_exists('bcpowmod')) {
return bcpowmod($base, $exponent, $modulus);
} else {
return $this->_powmod($base, $exponent, $modulus);
}
}
 
function toString($num)
{
return $num;
}
}
 
/**
* Exposes GMP math library functionality.
*
* {@link Auth_OpenID_GmpMathWrapper} wraps the functionality provided
* by the GMP extension.
*
* @access private
* @package OpenID
*/
class Auth_OpenID_GmpMathWrapper extends Auth_OpenID_MathLibrary{
var $type = 'gmp';
 
function add($x, $y)
{
return gmp_add($x, $y);
}
 
function sub($x, $y)
{
return gmp_sub($x, $y);
}
 
function pow($base, $exponent)
{
return gmp_pow($base, $exponent);
}
 
function cmp($x, $y)
{
return gmp_cmp($x, $y);
}
 
function init($number, $base = 10)
{
return gmp_init($number, $base);
}
 
function mod($base, $modulus)
{
return gmp_mod($base, $modulus);
}
 
function mul($x, $y)
{
return gmp_mul($x, $y);
}
 
function div($x, $y)
{
return gmp_div_q($x, $y);
}
 
function powmod($base, $exponent, $modulus)
{
return gmp_powm($base, $exponent, $modulus);
}
 
function toString($num)
{
return gmp_strval($num);
}
}
 
/**
* Define the supported extensions. An extension array has keys
* 'modules', 'extension', and 'class'. 'modules' is an array of PHP
* module names which the loading code will attempt to load. These
* values will be suffixed with a library file extension (e.g. ".so").
* 'extension' is the name of a PHP extension which will be tested
* before 'modules' are loaded. 'class' is the string name of a
* {@link Auth_OpenID_MathWrapper} subclass which should be
* instantiated if a given extension is present.
*
* You can define new math library implementations and add them to
* this array.
*/
global $_Auth_OpenID_math_extensions;
$_Auth_OpenID_math_extensions = array(
array('modules' => array('gmp', 'php_gmp'),
'extension' => 'gmp',
'class' => 'Auth_OpenID_GmpMathWrapper'),
array('modules' => array('bcmath', 'php_bcmath'),
'extension' => 'bcmath',
'class' => 'Auth_OpenID_BcMathWrapper')
);
 
/**
* Detect which (if any) math library is available
*/
function Auth_OpenID_detectMathLibrary($exts)
{
$loaded = false;
 
foreach ($exts as $extension) {
// See if the extension specified is already loaded.
if ($extension['extension'] &&
extension_loaded($extension['extension'])) {
$loaded = true;
}
 
// Try to load dynamic modules.
if (!$loaded) {
foreach ($extension['modules'] as $module) {
if (@dl($module . "." . PHP_SHLIB_SUFFIX)) {
$loaded = true;
break;
}
}
}
 
// If the load succeeded, supply an instance of
// Auth_OpenID_MathWrapper which wraps the specified
// module's functionality.
if ($loaded) {
return $extension;
}
}
 
return false;
}
 
/**
* {@link Auth_OpenID_getMathLib} checks for the presence of long
* number extension modules and returns an instance of
* {@link Auth_OpenID_MathWrapper} which exposes the module's
* functionality.
*
* Checks for the existence of an extension module described by the
* local {@link Auth_OpenID_math_extensions} array and returns an
* instance of a wrapper for that extension module. If no extension
* module is found, an instance of {@link Auth_OpenID_MathWrapper} is
* returned, which wraps the native PHP integer implementation. The
* proper calling convention for this method is $lib =&
* Auth_OpenID_getMathLib().
*
* This function checks for the existence of specific long number
* implementations in the following order: GMP followed by BCmath.
*
* @return Auth_OpenID_MathWrapper $instance An instance of
* {@link Auth_OpenID_MathWrapper} or one of its subclasses
*
* @package OpenID
*/
function &Auth_OpenID_getMathLib()
{
// The instance of Auth_OpenID_MathWrapper that we choose to
// supply will be stored here, so that subseqent calls to this
// method will return a reference to the same object.
static $lib = null;
 
if (isset($lib)) {
return $lib;
}
 
if (defined('Auth_OpenID_NO_MATH_SUPPORT')) {
$null = null;
return $null;
}
 
// If this method has not been called before, look at
// $Auth_OpenID_math_extensions and try to find an extension that
// works.
global $_Auth_OpenID_math_extensions;
$ext = Auth_OpenID_detectMathLibrary($_Auth_OpenID_math_extensions);
if ($ext === false) {
$tried = array();
foreach ($_Auth_OpenID_math_extensions as $extinfo) {
$tried[] = $extinfo['extension'];
}
$triedstr = implode(", ", $tried);
 
define('Auth_OpenID_NO_MATH_SUPPORT', true);
return null;
}
 
// Instantiate a new wrapper
$class = $ext['class'];
$lib = new $class();
 
return $lib;
}
 
?>
/trunk/composants/openid/Auth/OpenID/Association.php
New file
0,0 → 1,308
<?php
 
/**
* This module contains code for dealing with associations between
* consumers and servers.
*
* 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
*/
 
/**
* @access private
*/
require_once 'Auth/OpenID/CryptUtil.php';
 
/**
* @access private
*/
require_once 'Auth/OpenID/KVForm.php';
 
/**
* This class represents an association between a server and a
* consumer. In general, users of this library will never see
* instances of this object. The only exception is if you implement a
* custom {@link Auth_OpenID_OpenIDStore}.
*
* If you do implement such a store, it will need to store the values
* of the handle, secret, issued, lifetime, and assoc_type instance
* variables.
*
* @package OpenID
*/
class Auth_OpenID_Association {
 
/**
* This is a HMAC-SHA1 specific value.
*
* @access private
*/
var $SIG_LENGTH = 20;
 
/**
* The ordering and name of keys as stored by serialize.
*
* @access private
*/
var $assoc_keys = array(
'version',
'handle',
'secret',
'issued',
'lifetime',
'assoc_type'
);
 
/**
* This is an alternate constructor (factory method) used by the
* OpenID consumer library to create associations. OpenID store
* implementations shouldn't use this constructor.
*
* @access private
*
* @param integer $expires_in This is the amount of time this
* association is good for, measured in seconds since the
* association was issued.
*
* @param string $handle This is the handle the server gave this
* association.
*
* @param string secret This is the shared secret the server
* generated for this association.
*
* @param assoc_type This is the type of association this
* instance represents. The only valid value of this field at
* this time is 'HMAC-SHA1', but new types may be defined in the
* future.
*
* @return association An {@link Auth_OpenID_Association}
* instance.
*/
function fromExpiresIn($expires_in, $handle, $secret, $assoc_type)
{
$issued = time();
$lifetime = $expires_in;
return new Auth_OpenID_Association($handle, $secret,
$issued, $lifetime, $assoc_type);
}
 
/**
* This is the standard constructor for creating an association.
* The library should create all of the necessary associations, so
* this constructor is not part of the external API.
*
* @access private
*
* @param string $handle This is the handle the server gave this
* association.
*
* @param string $secret This is the shared secret the server
* generated for this association.
*
* @param integer $issued This is the time this association was
* issued, in seconds since 00:00 GMT, January 1, 1970. (ie, a
* unix timestamp)
*
* @param integer $lifetime This is the amount of time this
* association is good for, measured in seconds since the
* association was issued.
*
* @param string $assoc_type This is the type of association this
* instance represents. The only valid value of this field at
* this time is 'HMAC-SHA1', but new types may be defined in the
* future.
*/
function Auth_OpenID_Association(
$handle, $secret, $issued, $lifetime, $assoc_type)
{
if ($assoc_type != 'HMAC-SHA1') {
$fmt = 'HMAC-SHA1 is the only supported association type (got %s)';
trigger_error(sprintf($fmt, $assoc_type), E_USER_ERROR);
}
 
$this->handle = $handle;
$this->secret = $secret;
$this->issued = $issued;
$this->lifetime = $lifetime;
$this->assoc_type = $assoc_type;
}
 
/**
* This returns the number of seconds this association is still
* valid for, or 0 if the association is no longer valid.
*
* @return integer $seconds The number of seconds this association
* is still valid for, or 0 if the association is no longer valid.
*/
function getExpiresIn($now = null)
{
if ($now == null) {
$now = time();
}
 
return max(0, $this->issued + $this->lifetime - $now);
}
 
/**
* This checks to see if two {@link Auth_OpenID_Association}
* instances represent the same association.
*
* @return bool $result true if the two instances represent the
* same association, false otherwise.
*/
function equal($other)
{
return ((gettype($this) == gettype($other))
&& ($this->handle == $other->handle)
&& ($this->secret == $other->secret)
&& ($this->issued == $other->issued)
&& ($this->lifetime == $other->lifetime)
&& ($this->assoc_type == $other->assoc_type));
}
 
/**
* Convert an association to KV form.
*
* @return string $result String in KV form suitable for
* deserialization by deserialize.
*/
function serialize()
{
$data = array(
'version' => '2',
'handle' => $this->handle,
'secret' => base64_encode($this->secret),
'issued' => strval(intval($this->issued)),
'lifetime' => strval(intval($this->lifetime)),
'assoc_type' => $this->assoc_type
);
 
assert(array_keys($data) == $this->assoc_keys);
 
return Auth_OpenID_KVForm::fromArray($data, $strict = true);
}
 
/**
* Parse an association as stored by serialize(). This is the
* inverse of serialize.
*
* @param string $assoc_s Association as serialized by serialize()
* @return Auth_OpenID_Association $result instance of this class
*/
function deserialize($class_name, $assoc_s)
{
$pairs = Auth_OpenID_KVForm::toArray($assoc_s, $strict = true);
$keys = array();
$values = array();
foreach ($pairs as $key => $value) {
if (is_array($value)) {
list($key, $value) = $value;
}
$keys[] = $key;
$values[] = $value;
}
 
$class_vars = get_class_vars($class_name);
$class_assoc_keys = $class_vars['assoc_keys'];
 
sort($keys);
sort($class_assoc_keys);
 
if ($keys != $class_assoc_keys) {
trigger_error('Unexpected key values: ' . strval($keys),
E_USER_WARNING);
return null;
}
 
$version = $pairs['version'];
$handle = $pairs['handle'];
$secret = $pairs['secret'];
$issued = $pairs['issued'];
$lifetime = $pairs['lifetime'];
$assoc_type = $pairs['assoc_type'];
 
if ($version != '2') {
trigger_error('Unknown version: ' . $version, E_USER_WARNING);
return null;
}
 
$issued = intval($issued);
$lifetime = intval($lifetime);
$secret = base64_decode($secret);
 
return new $class_name(
$handle, $secret, $issued, $lifetime, $assoc_type);
}
 
/**
* Generate a signature for a sequence of (key, value) pairs
*
* @access private
* @param array $pairs The pairs to sign, in order. This is an
* array of two-tuples.
* @return string $signature The binary signature of this sequence
* of pairs
*/
function sign($pairs)
{
$kv = Auth_OpenID_KVForm::fromArray($pairs);
return Auth_OpenID_HMACSHA1($this->secret, $kv);
}
 
/**
* Generate a signature for some fields in a dictionary
*
* @access private
* @param array $fields The fields to sign, in order; this is an
* array of strings.
* @param array $data Dictionary of values to sign (an array of
* string => string pairs).
* @return string $signature The signature, base64 encoded
*/
function signDict($fields, $data, $prefix = 'openid.')
{
$pairs = array();
foreach ($fields as $field) {
$pairs[] = array($field, $data[$prefix . $field]);
}
 
return base64_encode($this->sign($pairs));
}
 
/**
* Add a signature to an array of fields
*
* @access private
*/
function addSignature($fields, &$data, $prefix = 'openid.')
{
$sig = $this->signDict($fields, $data, $prefix);
$signed = implode(",", $fields);
$data[$prefix . 'sig'] = $sig;
$data[$prefix . 'signed'] = $signed;
}
 
/**
* Confirm that the signature of these fields matches the
* signature contained in the data
*
* @access private
*/
function checkSignature($data, $prefix = 'openid.')
{
$signed = $data[$prefix . 'signed'];
$fields = explode(",", $signed);
$expected_sig = $this->signDict($fields, $data, $prefix);
$request_sig = $data[$prefix . 'sig'];
 
return ($request_sig == $expected_sig);
}
}
 
?>
/trunk/composants/openid/Auth/OpenID/SQLStore.php
New file
0,0 → 1,658
<?php
 
/**
* SQL-backed OpenID stores.
*
* 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 the PEAR DB module because we'll need it for the SQL-based
* stores implemented here. We silence any errors from the inclusion
* because it might not be present, and a user of the SQL stores may
* supply an Auth_OpenID_DatabaseConnection instance that implements
* its own storage.
*/
global $__Auth_OpenID_PEAR_AVAILABLE;
$__Auth_OpenID_PEAR_AVAILABLE = @include_once 'DB.php';
 
/**
* @access private
*/
require_once 'Auth/OpenID/Interface.php';
 
/**
* This is the parent class for the SQL stores, which contains the
* logic common to all of the SQL stores.
*
* The table names used are determined by the class variables
* settings_table_name, associations_table_name, and
* nonces_table_name. To change the name of the tables used, pass new
* table names into the constructor.
*
* To create the tables with the proper schema, see the createTables
* method.
*
* This class shouldn't be used directly. Use one of its subclasses
* instead, as those contain the code necessary to use a specific
* database. If you're an OpenID integrator and you'd like to create
* an SQL-driven store that wraps an application's database
* abstraction, be sure to create a subclass of
* {@link Auth_OpenID_DatabaseConnection} that calls the application's
* database abstraction calls. Then, pass an instance of your new
* database connection class to your SQLStore subclass constructor.
*
* All methods other than the constructor and createTables should be
* considered implementation details.
*
* @package OpenID
*/
class Auth_OpenID_SQLStore extends Auth_OpenID_OpenIDStore {
 
/**
* This creates a new SQLStore instance. It requires an
* established database connection be given to it, and it allows
* overriding the default table names.
*
* @param connection $connection This must be an established
* connection to a database of the correct type for the SQLStore
* subclass you're using. This must either be an PEAR DB
* connection handle or an instance of a subclass of
* Auth_OpenID_DatabaseConnection.
*
* @param string $settings_table This is an optional parameter to
* specify the name of the table used for this store's settings.
* The default value is 'oid_settings'.
*
* @param associations_table: This is an optional parameter to
* specify the name of the table used for storing associations.
* The default value is 'oid_associations'.
*
* @param nonces_table: This is an optional parameter to specify
* the name of the table used for storing nonces. The default
* value is 'oid_nonces'.
*/
function Auth_OpenID_SQLStore($connection, $settings_table = null,
$associations_table = null,
$nonces_table = null)
{
global $__Auth_OpenID_PEAR_AVAILABLE;
 
$this->settings_table_name = "oid_settings";
$this->associations_table_name = "oid_associations";
$this->nonces_table_name = "oid_nonces";
 
// Check the connection object type to be sure it's a PEAR
// database connection.
if (!(is_object($connection) &&
(is_subclass_of($connection, 'db_common') ||
is_subclass_of($connection,
'auth_openid_databaseconnection')))) {
trigger_error("Auth_OpenID_SQLStore 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 is a PEAR
// constant, so only try to use it if PEAR is present. Note
// that Auth_Openid_Databaseconnection instances need not
// implement ::setFetchMode for this reason.
if ($__Auth_OpenID_PEAR_AVAILABLE) {
$this->connection->setFetchMode(DB_FETCHMODE_ASSOC);
}
 
if ($settings_table) {
$this->settings_table_name = $settings_table;
}
 
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;
 
// Be sure to run the database queries with auto-commit mode
// turned OFF, because we want every function to run in a
// transaction, implicitly. As a rule, methods named with a
// leading underscore will NOT control transaction behavior.
// Callers of these methods will worry about transactions.
$this->connection->autoCommit(false);
 
// Create an empty SQL strings array.
$this->sql = array();
 
// Call this method (which should be overridden by subclasses)
// to populate the $this->sql array with SQL strings.
$this->setSQL();
 
// Verify that all required SQL statements have been set, and
// raise an error if any expected SQL strings were either
// absent or empty.
list($missing, $empty) = $this->_verifySQL();
 
if ($missing) {
trigger_error("Expected keys in SQL query list: " .
implode(", ", $missing),
E_USER_ERROR);
return;
}
 
if ($empty) {
trigger_error("SQL list keys have no SQL strings: " .
implode(", ", $empty),
E_USER_ERROR);
return;
}
 
// Add table names to queries.
$this->_fixSQL();
}
 
function tableExists($table_name)
{
return !$this->isError(
$this->connection->query("SELECT * FROM %s LIMIT 0",
$table_name));
}
 
/**
* Returns true if $value constitutes a database error; returns
* false otherwise.
*/
function isError($value)
{
return PEAR::isError($value);
}
 
/**
* Converts a query result to a boolean. If the result is a
* database error according to $this->isError(), this returns
* false; otherwise, this returns true.
*/
function resultToBool($obj)
{
if ($this->isError($obj)) {
return false;
} else {
return true;
}
}
 
/**
* This method should be overridden by subclasses. This method is
* called by the constructor to set values in $this->sql, which is
* an array keyed on sql name.
*/
function setSQL()
{
}
 
/**
* 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));
 
$this->connection->query(sprintf("DELETE FROM %s",
$this->settings_table_name));
}
 
/**
* @access private
*/
function _verifySQL()
{
$missing = array();
$empty = array();
 
$required_sql_keys = array(
'nonce_table',
'assoc_table',
'settings_table',
'get_auth',
'create_auth',
'set_assoc',
'get_assoc',
'get_assocs',
'remove_assoc',
'add_nonce',
'get_nonce',
'remove_nonce'
);
 
foreach ($required_sql_keys as $key) {
if (!array_key_exists($key, $this->sql)) {
$missing[] = $key;
} else if (!$this->sql[$key]) {
$empty[] = $key;
}
}
 
return array($missing, $empty);
}
 
/**
* @access private
*/
function _fixSQL()
{
$replacements = array(
array(
'value' => $this->nonces_table_name,
'keys' => array('nonce_table',
'add_nonce',
'get_nonce',
'remove_nonce')
),
array(
'value' => $this->associations_table_name,
'keys' => array('assoc_table',
'set_assoc',
'get_assoc',
'get_assocs',
'remove_assoc')
),
array(
'value' => $this->settings_table_name,
'keys' => array('settings_table',
'get_auth',
'create_auth')
)
);
 
foreach ($replacements as $item) {
$value = $item['value'];
$keys = $item['keys'];
 
foreach ($keys as $k) {
if (is_array($this->sql[$k])) {
foreach ($this->sql[$k] as $part_key => $part_value) {
$this->sql[$k][$part_key] = sprintf($part_value,
$value);
}
} else {
$this->sql[$k] = sprintf($this->sql[$k], $value);
}
}
}
}
 
function blobDecode($blob)
{
return $blob;
}
 
function blobEncode($str)
{
return $str;
}
 
function createTables()
{
$this->connection->autoCommit(true);
$n = $this->create_nonce_table();
$a = $this->create_assoc_table();
$s = $this->create_settings_table();
$this->connection->autoCommit(false);
 
if ($n && $a && $s) {
return true;
} else {
return false;
}
}
 
function create_nonce_table()
{
if (!$this->tableExists($this->nonces_table_name)) {
$r = $this->connection->query($this->sql['nonce_table']);
return $this->resultToBool($r);
}
return true;
}
 
function create_assoc_table()
{
if (!$this->tableExists($this->associations_table_name)) {
$r = $this->connection->query($this->sql['assoc_table']);
return $this->resultToBool($r);
}
return true;
}
 
function create_settings_table()
{
if (!$this->tableExists($this->settings_table_name)) {
$r = $this->connection->query($this->sql['settings_table']);
return $this->resultToBool($r);
}
return true;
}
 
/**
* @access private
*/
function _get_auth()
{
return $this->connection->getOne($this->sql['get_auth']);
}
 
/**
* @access private
*/
function _create_auth($str)
{
return $this->connection->query($this->sql['create_auth'],
array($str));
}
 
function getAuthKey()
{
$value = $this->_get_auth();
if (!$value) {
$auth_key =
Auth_OpenID_CryptUtil::randomString($this->AUTH_KEY_LEN);
 
$auth_key_s = $this->blobEncode($auth_key);
$this->_create_auth($auth_key_s);
} else {
$auth_key_s = $value;
$auth_key = $this->blobDecode($auth_key_s);
}
 
$this->connection->commit();
 
if (strlen($auth_key) != $this->AUTH_KEY_LEN) {
$fmt = "Expected %d-byte string for auth key. Got key of length %d";
trigger_error(sprintf($fmt, $this->AUTH_KEY_LEN, strlen($auth_key)),
E_USER_WARNING);
return null;
}
 
return $auth_key;
}
 
/**
* @access private
*/
function _set_assoc($server_url, $handle, $secret, $issued,
$lifetime, $assoc_type)
{
return $this->connection->query($this->sql['set_assoc'],
array(
$server_url,
$handle,
$secret,
$issued,
$lifetime,
$assoc_type));
}
 
function storeAssociation($server_url, $association)
{
if ($this->resultToBool($this->_set_assoc(
$server_url,
$association->handle,
$this->blobEncode(
$association->secret),
$association->issued,
$association->lifetime,
$association->assoc_type
))) {
$this->connection->commit();
} else {
$this->connection->rollback();
}
}
 
/**
* @access private
*/
function _get_assoc($server_url, $handle)
{
$result = $this->connection->getRow($this->sql['get_assoc'],
array($server_url, $handle));
if ($this->isError($result)) {
return null;
} else {
return $result;
}
}
 
/**
* @access private
*/
function _get_assocs($server_url)
{
$result = $this->connection->getAll($this->sql['get_assocs'],
array($server_url));
 
if ($this->isError($result)) {
return array();
} else {
return $result;
}
}
 
function removeAssociation($server_url, $handle)
{
if ($this->_get_assoc($server_url, $handle) == null) {
return false;
}
 
if ($this->resultToBool($this->connection->query(
$this->sql['remove_assoc'],
array($server_url, $handle)))) {
$this->connection->commit();
} else {
$this->connection->rollback();
}
 
return true;
}
 
function getAssociation($server_url, $handle = null)
{
if ($handle !== null) {
$assoc = $this->_get_assoc($server_url, $handle);
 
$assocs = array();
if ($assoc) {
$assocs[] = $assoc;
}
} else {
$assocs = $this->_get_assocs($server_url);
}
 
if (!$assocs || (count($assocs) == 0)) {
return null;
} else {
$associations = array();
 
foreach ($assocs as $assoc_row) {
$assoc = new Auth_OpenID_Association($assoc_row['handle'],
$assoc_row['secret'],
$assoc_row['issued'],
$assoc_row['lifetime'],
$assoc_row['assoc_type']);
 
$assoc->secret = $this->blobDecode($assoc->secret);
 
if ($assoc->getExpiresIn() == 0) {
$this->removeAssociation($server_url, $assoc->handle);
} else {
$associations[] = array($assoc->issued, $assoc);
}
}
 
if ($associations) {
$issued = array();
$assocs = array();
foreach ($associations as $key => $assoc) {
$issued[$key] = $assoc[0];
$assocs[$key] = $assoc[1];
}
 
array_multisort($issued, SORT_DESC, $assocs, SORT_DESC,
$associations);
 
// return the most recently issued one.
list($issued, $assoc) = $associations[0];
return $assoc;
} else {
return null;
}
}
}
 
/**
* @access private
*/
function _add_nonce($nonce, $expires)
{
$sql = $this->sql['add_nonce'];
$result = $this->connection->query($sql, array($nonce, $expires));
return $this->resultToBool($result);
}
 
/**
* @access private
*/
function storeNonce($nonce)
{
if ($this->_add_nonce($nonce, time())) {
$this->connection->commit();
} else {
$this->connection->rollback();
}
}
 
/**
* @access private
*/
function _get_nonce($nonce)
{
$result = $this->connection->getRow($this->sql['get_nonce'],
array($nonce));
 
if ($this->isError($result)) {
return null;
} else {
return $result;
}
}
 
/**
* @access private
*/
function _remove_nonce($nonce)
{
$this->connection->query($this->sql['remove_nonce'],
array($nonce));
}
 
function useNonce($nonce)
{
$row = $this->_get_nonce($nonce);
 
if ($row !== null) {
$nonce = $row['nonce'];
$timestamp = $row['expires'];
$nonce_age = time() - $timestamp;
 
if ($nonce_age > $this->max_nonce_age) {
$present = 0;
} else {
$present = 1;
}
 
$this->_remove_nonce($nonce);
} else {
$present = 0;
}
 
$this->connection->commit();
 
return $present;
}
 
/**
* "Octifies" a binary string by returning a string with escaped
* octal bytes. This is used for preparing binary data for
* PostgreSQL BYTEA fields.
*
* @access private
*/
function _octify($str)
{
$result = "";
for ($i = 0; $i < strlen($str); $i++) {
$ch = substr($str, $i, 1);
if ($ch == "\\") {
$result .= "\\\\\\\\";
} else if (ord($ch) == 0) {
$result .= "\\\\000";
} else {
$result .= "\\" . strval(decoct(ord($ch)));
}
}
return $result;
}
 
/**
* "Unoctifies" octal-escaped data from PostgreSQL and returns the
* resulting ASCII (possibly binary) string.
*
* @access private
*/
function _unoctify($str)
{
$result = "";
$i = 0;
while ($i < strlen($str)) {
$char = $str[$i];
if ($char == "\\") {
// Look to see if the next char is a backslash and
// append it.
if ($str[$i + 1] != "\\") {
$octal_digits = substr($str, $i + 1, 3);
$dec = octdec($octal_digits);
$char = chr($dec);
$i += 4;
} else {
$char = "\\";
$i += 2;
}
} else {
$i += 1;
}
 
$result .= $char;
}
 
return $result;
}
}
 
?>
/trunk/composants/openid/Auth/OpenID/Discover.php
New file
0,0 → 1,258
<?php
 
/**
* The OpenID and Yadis discovery implementation for OpenID 1.2.
*/
 
require_once "Auth/OpenID.php";
require_once "Auth/OpenID/Parse.php";
require_once "Services/Yadis/XRIRes.php";
require_once "Services/Yadis/Yadis.php";
 
define('_OPENID_1_0_NS', 'http://openid.net/xmlns/1.0');
define('_OPENID_1_2_TYPE', 'http://openid.net/signon/1.2');
define('_OPENID_1_1_TYPE', 'http://openid.net/signon/1.1');
define('_OPENID_1_0_TYPE', 'http://openid.net/signon/1.0');
 
/**
* Object representing an OpenID service endpoint.
*/
class Auth_OpenID_ServiceEndpoint {
function Auth_OpenID_ServiceEndpoint()
{
$this->identity_url = null;
$this->server_url = null;
$this->type_uris = array();
$this->delegate = null;
$this->canonicalID = null;
$this->used_yadis = false; // whether this came from an XRDS
}
 
function usesExtension($extension_uri)
{
return in_array($extension_uri, $this->type_uris);
}
 
function parseService($yadis_url, $uri, $type_uris, $service_element)
{
// Set the state of this object based on the contents of the
// service element.
$this->type_uris = $type_uris;
$this->identity_url = $yadis_url;
$this->server_url = $uri;
$this->delegate = Auth_OpenID_ServiceEndpoint::findDelegate(
$service_element);
$this->used_yadis = true;
}
 
function findDelegate($service)
{
// Extract a openid:Delegate value from a Yadis Service
// element. If no delegate is found, returns null.
 
// Try to register new namespace.
$service->parser->registerNamespace('openid',
'http://openid.net/xmlns/1.0');
 
// XXX: should this die if there is more than one delegate
// element?
$delegates = $service->getElements("openid:Delegate");
 
if ($delegates) {
return $service->parser->content($delegates[0]);
} else {
return null;
}
}
 
function getServerID()
{
// Return the identifier that should be sent as the
// openid.identity_url parameter to the server.
if ($this->delegate === null) {
if ($this->canonicalID) {
return $this->canonicalID;
} else {
return $this->identity_url;
}
} else {
return $this->delegate;
}
}
 
function fromHTML($uri, $html)
{
// Parse the given document as HTML looking for an OpenID <link
// rel=...>
$urls = Auth_OpenID_legacy_discover($html);
if ($urls === false) {
return null;
}
 
list($delegate_url, $server_url) = $urls;
 
$service = new Auth_OpenID_ServiceEndpoint();
$service->identity_url = $uri;
$service->delegate = $delegate_url;
$service->server_url = $server_url;
$service->type_uris = array(_OPENID_1_0_TYPE);
return $service;
}
}
 
function filter_MatchesAnyOpenIDType(&$service)
{
$uris = $service->getTypes();
 
foreach ($uris as $uri) {
if (in_array($uri,
array(_OPENID_1_0_TYPE,
_OPENID_1_1_TYPE,
_OPENID_1_2_TYPE))) {
return true;
}
}
 
return false;
}
 
function Auth_OpenID_makeOpenIDEndpoints($uri, $endpoints)
{
$s = array();
 
if (!$endpoints) {
return $s;
}
 
foreach ($endpoints 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();
$openid_endpoint->parseService($uri,
$service_uri,
$type_uris,
$service);
 
$s[] = $openid_endpoint;
}
}
}
 
return $s;
}
 
function Auth_OpenID_discoverWithYadis($uri, &$fetcher)
{
// 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.
$openid_services = array();
 
$http_response = null;
$response = Services_Yadis_Yadis::discover($uri, $http_response,
$fetcher);
 
if ($response) {
$identity_url = $response->uri;
$openid_services =
$response->xrds->services(array('filter_MatchesAnyOpenIDType'));
}
 
if (!$openid_services) {
return @Auth_OpenID_discoverWithoutYadis($uri,
$fetcher);
}
 
if (!$openid_services) {
$body = $response->body;
 
// Try to parse the response as HTML to get OpenID 1.0/1.1
// <link rel="...">
$service = Auth_OpenID_ServiceEndpoint::fromHTML($identity_url,
$body);
 
if ($service !== null) {
$openid_services = array($service);
}
} else {
$openid_services = Auth_OpenID_makeOpenIDEndpoints($response->uri,
$openid_services);
}
 
return array($identity_url, $openid_services, $http_response);
}
 
function _Auth_OpenID_discoverServiceList($uri, &$fetcher)
{
list($url, $services, $resp) = Auth_OpenID_discoverWithYadis($uri,
$fetcher);
 
return $services;
}
 
function _Auth_OpenID_discoverXRIServiceList($uri, &$fetcher)
{
list($url, $services, $resp) = _Auth_OpenID_discoverXRI($uri,
$fetcher);
return $services;
}
 
function Auth_OpenID_discoverWithoutYadis($uri, &$fetcher)
{
$http_resp = @$fetcher->get($uri);
 
if ($http_resp->status != 200) {
return array(null, array(), $http_resp);
}
 
$identity_url = $http_resp->final_url;
 
// Try to parse the response as HTML to get OpenID 1.0/1.1 <link
// rel="...">
$endpoint =& new Auth_OpenID_ServiceEndpoint();
$service = $endpoint->fromHTML($identity_url, $http_resp->body);
if ($service === null) {
$openid_services = array();
} else {
$openid_services = array($service);
}
 
return array($identity_url, $openid_services, $http_resp);
}
 
function _Auth_OpenID_discoverXRI($iname, &$fetcher)
{
$services = new Services_Yadis_ProxyResolver($fetcher);
list($canonicalID, $service_list) = $services->query($iname,
array(_OPENID_1_0_TYPE,
_OPENID_1_1_TYPE,
_OPENID_1_2_TYPE),
array('filter_MatchesAnyOpenIDType'));
 
$endpoints = Auth_OpenID_makeOpenIDEndpoints($iname, $service_list);
 
for ($i = 0; $i < count($endpoints); $i++) {
$endpoints[$i]->canonicalID = $canonicalID;
}
 
// FIXME: returned xri should probably be in some normal form
return array($iname, $endpoints, null);
}
 
function Auth_OpenID_discover($uri, &$fetcher)
{
return @Auth_OpenID_discoverWithYadis($uri, $fetcher);
}
 
?>
/trunk/composants/openid/Auth/OpenID/SQLiteStore.php
New file
0,0 → 1,66
<?php
 
/**
* An SQLite store.
*
* @package OpenID
*/
 
/**
* Require the base class file.
*/
require_once "Auth/OpenID/SQLStore.php";
 
/**
* An SQL store that uses SQLite as its backend.
*
* @package OpenID
*/
class Auth_OpenID_SQLiteStore extends Auth_OpenID_SQLStore {
function setSQL()
{
$this->sql['nonce_table'] =
"CREATE TABLE %s (nonce CHAR(8) UNIQUE PRIMARY KEY, ".
"expires INTEGER)";
 
$this->sql['assoc_table'] =
"CREATE TABLE %s (server_url VARCHAR(2047), handle VARCHAR(255), ".
"secret BLOB(128), issued INTEGER, lifetime INTEGER, ".
"assoc_type VARCHAR(64), PRIMARY KEY (server_url, handle))";
 
$this->sql['settings_table'] =
"CREATE TABLE %s (setting VARCHAR(128) UNIQUE PRIMARY KEY, ".
"value BLOB(20))";
 
$this->sql['create_auth'] =
"INSERT INTO %s VALUES ('auth_key', ?)";
 
$this->sql['get_auth'] =
"SELECT value FROM %s WHERE setting = 'auth_key'";
 
$this->sql['set_assoc'] =
"INSERT OR REPLACE INTO %s VALUES (?, ?, ?, ?, ?, ?)";
 
$this->sql['get_assocs'] =
"SELECT handle, secret, issued, lifetime, assoc_type FROM %s ".
"WHERE server_url = ?";
 
$this->sql['get_assoc'] =
"SELECT handle, secret, issued, lifetime, assoc_type FROM %s ".
"WHERE server_url = ? AND handle = ?";
 
$this->sql['remove_assoc'] =
"DELETE FROM %s WHERE server_url = ? AND handle = ?";
 
$this->sql['add_nonce'] =
"INSERT OR REPLACE INTO %s (nonce, expires) VALUES (?, ?)";
 
$this->sql['get_nonce'] =
"SELECT * FROM %s WHERE nonce = ?";
 
$this->sql['remove_nonce'] =
"DELETE FROM %s WHERE nonce = ?";
}
}
 
?>
/trunk/composants/openid/Auth/OpenID/ServerRequest.php
New file
0,0 → 1,37
<?php
/**
* OpenID Server Request
*
* @see Auth_OpenID_Server
*
* 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
*/
 
/**
* Imports
*/
require_once "Auth/OpenID.php";
 
/**
* Object that holds the state of a request to the OpenID server
*
* With accessor functions to get at the internal request data.
*
* @see Auth_OpenID_Server
* @package OpenID
*/
class Auth_OpenID_ServerRequest {
function Auth_OpenID_ServerRequest()
{
$this->mode = null;
}
}
 
?>
/trunk/composants/openid/Auth/OpenID/PostgreSQLStore.php
New file
0,0 → 1,136
<?php
 
/**
* A PostgreSQL store.
*
* @package OpenID
*/
 
/**
* Require the base class file.
*/
require_once "Auth/OpenID/SQLStore.php";
 
/**
* An SQL store that uses PostgreSQL as its backend.
*
* @package OpenID
*/
class Auth_OpenID_PostgreSQLStore extends Auth_OpenID_SQLStore {
/**
* @access private
*/
function setSQL()
{
$this->sql['nonce_table'] =
"CREATE TABLE %s (nonce CHAR(8) UNIQUE PRIMARY KEY, ".
"expires INTEGER)";
 
$this->sql['assoc_table'] =
"CREATE TABLE %s (server_url VARCHAR(2047), handle VARCHAR(255), ".
"secret BYTEA, issued INTEGER, lifetime INTEGER, ".
"assoc_type VARCHAR(64), PRIMARY KEY (server_url, handle), ".
"CONSTRAINT secret_length_constraint CHECK ".
"(LENGTH(secret) <= 128))";
 
$this->sql['settings_table'] =
"CREATE TABLE %s (setting VARCHAR(128) UNIQUE PRIMARY KEY, ".
"value BYTEA, ".
"CONSTRAINT value_length_constraint CHECK (LENGTH(value) <= 20))";
 
$this->sql['create_auth'] =
"INSERT INTO %s VALUES ('auth_key', '!')";
 
$this->sql['get_auth'] =
"SELECT value FROM %s WHERE setting = 'auth_key'";
 
$this->sql['set_assoc'] =
array(
'insert_assoc' => "INSERT INTO %s (server_url, handle, ".
"secret, issued, lifetime, assoc_type) VALUES ".
"(?, ?, '!', ?, ?, ?)",
'update_assoc' => "UPDATE %s SET secret = '!', issued = ?, ".
"lifetime = ?, assoc_type = ? WHERE server_url = ? AND ".
"handle = ?"
);
 
$this->sql['get_assocs'] =
"SELECT handle, secret, issued, lifetime, assoc_type FROM %s ".
"WHERE server_url = ?";
 
$this->sql['get_assoc'] =
"SELECT handle, secret, issued, lifetime, assoc_type FROM %s ".
"WHERE server_url = ? AND handle = ?";
 
$this->sql['remove_assoc'] =
"DELETE FROM %s WHERE server_url = ? AND handle = ?";
 
$this->sql['add_nonce'] =
array(
'insert_nonce' => "INSERT INTO %s (nonce, expires) VALUES ".
"(?, ?)",
'update_nonce' => "UPDATE %s SET expires = ? WHERE nonce = ?"
);
 
$this->sql['get_nonce'] =
"SELECT * FROM %s WHERE nonce = ?";
 
$this->sql['remove_nonce'] =
"DELETE FROM %s WHERE nonce = ?";
}
 
/**
* @access private
*/
function _set_assoc($server_url, $handle, $secret, $issued, $lifetime,
$assoc_type)
{
$result = $this->_get_assoc($server_url, $handle);
if ($result) {
// Update the table since this associations already exists.
$this->connection->query($this->sql['set_assoc']['update_assoc'],
array($secret, $issued, $lifetime,
$assoc_type, $server_url, $handle));
} else {
// Insert a new record because this association wasn't
// found.
$this->connection->query($this->sql['set_assoc']['insert_assoc'],
array($server_url, $handle, $secret,
$issued, $lifetime, $assoc_type));
}
}
 
/**
* @access private
*/
function _add_nonce($nonce, $expires)
{
if ($this->_get_nonce($nonce)) {
return $this->resultToBool($this->connection->query(
$this->sql['add_nonce']['update_nonce'],
array($expires, $nonce)));
} else {
return $this->resultToBool($this->connection->query(
$this->sql['add_nonce']['insert_nonce'],
array($nonce, $expires)));
}
}
 
/**
* @access private
*/
function blobEncode($blob)
{
return $this->_octify($blob);
}
 
/**
* @access private
*/
function blobDecode($blob)
{
return $this->_unoctify($blob);
}
}
 
?>
/trunk/composants/openid/Auth/OpenID/MySQLStore.php
New file
0,0 → 1,78
<?php
 
/**
* A MySQL store.
*
* @package OpenID
*/
 
/**
* Require the base class file.
*/
require_once "Auth/OpenID/SQLStore.php";
 
/**
* An SQL store that uses MySQL as its backend.
*
* @package OpenID
*/
class Auth_OpenID_MySQLStore extends Auth_OpenID_SQLStore {
/**
* @access private
*/
function setSQL()
{
$this->sql['nonce_table'] =
"CREATE TABLE %s (nonce CHAR(8) UNIQUE PRIMARY KEY, ".
"expires INTEGER) TYPE=InnoDB";
 
$this->sql['assoc_table'] =
"CREATE TABLE %s (server_url BLOB, handle VARCHAR(255), ".
"secret BLOB, issued INTEGER, lifetime INTEGER, ".
"assoc_type VARCHAR(64), PRIMARY KEY (server_url(255), handle)) ".
"TYPE=InnoDB";
 
$this->sql['settings_table'] =
"CREATE TABLE %s (setting VARCHAR(128) UNIQUE PRIMARY KEY, ".
"value BLOB) TYPE=InnoDB";
 
$this->sql['create_auth'] =
"INSERT INTO %s VALUES ('auth_key', !)";
 
$this->sql['get_auth'] =
"SELECT value FROM %s WHERE setting = 'auth_key'";
 
$this->sql['set_assoc'] =
"REPLACE INTO %s VALUES (?, ?, !, ?, ?, ?)";
 
$this->sql['get_assocs'] =
"SELECT handle, secret, issued, lifetime, assoc_type FROM %s ".
"WHERE server_url = ?";
 
$this->sql['get_assoc'] =
"SELECT handle, secret, issued, lifetime, assoc_type FROM %s ".
"WHERE server_url = ? AND handle = ?";
 
$this->sql['remove_assoc'] =
"DELETE FROM %s WHERE server_url = ? AND handle = ?";
 
$this->sql['add_nonce'] =
"REPLACE INTO %s (nonce, expires) VALUES (?, ?)";
 
$this->sql['get_nonce'] =
"SELECT * FROM %s WHERE nonce = ?";
 
$this->sql['remove_nonce'] =
"DELETE FROM %s WHERE nonce = ?";
}
 
/**
* @access private
*/
function blobEncode($blob)
{
return "0x" . bin2hex($blob);
}
}
 
?>
/trunk/composants/openid/Auth/OpenID/DatabaseConnection.php
New file
0,0 → 1,131
<?php
 
/**
* The Auth_OpenID_DatabaseConnection class, which is used to emulate
* a PEAR database connection.
*
* @package OpenID
* @author JanRain, Inc. <openid@janrain.com>
* @copyright 2005 Janrain, Inc.
* @license http://www.gnu.org/copyleft/lesser.html LGPL
*/
 
/**
* An empty base class intended to emulate PEAR connection
* functionality in applications that supply their own database
* abstraction mechanisms. See {@link Auth_OpenID_SQLStore} for more
* information. You should subclass this class if you need to create
* an SQL store that needs to access its database using an
* application's database abstraction layer instead of a PEAR database
* connection. Any subclass of Auth_OpenID_DatabaseConnection MUST
* adhere to the interface specified here.
*
* @package OpenID
*/
class Auth_OpenID_DatabaseConnection {
/**
* Sets auto-commit mode on this database connection.
*
* @param bool $mode True if auto-commit is to be used; false if
* not.
*/
function autoCommit($mode)
{
}
 
/**
* Run an SQL query with the specified parameters, if any.
*
* @param string $sql An SQL string with placeholders. The
* placeholders are assumed to be specific to the database engine
* for this connection.
*
* @param array $params An array of parameters to insert into the
* SQL string using this connection's escaping mechanism.
*
* @return mixed $result The result of calling this connection's
* internal query function. The type of result depends on the
* underlying database engine. This method is usually used when
* the result of a query is not important, like a DDL query.
*/
function query($sql, $params = array())
{
}
 
/**
* Starts a transaction on this connection, if supported.
*/
function begin()
{
}
 
/**
* Commits a transaction on this connection, if supported.
*/
function commit()
{
}
 
/**
* Performs a rollback on this connection, if supported.
*/
function rollback()
{
}
 
/**
* Run an SQL query and return the first column of the first row
* of the result set, if any.
*
* @param string $sql An SQL string with placeholders. The
* placeholders are assumed to be specific to the database engine
* for this connection.
*
* @param array $params An array of parameters to insert into the
* SQL string using this connection's escaping mechanism.
*
* @return mixed $result The value of the first column of the
* first row of the result set. False if no such result was
* found.
*/
function getOne($sql, $params = array())
{
}
 
/**
* Run an SQL query and return the first row of the result set, if
* any.
*
* @param string $sql An SQL string with placeholders. The
* placeholders are assumed to be specific to the database engine
* for this connection.
*
* @param array $params An array of parameters to insert into the
* SQL string using this connection's escaping mechanism.
*
* @return array $result The first row of the result set, if any,
* keyed on column name. False if no such result was found.
*/
function getRow($sql, $params = array())
{
}
 
/**
* Run an SQL query with the specified parameters, if any.
*
* @param string $sql An SQL string with placeholders. The
* placeholders are assumed to be specific to the database engine
* for this connection.
*
* @param array $params An array of parameters to insert into the
* SQL string using this connection's escaping mechanism.
*
* @return array $result An array of arrays representing the
* result of the query; each array is keyed on column name.
*/
function getAll($sql, $params = array())
{
}
}
 
?>
/trunk/composants/openid/Auth/OpenID/TrustRoot.php
New file
0,0 → 1,243
<?php
/**
* Functions for dealing with OpenID trust roots
*
* 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
*/
 
/**
* A regular expression that matches a domain ending in a top-level domains.
* Used in checking trust roots for sanity.
*
* @access private
*/
define('Auth_OpenID___TLDs',
'/\.(com|edu|gov|int|mil|net|org|biz|info|name|museum|coop|aero|ac|' .
'ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|az|ba|bb|bd|be|bf|bg|' .
'bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|' .
'cm|cn|co|cr|cu|cv|cx|cy|cz|de|dj|dk|dm|do|dz|ec|ee|eg|eh|er|es|et|' .
'fi|fj|fk|fm|fo|fr|ga|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|' .
'gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|' .
'ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|' .
'ma|mc|md|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|' .
'nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|' .
'ps|pt|pw|py|qa|re|ro|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|' .
'so|sr|st|sv|sy|sz|tc|td|tf|tg|th|tj|tk|tm|tn|to|tp|tr|tt|tv|tw|tz|' .
'ua|ug|uk|um|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zw)$/');
 
/**
* A wrapper for trust-root related functions
*/
class Auth_OpenID_TrustRoot {
/**
* Parse a URL into its trust_root parts.
*
* @static
*
* @access private
*
* @param string $trust_root The url to parse
*
* @return mixed $parsed Either an associative array of trust root
* parts or false if parsing failed.
*/
function _parse($trust_root)
{
$parts = @parse_url($trust_root);
if ($parts === false) {
return false;
}
$required_parts = array('scheme', 'host');
$forbidden_parts = array('user', 'pass', 'fragment');
$keys = array_keys($parts);
if (array_intersect($keys, $required_parts) != $required_parts) {
return false;
}
 
if (array_intersect($keys, $forbidden_parts) != array()) {
return false;
}
 
// Return false if the original trust root value has more than
// one port specification.
if (preg_match("/:\/\/[^:]+(:\d+){2,}(\/|$)/", $trust_root)) {
return false;
}
 
$scheme = strtolower($parts['scheme']);
$allowed_schemes = array('http', 'https');
if (!in_array($scheme, $allowed_schemes)) {
return false;
}
$parts['scheme'] = $scheme;
 
$host = strtolower($parts['host']);
$hostparts = explode('*', $host);
switch (count($hostparts)) {
case 1:
$parts['wildcard'] = false;
break;
case 2:
if ($hostparts[0] ||
($hostparts[1] && substr($hostparts[1], 0, 1) != '.')) {
return false;
}
$host = $hostparts[1];
$parts['wildcard'] = true;
break;
default:
return false;
}
if (strpos($host, ':') !== false) {
return false;
}
 
$parts['host'] = $host;
 
if (isset($parts['path'])) {
$path = strtolower($parts['path']);
if (substr($path, -1) != '/') {
$path .= '/';
}
} else {
$path = '/';
}
$parts['path'] = $path;
if (!isset($parts['port'])) {
$parts['port'] = false;
}
return $parts;
}
 
/**
* Is this trust root sane?
*
* A trust root is sane if it is syntactically valid and it has a
* reasonable domain name. Specifically, the domain name must be
* more than one level below a standard TLD or more than two
* levels below a two-letter tld.
*
* For example, '*.com' is not a sane trust root, but '*.foo.com'
* is. '*.co.uk' is not sane, but '*.bbc.co.uk' is.
*
* This check is not always correct, but it attempts to err on the
* side of marking sane trust roots insane instead of marking
* insane trust roots sane. For example, 'kink.fm' is marked as
* insane even though it "should" (for some meaning of should) be
* marked sane.
*
* This function should be used when creating OpenID servers to
* alert the users of the server when a consumer attempts to get
* the user to accept a suspicious trust root.
*
* @static
* @param string $trust_root The trust root to check
* @return bool $sanity Whether the trust root looks OK
*/
function isSane($trust_root)
{
$parts = Auth_OpenID_TrustRoot::_parse($trust_root);
if ($parts === false) {
return false;
}
 
// Localhost is a special case
if ($parts['host'] == 'localhost') {
return true;
}
 
// Get the top-level domain of the host. If it is not a valid TLD,
// it's not sane.
preg_match(Auth_OpenID___TLDs, $parts['host'], $matches);
if (!$matches) {
return false;
}
$tld = $matches[1];
 
// Require at least two levels of specificity for non-country
// tlds and three levels for country tlds.
$elements = explode('.', $parts['host']);
$n = count($elements);
if ($parts['wildcard']) {
$n -= 1;
}
if (strlen($tld) == 2) {
$n -= 1;
}
if ($n <= 1) {
return false;
}
return true;
}
 
/**
* Does this URL match the given trust root?
*
* Return whether the URL falls under the given trust root. This
* does not check whether the trust root is sane. If the URL or
* trust root do not parse, this function will return false.
*
* @param string $trust_root The trust root to match against
*
* @param string $url The URL to check
*
* @return bool $matches Whether the URL matches against the
* trust root
*/
function match($trust_root, $url)
{
$trust_root_parsed = Auth_OpenID_TrustRoot::_parse($trust_root);
$url_parsed = Auth_OpenID_TrustRoot::_parse($url);
if (!$trust_root_parsed || !$url_parsed) {
return false;
}
 
// Check hosts matching
if ($url_parsed['wildcard']) {
return false;
}
if ($trust_root_parsed['wildcard']) {
$host_tail = $trust_root_parsed['host'];
$host = $url_parsed['host'];
if ($host_tail &&
substr($host, -(strlen($host_tail))) != $host_tail &&
substr($host_tail, 1) != $host) {
return false;
}
} else {
if ($trust_root_parsed['host'] != $url_parsed['host']) {
return false;
}
}
 
// Check path and query matching
$base_path = $trust_root_parsed['path'];
$path = $url_parsed['path'];
if (!isset($trust_root_parsed['query'])) {
if (substr($path, 0, strlen($base_path)) != $base_path) {
return false;
}
} else {
$base_query = $trust_root_parsed['query'];
$query = @$url_parsed['query'];
$qplus = substr($query, 0, strlen($base_query) + 1);
$bqplus = $base_query . '&';
if ($base_path != $path ||
($base_query != $query && $qplus != $bqplus)) {
return false;
}
}
 
// The port and scheme need to match exactly
return ($trust_root_parsed['scheme'] == $url_parsed['scheme'] &&
$url_parsed['port'] === $trust_root_parsed['port']);
}
}
?>
/trunk/composants/openid/Auth/OpenID/HMACSHA1.php
New file
0,0 → 1,72
<?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 Janrain, Inc.
* @license http://www.gnu.org/copyleft/lesser.html LGPL
*/
 
/**
* SHA1_BLOCKSIZE is this module's SHA1 blocksize used by the fallback
* implementation.
*/
define('Auth_OpenID_SHA1_BLOCKSIZE', 64);
 
if (!function_exists('sha1')) {
/**
* Return a raw SHA1 hash of the given string
*
* XXX: include the SHA1 code from Dan Libby's OpenID library
*/
function Auth_OpenID_SHA1($text)
{
trigger_error('No SHA1 function found', E_USER_ERROR);
}
} else {
/**
* @ignore
*/
function Auth_OpenID_SHA1($text)
{
$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;
}
}
 
/**
* 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 (strlen($key) > Auth_OpenID_SHA1_BLOCKSIZE) {
$key = Auth_OpenID_SHA1($key, true);
}
 
$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;
}
 
?>
/trunk/composants/openid/Auth/OpenID/DiffieHellman.php
New file
0,0 → 1,181
<?php
 
/**
* The OpenID library's Diffie-Hellman implementation.
*
* 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 Janrain, Inc.
* @license http://www.gnu.org/copyleft/lesser.html LGPL
*/
 
require_once 'Auth/OpenID/BigMath.php';
require_once 'Auth/OpenID/HMACSHA1.php';
 
function Auth_OpenID_getDefaultMod()
{
return '155172898181473697471232257763715539915724801'.
'966915404479707795314057629378541917580651227423'.
'698188993727816152646631438561595825688188889951'.
'272158842675419950341258706556549803580104870537'.
'681476726513255747040765857479291291572334510643'.
'245094715007229621094194349783925984760375594985'.
'848253359305585439638443';
}
 
function Auth_OpenID_getDefaultGen()
{
return '2';
}
 
/**
* The Diffie-Hellman key exchange class. This class relies on
* {@link Auth_OpenID_MathLibrary} to perform large number operations.
*
* @access private
* @package OpenID
*/
class Auth_OpenID_DiffieHellman {
 
var $mod;
var $gen;
var $private;
var $lib = null;
 
function Auth_OpenID_DiffieHellman($mod = null, $gen = null,
$private = null, $lib = null)
{
if ($lib === null) {
$this->lib =& Auth_OpenID_getMathLib();
} else {
$this->lib =& $lib;
}
 
if ($mod === null) {
$this->mod = $this->lib->init(Auth_OpenID_getDefaultMod());
} else {
$this->mod = $mod;
}
 
if ($gen === null) {
$this->gen = $this->lib->init(Auth_OpenID_getDefaultGen());
} else {
$this->gen = $gen;
}
 
if ($private === null) {
$r = $this->lib->rand($this->mod);
$this->private = $this->lib->add($r, 1);
} else {
$this->private = $private;
}
 
$this->public = $this->lib->powmod($this->gen, $this->private,
$this->mod);
}
 
function getSharedSecret($composite)
{
return $this->lib->powmod($composite, $this->private, $this->mod);
}
 
function getPublicKey()
{
return $this->public;
}
 
/**
* Generate the arguments for an OpenID Diffie-Hellman association
* request
*/
function getAssocArgs()
{
$cpub = $this->lib->longToBase64($this->getPublicKey());
$args = array(
'openid.dh_consumer_public' => $cpub,
'openid.session_type' => 'DH-SHA1'
);
 
if ($this->lib->cmp($this->mod, Auth_OpenID_getDefaultMod()) ||
$this->lib->cmp($this->gen, Auth_OpenID_getDefaultGen())) {
$args['openid.dh_modulus'] = $this->lib->longToBase64($this->mod);
$args['openid.dh_gen'] = $this->lib->longToBase64($this->gen);
}
 
return $args;
}
 
function usingDefaultValues()
{
return ($this->mod == Auth_OpenID_getDefaultMod() &&
$this->gen == Auth_OpenID_getDefaultGen());
}
 
/**
* Perform the server side of the OpenID Diffie-Hellman association
*/
function serverAssociate($consumer_args, $assoc_secret)
{
$lib =& Auth_OpenID_getMathLib();
 
if (isset($consumer_args['openid.dh_modulus'])) {
$mod = $lib->base64ToLong($consumer_args['openid.dh_modulus']);
} else {
$mod = null;
}
 
if (isset($consumer_args['openid.dh_gen'])) {
$gen = $lib->base64ToLong($consumer_args['openid.dh_gen']);
} else {
$gen = null;
}
$cpub64 = @$consumer_args['openid.dh_consumer_public'];
if (!isset($cpub64)) {
return false;
}
 
$dh = new Auth_OpenID_DiffieHellman($mod, $gen);
$cpub = $lib->base64ToLong($cpub64);
$mac_key = $dh->xorSecret($cpub, $assoc_secret);
$enc_mac_key = base64_encode($mac_key);
$spub64 = $lib->longToBase64($dh->getPublicKey());
 
$server_args = array(
'session_type' => 'DH-SHA1',
'dh_server_public' => $spub64,
'enc_mac_key' => $enc_mac_key
);
 
return $server_args;
}
 
function consumerFinish($reply)
{
$spub = $this->lib->base64ToLong($reply['dh_server_public']);
if ($this->lib->cmp($spub, 0) <= 0) {
return false;
}
$enc_mac_key = base64_decode($reply['enc_mac_key']);
return $this->xorSecret($spub, $enc_mac_key);
}
 
function xorSecret($composite, $secret)
{
$dh_shared = $this->getSharedSecret($composite);
$dh_shared_str = $this->lib->longToBinary($dh_shared);
$sha1_dh_shared = Auth_OpenID_SHA1($dh_shared_str);
 
$xsecret = "";
for ($i = 0; $i < strlen($secret); $i++) {
$xsecret .= chr(ord($secret[$i]) ^ ord($sha1_dh_shared[$i]));
}
 
return $xsecret;
}
}
/trunk/composants/openid/Auth/OpenID.php
New file
0,0 → 1,412
<?php
 
/**
* This is the PHP OpenID library by JanRain, Inc.
*
* This module contains core utility functionality used by the
* library. See Consumer.php and Server.php for the consumer and
* server 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 Janrain, Inc.
* @license http://www.gnu.org/copyleft/lesser.html LGPL
*/
 
/**
* Require the fetcher code.
*/
require_once "Services/Yadis/PlainHTTPFetcher.php";
require_once "Services/Yadis/ParanoidHTTPFetcher.php";
require_once "Auth/OpenID/BigMath.php";
 
/**
* Status code returned by the server when the only option is to show
* an error page, since we do not have enough information to redirect
* back to the consumer. The associated value is an error message that
* should be displayed on an HTML error page.
*
* @see Auth_OpenID_Server
*/
define('Auth_OpenID_LOCAL_ERROR', 'local_error');
 
/**
* Status code returned when there is an error to return in key-value
* form to the consumer. The caller should return a 400 Bad Request
* response with content-type text/plain and the value as the body.
*
* @see Auth_OpenID_Server
*/
define('Auth_OpenID_REMOTE_ERROR', 'remote_error');
 
/**
* Status code returned when there is a key-value form OK response to
* the consumer. The value associated with this code is the
* response. The caller should return a 200 OK response with
* content-type text/plain and the value as the body.
*
* @see Auth_OpenID_Server
*/
define('Auth_OpenID_REMOTE_OK', 'remote_ok');
 
/**
* Status code returned when there is a redirect back to the
* consumer. The value is the URL to redirect back to. The caller
* should return a 302 Found redirect with a Location: header
* containing the URL.
*
* @see Auth_OpenID_Server
*/
define('Auth_OpenID_REDIRECT', 'redirect');
 
/**
* Status code returned when the caller needs to authenticate the
* user. The associated value is a {@link Auth_OpenID_ServerRequest}
* object that can be used to complete the authentication. If the user
* has taken some authentication action, use the retry() method of the
* {@link Auth_OpenID_ServerRequest} object to complete the request.
*
* @see Auth_OpenID_Server
*/
define('Auth_OpenID_DO_AUTH', 'do_auth');
 
/**
* Status code returned when there were no OpenID arguments
* passed. This code indicates that the caller should return a 200 OK
* response and display an HTML page that says that this is an OpenID
* server endpoint.
*
* @see Auth_OpenID_Server
*/
define('Auth_OpenID_DO_ABOUT', 'do_about');
 
/**
* Defines for regexes and format checking.
*/
define('Auth_OpenID_letters',
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
 
define('Auth_OpenID_digits',
"0123456789");
 
define('Auth_OpenID_punct',
"!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~");
 
if (Auth_OpenID_getMathLib() === null) {
define('Auth_OpenID_NO_MATH_SUPPORT', true);
}
 
/**
* The OpenID utility function class.
*
* @package OpenID
* @access private
*/
class Auth_OpenID {
 
/**
* These namespaces are automatically fixed in query arguments by
* Auth_OpenID::fixArgs.
*/
function getOpenIDNamespaces()
{
return array('openid',
'sreg');
}
 
/**
* Rename query arguments back to 'openid.' from 'openid_'
*
* @access private
* @param array $args An associative array of URL query arguments
*/
function fixArgs($args)
{
foreach (array_keys($args) as $key) {
$fixed = $key;
if (preg_match('/^openid/', $key)) {
foreach (Auth_OpenID::getOpenIDNamespaces() as $ns) {
if (preg_match('/'.$ns.'_/', $key)) {
$fixed = preg_replace('/'.$ns.'_/', $ns.'.', $fixed);
}
}
 
if ($fixed != $key) {
$val = $args[$key];
unset($args[$key]);
$args[$fixed] = $val;
}
}
}
 
return $args;
}
 
/**
* Create dir_name as a directory if it does not exist. If it
* exists, make sure that it is, in fact, a directory. Returns
* true if the operation succeeded; false if not.
*
* @access private
*/
function ensureDir($dir_name)
{
if (is_dir($dir_name) || @mkdir($dir_name)) {
return true;
} else {
if (Auth_OpenID::ensureDir(dirname($dir_name))) {
return is_dir($dir_name) || @mkdir($dir_name);
} else {
return false;
}
}
}
 
/**
* Convenience function for getting array values.
*
* @access private
*/
function arrayGet($arr, $key, $fallback = null)
{
if (is_array($arr)) {
if (array_key_exists($key, $arr)) {
return $arr[$key];
} else {
return $fallback;
}
} else {
trigger_error("Auth_OpenID::arrayGet expected " .
"array as first parameter", E_USER_WARNING);
return false;
}
}
 
/**
* Implements the PHP 5 'http_build_query' functionality.
*
* @access private
* @param array $data Either an array key/value pairs or an array
* of arrays, each of which holding two values: a key and a value,
* sequentially.
* @return string $result The result of url-encoding the key/value
* pairs from $data into a URL query string
* (e.g. "username=bob&id=56").
*/
function httpBuildQuery($data)
{
$pairs = array();
foreach ($data as $key => $value) {
if (is_array($value)) {
$pairs[] = urlencode($value[0])."=".urlencode($value[1]);
} else {
$pairs[] = urlencode($key)."=".urlencode($value);
}
}
return implode("&", $pairs);
}
 
/**
* "Appends" query arguments onto a URL. The URL may or may not
* already have arguments (following a question mark).
*
* @param string $url A URL, which may or may not already have
* arguments.
* @param array $args Either an array key/value pairs or an array of
* arrays, each of which holding two values: a key and a value,
* sequentially. If $args is an ordinary key/value array, the
* parameters will be added to the URL in sorted alphabetical order;
* if $args is an array of arrays, their order will be preserved.
* @return string $url The original URL with the new parameters added.
*
*/
function appendArgs($url, $args)
{
if (count($args) == 0) {
return $url;
}
 
// Non-empty array; if it is an array of arrays, use
// multisort; otherwise use sort.
if (array_key_exists(0, $args) &&
is_array($args[0])) {
// Do nothing here.
} else {
$keys = array_keys($args);
sort($keys);
$new_args = array();
foreach ($keys as $key) {
$new_args[] = array($key, $args[$key]);
}
$args = $new_args;
}
 
$sep = '?';
if (strpos($url, '?') !== false) {
$sep = '&';
}
 
return $url . $sep . Auth_OpenID::httpBuildQuery($args);
}
 
/**
* Turn a string into an ASCII string.
*
* Replace non-ascii characters with a %-encoded, UTF-8
* encoding. This function will fail if the input is a string and
* there are non-7-bit-safe characters. It is assumed that the
* caller will have already translated the input into a Unicode
* character sequence, according to the encoding of the HTTP POST
* or GET.
*
* Do not escape anything that is already 7-bit safe, so we do the
* minimal transform on the identity URL
*
* @access private
*/
function quoteMinimal($s)
{
$res = array();
for ($i = 0; $i < strlen($s); $i++) {
$c = $s[$i];
if ($c >= "\x80") {
for ($j = 0; $j < count(utf8_encode($c)); $j++) {
array_push($res, sprintf("%02X", ord($c[$j])));
}
} else {
array_push($res, $c);
}
}
return implode('', $res);
}
 
/**
* Implements python's urlunparse, which is not available in PHP.
* Given the specified components of a URL, this function rebuilds
* and returns the URL.
*
* @access private
* @param string $scheme The scheme (e.g. 'http'). Defaults to 'http'.
* @param string $host The host. Required.
* @param string $port The port.
* @param string $path The path.
* @param string $query The query.
* @param string $fragment The fragment.
* @return string $url The URL resulting from assembling the
* specified components.
*/
function urlunparse($scheme, $host, $port = null, $path = '/',
$query = '', $fragment = '')
{
 
if (!$scheme) {
$scheme = 'http';
}
 
if (!$host) {
return false;
}
 
if (!$path) {
$path = '/';
}
 
$result = $scheme . "://" . $host;
 
if ($port) {
$result .= ":" . $port;
}
 
$result .= $path;
 
if ($query) {
$result .= "?" . $query;
}
 
if ($fragment) {
$result .= "#" . $fragment;
}
 
return $result;
}
 
/**
* Given a URL, this "normalizes" it by adding a trailing slash
* and / or a leading http:// scheme where necessary. Returns
* null if the original URL is malformed and cannot be normalized.
*
* @access private
* @param string $url The URL to be normalized.
* @return mixed $new_url The URL after normalization, or null if
* $url was malformed.
*/
function normalizeUrl($url)
{
if ($url === null) {
return null;
}
 
assert(is_string($url));
 
$old_url = $url;
$url = trim($url);
 
if (strpos($url, "://") === false) {
$url = "http://" . $url;
}
 
$parsed = @parse_url($url);
 
if ($parsed === false) {
return null;
}
 
$defaults = array(
'scheme' => '',
'host' => '',
'path' => '',
'query' => '',
'fragment' => '',
'port' => ''
);
 
$parsed = array_merge($defaults, $parsed);
 
if (($parsed['scheme'] == '') ||
($parsed['host'] == '')) {
if ($parsed['path'] == '' &&
$parsed['query'] == '' &&
$parsed['fragment'] == '') {
return null;
}
 
$url = 'http://' + $url;
$parsed = parse_url($url);
 
$parsed = array_merge($defaults, $parsed);
}
 
$tail = array_map(array('Auth_OpenID', 'quoteMinimal'),
array($parsed['path'],
$parsed['query'],
$parsed['fragment']));
if ($tail[0] == '') {
$tail[0] = '/';
}
 
$url = Auth_OpenID::urlunparse($parsed['scheme'], $parsed['host'],
$parsed['port'], $tail[0], $tail[1],
$tail[2]);
 
assert(is_string($url));
 
return $url;
}
}
 
?>
/trunk/composants/openid/Services/Yadis/ParseHTML.php
New file
0,0 → 1,258
<?php
 
/**
* This is the HTML pseudo-parser for the Yadis library.
*
* PHP versions 4 and 5
*
* LICENSE: See the COPYING file included in this distribution.
*
* @package Yadis
* @author JanRain, Inc. <openid@janrain.com>
* @copyright 2005 Janrain, Inc.
* @license http://www.gnu.org/copyleft/lesser.html LGPL
*/
 
/**
* This class is responsible for scanning an HTML string to find META
* tags and their attributes. This is used by the Yadis discovery
* process. This class must be instantiated to be used.
*
* @package Yadis
*/
class Services_Yadis_ParseHTML {
 
/**
* @access private
*/
var $_re_flags = "si";
 
/**
* @access private
*/
var $_removed_re =
"<!--.*?-->|<!\[CDATA\[.*?\]\]>|<script\b(?!:)[^>]*>.*?<\/script>";
 
/**
* @access private
*/
var $_tag_expr = "<%s%s(?:\s.*?)?%s>";
 
/**
* @access private
*/
var $_attr_find = '\b([-\w]+)=(".*?"|\'.*?\'|.+?)[\s>]';
 
function Services_Yadis_ParseHTML()
{
$this->_attr_find = sprintf("/%s/%s",
$this->_attr_find,
$this->_re_flags);
 
$this->_removed_re = sprintf("/%s/%s",
$this->_removed_re,
$this->_re_flags);
 
$this->_entity_replacements = array(
'amp' => '&',
'lt' => '<',
'gt' => '>',
'quot' => '"'
);
 
$this->_ent_replace =
sprintf("&(%s);", implode("|",
$this->_entity_replacements));
}
 
/**
* Replace HTML entities (amp, lt, gt, and quot) as well as
* numeric entities (e.g. #x9f;) with their actual values and
* return the new string.
*
* @access private
* @param string $str The string in which to look for entities
* @return string $new_str The new string entities decoded
*/
function replaceEntities($str)
{
foreach ($this->_entity_replacements as $old => $new) {
$str = preg_replace(sprintf("/&%s;/", $old), $new, $str);
}
 
// Replace numeric entities because html_entity_decode doesn't
// do it for us.
$str = preg_replace('~&#x([0-9a-f]+);~ei', 'chr(hexdec("\\1"))', $str);
$str = preg_replace('~&#([0-9]+);~e', 'chr(\\1)', $str);
 
return $str;
}
 
/**
* Strip single and double quotes off of a string, if they are
* present.
*
* @access private
* @param string $str The original string
* @return string $new_str The new string with leading and
* trailing quotes removed
*/
function removeQuotes($str)
{
$matches = array();
$double = '/^"(.*)"$/';
$single = "/^\'(.*)\'$/";
 
if (preg_match($double, $str, $matches)) {
return $matches[1];
} else if (preg_match($single, $str, $matches)) {
return $matches[1];
} else {
return $str;
}
}
 
/**
* Create a regular expression that will match an opening
* or closing tag from a set of names.
*
* @access private
* @param mixed $tag_names Tag names to match
* @param mixed $close false/0 = no, true/1 = yes, other = maybe
* @param mixed $self_close false/0 = no, true/1 = yes, other = maybe
* @return string $regex A regular expression string to be used
* in, say, preg_match.
*/
function tagPattern($tag_names, $close, $self_close)
{
if (is_array($tag_names)) {
$tag_names = '(?:'.implode('|',$tag_names).')';
}
if ($close) {
$close = '\/' . (($close == 1)? '' : '?');
} else {
$close = '';
}
if ($self_close) {
$self_close = '(?:\/\s*)' . (($self_close == 1)? '' : '?');
} else {
$self_close = '';
}
$expr = sprintf($this->_tag_expr, $close, $tag_names, $self_close);
 
return sprintf("/%s/%s", $expr, $this->_re_flags);
}
 
/**
* Given an HTML document string, this finds all the META tags in
* the document, provided they are found in the
* <HTML><HEAD>...</HEAD> section of the document. The <HTML> tag
* may be missing.
*
* @access private
* @param string $html_string An HTMl document string
* @return array $tag_list Array of tags; each tag is an array of
* attribute -> value.
*/
function getMetaTags($html_string)
{
$html_string = preg_replace($this->_removed_re,
"",
$html_string);
 
$key_tags = array($this->tagPattern('html', false, false),
$this->tagPattern('head', false, false),
$this->tagPattern('head', true, false),
$this->tagPattern('html', true, false),
$this->tagPattern(array(
'body', 'frameset', 'frame', 'p', 'div',
'table','span','a'), 'maybe', 'maybe'));
$key_tags_pos = array();
foreach ($key_tags as $pat) {
$matches = array();
preg_match($pat, $html_string, $matches, PREG_OFFSET_CAPTURE);
if($matches) {
$key_tags_pos[] = $matches[0][1];
} else {
$key_tags_pos[] = null;
}
}
// no opening head tag
if (is_null($key_tags_pos[1])) {
return array();
}
// the effective </head> is the min of the following
if (is_null($key_tags_pos[2])) {
$key_tags_pos[2] = strlen($html_string);
}
foreach (array($key_tags_pos[3], $key_tags_pos[4]) as $pos) {
if (!is_null($pos) && $pos < $key_tags_pos[2]) {
$key_tags_pos[2] = $pos;
}
}
// closing head tag comes before opening head tag
if ($key_tags_pos[1] > $key_tags_pos[2]) {
return array();
}
// if there is an opening html tag, make sure the opening head tag
// comes after it
if (!is_null($key_tags_pos[0]) && $key_tags_pos[1] < $key_tags_pos[0]) {
return array();
}
$html_string = substr($html_string, $key_tags_pos[1], ($key_tags_pos[2]-$key_tags_pos[1]));
 
$link_data = array();
$link_matches = array();
if (!preg_match_all($this->tagPattern('meta', false, 'maybe'),
$html_string, $link_matches)) {
return array();
}
 
foreach ($link_matches[0] as $link) {
$attr_matches = array();
preg_match_all($this->_attr_find, $link, $attr_matches);
$link_attrs = array();
foreach ($attr_matches[0] as $index => $full_match) {
$name = $attr_matches[1][$index];
$value = $this->replaceEntities(
$this->removeQuotes($attr_matches[2][$index]));
 
$link_attrs[strtolower($name)] = $value;
}
$link_data[] = $link_attrs;
}
 
return $link_data;
}
 
/**
* Looks for a META tag with an "http-equiv" attribute whose value
* is one of ("x-xrds-location", "x-yadis-location"), ignoring
* case. If such a META tag is found, its "content" attribute
* value is returned.
*
* @param string $html_string An HTML document in string format
* @return mixed $content The "content" attribute value of the
* META tag, if found, or null if no such tag was found.
*/
function getHTTPEquiv($html_string)
{
$meta_tags = $this->getMetaTags($html_string);
 
if ($meta_tags) {
foreach ($meta_tags as $tag) {
if (array_key_exists('http-equiv', $tag) &&
(in_array(strtolower($tag['http-equiv']),
array('x-xrds-location', 'x-yadis-location'))) &&
array_key_exists('content', $tag)) {
return $tag['content'];
}
}
}
 
return null;
}
}
 
?>
/trunk/composants/openid/Services/Yadis/HTTPFetcher.php
New file
0,0 → 1,92
<?php
 
/**
* This module contains the HTTP fetcher interface
*
* PHP versions 4 and 5
*
* LICENSE: See the COPYING file included in this distribution.
*
* @package Yadis
* @author JanRain, Inc. <openid@janrain.com>
* @copyright 2005 Janrain, Inc.
* @license http://www.gnu.org/copyleft/lesser.html LGPL
*/
 
class Services_Yadis_HTTPResponse {
function Services_Yadis_HTTPResponse($final_url = null, $status = null,
$headers = null, $body = null)
{
$this->final_url = $final_url;
$this->status = $status;
$this->headers = $headers;
$this->body = $body;
}
}
 
/**
* This class is the interface for HTTP fetchers the Yadis library
* uses. This interface is only important if you need to write a new
* fetcher for some reason.
*
* @access private
* @package Yadis
*/
class Services_Yadis_HTTPFetcher {
 
var $timeout = 20; // timeout in seconds.
 
/**
* Return whether a URL should be allowed. Override this method to
* conform to your local policy.
*
* By default, will attempt to fetch any http or https URL.
*/
function allowedURL($url)
{
return $this->URLHasAllowedScheme($url);
}
 
/**
* Is this an http or https URL?
*
* @access private
*/
function URLHasAllowedScheme($url)
{
return (bool)preg_match('/^https?:\/\//i', $url);
}
 
/**
* @access private
*/
function _findRedirect($headers)
{
foreach ($headers as $line) {
if (strpos($line, "Location: ") === 0) {
$parts = explode(" ", $line, 2);
return $parts[1];
}
}
return null;
}
 
/**
* Fetches the specified URL using optional extra headers and
* returns the server's response.
*
* @param string $url The URL to be fetched.
* @param array $extra_headers An array of header strings
* (e.g. "Accept: text/html").
* @return mixed $result An array of ($code, $url, $headers,
* $body) if the URL could be fetched; null if the URL does not
* pass the URLHasAllowedScheme check or if the server's response
* is malformed.
*/
function get($url, $headers)
{
trigger_error("not implemented", E_USER_ERROR);
}
}
 
?>
/trunk/composants/openid/Services/Yadis/XML.php
New file
0,0 → 1,365
<?php
 
/**
* XML-parsing classes to wrap the domxml and DOM extensions for PHP 4
* and 5, respectively.
*
* @package Yadis
*/
 
/**
* The base class for wrappers for available PHP XML-parsing
* extensions. To work with this Yadis library, subclasses of this
* class MUST implement the API as defined in the remarks for this
* class. Subclasses of Services_Yadis_XMLParser are used to wrap
* particular PHP XML extensions such as 'domxml'. These are used
* internally by the library depending on the availability of
* supported PHP XML extensions.
*
* @package Yadis
*/
class Services_Yadis_XMLParser {
/**
* Initialize an instance of Services_Yadis_XMLParser with some
* XML and namespaces. This SHOULD NOT be overridden by
* subclasses.
*
* @param string $xml_string A string of XML to be parsed.
* @param array $namespace_map An array of ($ns_name => $ns_uri)
* to be registered with the XML parser. May be empty.
* @return boolean $result True if the initialization and
* namespace registration(s) succeeded; false otherwise.
*/
function init($xml_string, $namespace_map)
{
if (!$this->setXML($xml_string)) {
return false;
}
 
foreach ($namespace_map as $prefix => $uri) {
if (!$this->registerNamespace($prefix, $uri)) {
return false;
}
}
 
return true;
}
 
/**
* Register a namespace with the XML parser. This should be
* overridden by subclasses.
*
* @param string $prefix The namespace prefix to appear in XML tag
* names.
*
* @param string $uri The namespace URI to be used to identify the
* namespace in the XML.
*
* @return boolean $result True if the registration succeeded;
* false otherwise.
*/
function registerNamespace($prefix, $uri)
{
// Not implemented.
}
 
/**
* Set this parser object's XML payload. This should be
* overridden by subclasses.
*
* @param string $xml_string The XML string to pass to this
* object's XML parser.
*
* @return boolean $result True if the initialization succeeded;
* false otherwise.
*/
function setXML($xml_string)
{
// Not implemented.
}
 
/**
* Evaluate an XPath expression and return the resulting node
* list. This should be overridden by subclasses.
*
* @param string $xpath The XPath expression to be evaluated.
*
* @param mixed $node A node object resulting from a previous
* evalXPath call. This node, if specified, provides the context
* for the evaluation of this xpath expression.
*
* @return array $node_list An array of matching opaque node
* objects to be used with other methods of this parser class.
*/
function evalXPath($xpath, $node = null)
{
// Not implemented.
}
 
/**
* Return the textual content of a specified node.
*
* @param mixed $node A node object from a previous call to
* $this->evalXPath().
*
* @return string $content The content of this node.
*/
function content($node)
{
// Not implemented.
}
 
/**
* Return the attributes of a specified node.
*
* @param mixed $node A node object from a previous call to
* $this->evalXPath().
*
* @return array $attrs An array mapping attribute names to
* values.
*/
function attributes($node)
{
// Not implemented.
}
}
 
/**
* This concrete implementation of Services_Yadis_XMLParser implements
* the appropriate API for the 'domxml' extension which is typically
* packaged with PHP 4. This class will be used whenever the 'domxml'
* extension is detected. See the Services_Yadis_XMLParser class for
* details on this class's methods.
*
* @package Yadis
*/
class Services_Yadis_domxml extends Services_Yadis_XMLParser {
function Services_Yadis_domxml()
{
$this->xml = null;
$this->doc = null;
$this->xpath = null;
$this->errors = array();
}
 
function setXML($xml_string)
{
$this->xml = $xml_string;
$this->doc = @domxml_open_mem($xml_string, DOMXML_LOAD_PARSING,
$this->errors);
 
if (!$this->doc) {
return false;
}
 
$this->xpath = $this->doc->xpath_new_context();
 
return true;
}
 
function registerNamespace($prefix, $uri)
{
return xpath_register_ns($this->xpath, $prefix, $uri);
}
 
function &evalXPath($xpath, $node = null)
{
if ($node) {
$result = @$this->xpath->xpath_eval($xpath, $node);
} else {
$result = @$this->xpath->xpath_eval($xpath);
}
 
if (!$result->nodeset) {
$n = array();
return $n;
}
 
return $result->nodeset;
}
 
function content($node)
{
if ($node) {
return $node->get_content();
}
}
 
function attributes($node)
{
if ($node) {
$arr = $node->attributes();
$result = array();
 
if ($arr) {
foreach ($arr as $attrnode) {
$result[$attrnode->name] = $attrnode->value;
}
}
 
return $result;
}
}
}
 
/**
* This concrete implementation of Services_Yadis_XMLParser implements
* the appropriate API for the 'dom' extension which is typically
* packaged with PHP 5. This class will be used whenever the 'dom'
* extension is detected. See the Services_Yadis_XMLParser class for
* details on this class's methods.
*
* @package Yadis
*/
class Services_Yadis_dom extends Services_Yadis_XMLParser {
function Services_Yadis_dom()
{
$this->xml = null;
$this->doc = null;
$this->xpath = null;
$this->errors = array();
}
 
function setXML($xml_string)
{
$this->xml = $xml_string;
$this->doc = new DOMDocument;
 
if (!$this->doc) {
return false;
}
 
if (!@$this->doc->loadXML($xml_string)) {
return false;
}
 
$this->xpath = new DOMXPath($this->doc);
 
if ($this->xpath) {
return true;
} else {
return false;
}
}
 
function registerNamespace($prefix, $uri)
{
return $this->xpath->registerNamespace($prefix, $uri);
}
 
function &evalXPath($xpath, $node = null)
{
if ($node) {
$result = @$this->xpath->query($xpath, $node);
} else {
$result = @$this->xpath->query($xpath);
}
 
$n = array();
 
for ($i = 0; $i < $result->length; $i++) {
$n[] = $result->item($i);
}
 
return $n;
}
 
function content($node)
{
if ($node) {
return $node->textContent;
}
}
 
function attributes($node)
{
if ($node) {
$arr = $node->attributes;
$result = array();
 
if ($arr) {
for ($i = 0; $i < $arr->length; $i++) {
$node = $arr->item($i);
$result[$node->nodeName] = $node->nodeValue;
}
}
 
return $result;
}
}
}
 
global $__Services_Yadis_defaultParser;
$__Services_Yadis_defaultParser = null;
 
/**
* Set a default parser to override the extension-driven selection of
* available parser classes. This is helpful in a test environment or
* one in which multiple parsers can be used but one is more
* desirable.
*
* @param Services_Yadis_XMLParser $parser An instance of a
* Services_Yadis_XMLParser subclass.
*/
function Services_Yadis_setDefaultParser(&$parser)
{
global $__Services_Yadis_defaultParser;
$__Services_Yadis_defaultParser =& $parser;
}
 
function Services_Yadis_getSupportedExtensions()
{
return array(
'dom' => array('classname' => 'Services_Yadis_dom',
'libname' => array('dom.so', 'dom.dll')),
'domxml' => array('classname' => 'Services_Yadis_domxml',
'libname' => array('domxml.so', 'php_domxml.dll')),
);
}
 
/**
* Returns an instance of a Services_Yadis_XMLParser subclass based on
* the availability of PHP extensions for XML parsing. If
* Services_Yadis_setDefaultParser has been called, the parser used in
* that call will be returned instead.
*/
function &Services_Yadis_getXMLParser()
{
global $__Services_Yadis_defaultParser;
 
if (isset($__Services_Yadis_defaultParser)) {
return $__Services_Yadis_defaultParser;
}
 
$p = null;
$classname = null;
 
$extensions = Services_Yadis_getSupportedExtensions();
 
// Return a wrapper for the resident implementation, if any.
foreach ($extensions as $name => $params) {
if (!extension_loaded($name)) {
foreach ($params['libname'] as $libname) {
if (@dl($libname)) {
$classname = $params['classname'];
}
}
} else {
$classname = $params['classname'];
}
if (isset($classname)) {
$p = new $classname();
return $p;
}
}
 
if (!isset($p)) {
trigger_error('No XML parser was found', E_USER_ERROR);
} else {
Services_Yadis_setDefaultParser($p);
}
 
return $p;
}
 
?>
/trunk/composants/openid/Services/Yadis/XRDS.php
New file
0,0 → 1,425
<?php
 
/**
* This module contains the XRDS parsing code.
*
* PHP versions 4 and 5
*
* LICENSE: See the COPYING file included in this distribution.
*
* @package Yadis
* @author JanRain, Inc. <openid@janrain.com>
* @copyright 2005 Janrain, Inc.
* @license http://www.gnu.org/copyleft/lesser.html LGPL
*/
 
/**
* Require the XPath implementation.
*/
require_once 'Services/Yadis/XML.php';
 
/**
* This match mode means a given service must match ALL filters passed
* to the Services_Yadis_XRDS::services() call.
*/
define('SERVICES_YADIS_MATCH_ALL', 101);
 
/**
* This match mode means a given service must match ANY filters (at
* least one) passed to the Services_Yadis_XRDS::services() call.
*/
define('SERVICES_YADIS_MATCH_ANY', 102);
 
/**
* The priority value used for service elements with no priority
* specified.
*/
define('SERVICES_YADIS_MAX_PRIORITY', pow(2, 30));
 
function Services_Yadis_getNSMap()
{
return array('xrds' => 'xri://$xrds',
'xrd' => 'xri://$xrd*($v*2.0)');
}
 
/**
* @access private
*/
function Services_Yadis_array_scramble($arr)
{
$result = array();
 
while (count($arr)) {
$index = array_rand($arr, 1);
$result[] = $arr[$index];
unset($arr[$index]);
}
 
return $result;
}
 
/**
* This class represents a <Service> element in an XRDS document.
* Objects of this type are returned by
* Services_Yadis_XRDS::services() and
* Services_Yadis_Yadis::services(). Each object corresponds directly
* to a <Service> element in the XRDS and supplies a
* getElements($name) method which you should use to inspect the
* element's contents. See {@link Services_Yadis_Yadis} for more
* information on the role this class plays in Yadis discovery.
*
* @package Yadis
*/
class Services_Yadis_Service {
 
/**
* Creates an empty service object.
*/
function Services_Yadis_Service()
{
$this->element = null;
$this->parser = null;
}
 
/**
* Return the URIs in the "Type" elements, if any, of this Service
* element.
*
* @return array $type_uris An array of Type URI strings.
*/
function getTypes()
{
$t = array();
foreach ($this->getElements('xrd:Type') as $elem) {
$c = $this->parser->content($elem);
if ($c) {
$t[] = $c;
}
}
return $t;
}
 
/**
* Return the URIs in the "URI" elements, if any, of this Service
* element. The URIs are returned sorted in priority order.
*
* @return array $uris An array of URI strings.
*/
function getURIs()
{
$uris = array();
$last = array();
 
foreach ($this->getElements('xrd:URI') as $elem) {
$uri_string = $this->parser->content($elem);
$attrs = $this->parser->attributes($elem);
if ($attrs &&
array_key_exists('priority', $attrs)) {
$priority = intval($attrs['priority']);
if (!array_key_exists($priority, $uris)) {
$uris[$priority] = array();
}
 
$uris[$priority][] = $uri_string;
} else {
$last[] = $uri_string;
}
}
 
$keys = array_keys($uris);
sort($keys);
 
// Rebuild array of URIs.
$result = array();
foreach ($keys as $k) {
$new_uris = Services_Yadis_array_scramble($uris[$k]);
$result = array_merge($result, $new_uris);
}
 
$result = array_merge($result,
Services_Yadis_array_scramble($last));
 
return $result;
}
 
/**
* Returns the "priority" attribute value of this <Service>
* element, if the attribute is present. Returns null if not.
*
* @return mixed $result Null or integer, depending on whether
* this Service element has a 'priority' attribute.
*/
function getPriority()
{
$attributes = $this->parser->attributes($this->element);
 
if (array_key_exists('priority', $attributes)) {
return intval($attributes['priority']);
}
 
return null;
}
 
/**
* Used to get XML elements from this object's <Service> element.
*
* This is what you should use to get all custom information out
* of this element. This is used by service filter functions to
* determine whether a service element contains specific tags,
* etc. NOTE: this only considers elements which are direct
* children of the <Service> element for this object.
*
* @param string $name The name of the element to look for
* @return array $list An array of elements with the specified
* name which are direct children of the <Service> element. The
* nodes returned by this function can be passed to $this->parser
* methods (see {@link Services_Yadis_XMLParser}).
*/
function getElements($name)
{
return $this->parser->evalXPath($name, $this->element);
}
}
 
/**
* This class performs parsing of XRDS documents.
*
* You should not instantiate this class directly; rather, call
* parseXRDS statically:
*
* <pre> $xrds = Services_Yadis_XRDS::parseXRDS($xml_string);</pre>
*
* If the XRDS can be parsed and is valid, an instance of
* Services_Yadis_XRDS will be returned. Otherwise, null will be
* returned. This class is used by the Services_Yadis_Yadis::discover
* method.
*
* @package Yadis
*/
class Services_Yadis_XRDS {
 
/**
* Instantiate a Services_Yadis_XRDS object. Requires an XPath
* instance which has been used to parse a valid XRDS document.
*/
function Services_Yadis_XRDS(&$xmlParser, &$xrdNodes)
{
$this->parser =& $xmlParser;
$this->xrdNode = $xrdNodes[count($xrdNodes) - 1];
$this->allXrdNodes =& $xrdNodes;
$this->serviceList = array();
$this->_parse();
}
 
/**
* Parse an XML string (XRDS document) and return either a
* Services_Yadis_XRDS object or null, depending on whether the
* XRDS XML is valid.
*
* @param string $xml_string An XRDS XML string.
* @return mixed $xrds An instance of Services_Yadis_XRDS or null,
* depending on the validity of $xml_string
*/
function &parseXRDS($xml_string, $extra_ns_map = null)
{
$_null = null;
 
if (!$xml_string) {
return $_null;
}
 
$parser = Services_Yadis_getXMLParser();
 
$ns_map = Services_Yadis_getNSMap();
 
if ($extra_ns_map && is_array($extra_ns_map)) {
$ns_map = array_merge($ns_map, $extra_ns_map);
}
 
if (!($parser && $parser->init($xml_string, $ns_map))) {
return $_null;
}
 
// Try to get root element.
$root = $parser->evalXPath('/xrds:XRDS[1]');
if (!$root) {
return $_null;
}
 
if (is_array($root)) {
$root = $root[0];
}
 
$attrs = $parser->attributes($root);
 
if (array_key_exists('xmlns:xrd', $attrs) &&
$attrs['xmlns:xrd'] != 'xri://$xrd*($v*2.0)') {
return $_null;
} else if (array_key_exists('xmlns', $attrs) &&
preg_match('/xri/', $attrs['xmlns']) &&
$attrs['xmlns'] != 'xri://$xrd*($v*2.0)') {
return $_null;
}
 
// Get the last XRD node.
$xrd_nodes = $parser->evalXPath('/xrds:XRDS[1]/xrd:XRD');
 
if (!$xrd_nodes) {
return $_null;
}
 
$xrds = new Services_Yadis_XRDS($parser, $xrd_nodes);
return $xrds;
}
 
/**
* @access private
*/
function _addService($priority, $service)
{
$priority = intval($priority);
 
if (!array_key_exists($priority, $this->serviceList)) {
$this->serviceList[$priority] = array();
}
 
$this->serviceList[$priority][] = $service;
}
 
/**
* Creates the service list using nodes from the XRDS XML
* document.
*
* @access private
*/
function _parse()
{
$this->serviceList = array();
 
$services = $this->parser->evalXPath('xrd:Service', $this->xrdNode);
 
foreach ($services as $node) {
$s =& new Services_Yadis_Service();
$s->element = $node;
$s->parser =& $this->parser;
 
$priority = $s->getPriority();
 
if ($priority === null) {
$priority = SERVICES_YADIS_MAX_PRIORITY;
}
 
$this->_addService($priority, $s);
}
}
 
/**
* Returns a list of service objects which correspond to <Service>
* elements in the XRDS XML document for this object.
*
* Optionally, an array of filter callbacks may be given to limit
* the list of returned service objects. Furthermore, the default
* mode is to return all service objects which match ANY of the
* specified filters, but $filter_mode may be
* SERVICES_YADIS_MATCH_ALL if you want to be sure that the
* returned services match all the given filters. See {@link
* Services_Yadis_Yadis} for detailed usage information on filter
* functions.
*
* @param mixed $filters An array of callbacks to filter the
* returned services, or null if all services are to be returned.
* @param integer $filter_mode SERVICES_YADIS_MATCH_ALL or
* SERVICES_YADIS_MATCH_ANY, depending on whether the returned
* services should match ALL or ANY of the specified filters,
* respectively.
* @return mixed $services An array of {@link
* Services_Yadis_Service} objects if $filter_mode is a valid
* mode; null if $filter_mode is an invalid mode (i.e., not
* SERVICES_YADIS_MATCH_ANY or SERVICES_YADIS_MATCH_ALL).
*/
function services($filters = null,
$filter_mode = SERVICES_YADIS_MATCH_ANY)
{
 
$pri_keys = array_keys($this->serviceList);
sort($pri_keys, SORT_NUMERIC);
 
// If no filters are specified, return the entire service
// list, ordered by priority.
if (!$filters ||
(!is_array($filters))) {
 
$result = array();
foreach ($pri_keys as $pri) {
$result = array_merge($result, $this->serviceList[$pri]);
}
 
return $result;
}
 
// If a bad filter mode is specified, return null.
if (!in_array($filter_mode, array(SERVICES_YADIS_MATCH_ANY,
SERVICES_YADIS_MATCH_ALL))) {
return null;
}
 
// Otherwise, use the callbacks in the filter list to
// determine which services are returned.
$filtered = array();
 
foreach ($pri_keys as $priority_value) {
$service_obj_list = $this->serviceList[$priority_value];
 
foreach ($service_obj_list as $service) {
 
$matches = 0;
 
foreach ($filters as $filter) {
if (call_user_func_array($filter, array($service))) {
$matches++;
 
if ($filter_mode == SERVICES_YADIS_MATCH_ANY) {
$pri = $service->getPriority();
if ($pri === null) {
$pri = SERVICES_YADIS_MAX_PRIORITY;
}
 
if (!array_key_exists($pri, $filtered)) {
$filtered[$pri] = array();
}
 
$filtered[$pri][] = $service;
break;
}
}
}
 
if (($filter_mode == SERVICES_YADIS_MATCH_ALL) &&
($matches == count($filters))) {
 
$pri = $service->getPriority();
if ($pri === null) {
$pri = SERVICES_YADIS_MAX_PRIORITY;
}
 
if (!array_key_exists($pri, $filtered)) {
$filtered[$pri] = array();
}
$filtered[$pri][] = $service;
}
}
}
 
$pri_keys = array_keys($filtered);
sort($pri_keys, SORT_NUMERIC);
 
$result = array();
foreach ($pri_keys as $pri) {
$result = array_merge($result, $filtered[$pri]);
}
 
return $result;
}
}
 
?>
/trunk/composants/openid/Services/Yadis/XRI.php
New file
0,0 → 1,233
<?php
 
/**
* Routines for XRI resolution.
*
* @package Yadis
* @author JanRain, Inc. <openid@janrain.com>
* @copyright 2005 Janrain, Inc.
* @license http://www.gnu.org/copyleft/lesser.html LGPL
*/
 
require_once 'Services/Yadis/Misc.php';
require_once 'Services/Yadis/Yadis.php';
require_once 'Auth/OpenID.php';
 
function Services_Yadis_getDefaultProxy()
{
return 'http://proxy.xri.net/';
}
 
function Services_Yadis_getXRIAuthorities()
{
return array('!', '=', '@', '+', '$', '(');
}
 
function Services_Yadis_getEscapeRE()
{
$parts = array();
foreach (array_merge(Services_Yadis_getUCSChars(),
Services_Yadis_getIPrivateChars()) as $pair) {
list($m, $n) = $pair;
$parts[] = sprintf("%s-%s", chr($m), chr($n));
}
 
return sprintf('/[%s]/', implode('', $parts));
}
 
function Services_Yadis_getXrefRE()
{
return '/\((.*?)\)/';
}
 
function Services_Yadis_identifierScheme($identifier)
{
if (Services_Yadis_startswith($identifier, 'xri://') ||
(in_array($identifier[0], Services_Yadis_getXRIAuthorities()))) {
return "XRI";
} else {
return "URI";
}
}
 
function Services_Yadis_toIRINormal($xri)
{
if (!Services_Yadis_startswith($xri, 'xri://')) {
$xri = 'xri://' . $xri;
}
 
return Services_Yadis_escapeForIRI($xri);
}
 
function _escape_xref($xref_match)
{
$xref = $xref_match[0];
$xref = str_replace('/', '%2F', $xref);
$xref = str_replace('?', '%3F', $xref);
$xref = str_replace('#', '%23', $xref);
return $xref;
}
 
function Services_Yadis_escapeForIRI($xri)
{
$xri = str_replace('%', '%25', $xri);
$xri = preg_replace_callback(Services_Yadis_getXrefRE(),
'_escape_xref', $xri);
return $xri;
}
 
function Services_Yadis_toURINormal($xri)
{
return Services_Yadis_iriToURI(Services_Yadis_toIRINormal($xri));
}
 
function Services_Yadis_iriToURI($iri)
{
if (1) {
return $iri;
} else {
// According to RFC 3987, section 3.1, "Mapping of IRIs to URIs"
return preg_replace_callback(Services_Yadis_getEscapeRE(),
'Services_Yadis_pct_escape_unicode', $iri);
}
}
 
 
function Services_Yadis_XRIAppendArgs($url, $args)
{
// Append some arguments to an HTTP query. Yes, this is just like
// OpenID's appendArgs, but with special seasoning for XRI
// queries.
 
if (count($args) == 0) {
return $url;
}
 
// Non-empty array; if it is an array of arrays, use multisort;
// otherwise use sort.
if (array_key_exists(0, $args) &&
is_array($args[0])) {
// Do nothing here.
} else {
$keys = array_keys($args);
sort($keys);
$new_args = array();
foreach ($keys as $key) {
$new_args[] = array($key, $args[$key]);
}
$args = $new_args;
}
 
// According to XRI Resolution section "QXRI query parameters":
//
// "If the original QXRI had a null query component (only a
// leading question mark), or a query component consisting of
// only question marks, one additional leading question mark MUST
// be added when adding any XRI resolution parameters."
if (strpos(rtrim($url, '?'), '?') !== false) {
$sep = '&';
} else {
$sep = '?';
}
 
return $url . $sep . Auth_OpenID::httpBuildQuery($args);
}
 
function Services_Yadis_providerIsAuthoritative($providerID, $canonicalID)
{
$lastbang = strrpos($canonicalID, '!');
$p = substr($canonicalID, 0, $lastbang);
return $p == $providerID;
}
 
function Services_Yadis_rootAuthority($xri)
{
// Return the root authority for an XRI.
 
$root = null;
 
if (Services_Yadis_startswith($xri, 'xri://')) {
$xri = substr($xri, 6);
}
 
$authority = explode('/', $xri, 2);
$authority = $authority[0];
if ($authority[0] == '(') {
// Cross-reference.
// XXX: This is incorrect if someone nests cross-references so
// there is another close-paren in there. Hopefully nobody
// does that before we have a real xriparse function.
// Hopefully nobody does that *ever*.
$root = substr($authority, 0, strpos($authority, ')') + 1);
} else if (in_array($authority[0], Services_Yadis_getXRIAuthorities())) {
// Other XRI reference.
$root = $authority[0];
} else {
// IRI reference.
$_segments = explode("!", $authority);
$segments = array();
foreach ($_segments as $s) {
$segments = array_merge($segments, explode("*", $s));
}
$root = $segments[0];
}
 
return Services_Yadis_XRI($root);
}
 
function Services_Yadis_XRI($xri)
{
if (!Services_Yadis_startswith($xri, 'xri://')) {
$xri = 'xri://' . $xri;
}
return $xri;
}
 
function Services_Yadis_getCanonicalID($iname, $xrds)
{
// Returns FALSE or a canonical ID value.
 
// Now nodes are in reverse order.
$xrd_list = array_reverse($xrds->allXrdNodes);
$parser =& $xrds->parser;
$node = $xrd_list[0];
 
$canonicalID_nodes = $parser->evalXPath('xrd:CanonicalID', $node);
 
if (!$canonicalID_nodes) {
return false;
}
 
$canonicalID = $canonicalID_nodes[count($canonicalID_nodes) - 1];
$canonicalID = Services_Yadis_XRI($parser->content($canonicalID));
 
$childID = $canonicalID;
 
for ($i = 1; $i < count($xrd_list); $i++) {
$xrd = $xrd_list[$i];
 
$parent_sought = substr($childID, 0, strrpos($childID, '!'));
$parent_list = array();
 
foreach ($parser->evalXPath('xrd:CanonicalID', $xrd) as $c) {
$parent_list[] = Services_Yadis_XRI($parser->content($c));
}
 
if (!in_array($parent_sought, $parent_list)) {
// raise XRDSFraud.
return false;
}
 
$childID = $parent_sought;
}
 
$root = Services_Yadis_rootAuthority($iname);
if (!Services_Yadis_providerIsAuthoritative($root, $childID)) {
// raise XRDSFraud.
return false;
}
 
return $canonicalID;
}
 
?>
/trunk/composants/openid/Services/Yadis/PlainHTTPFetcher.php
New file
0,0 → 1,245
<?php
 
/**
* This module contains the plain non-curl HTTP fetcher
* implementation.
*
* PHP versions 4 and 5
*
* LICENSE: See the COPYING file included in this distribution.
*
* @package Yadis
* @author JanRain, Inc. <openid@janrain.com>
* @copyright 2005 Janrain, Inc.
* @license http://www.gnu.org/copyleft/lesser.html LGPL
*/
 
/**
* Interface import
*/
require_once "Services/Yadis/HTTPFetcher.php";
 
/**
* This class implements a plain, hand-built socket-based fetcher
* which will be used in the event that CURL is unavailable.
*
* @package Yadis
*/
class Services_Yadis_PlainHTTPFetcher extends Services_Yadis_HTTPFetcher {
function get($url, $extra_headers = null)
{
if (!$this->allowedURL($url)) {
trigger_error("Bad URL scheme in url: " . $url,
E_USER_WARNING);
return null;
}
 
$redir = true;
 
$stop = time() + $this->timeout;
$off = $this->timeout;
 
while ($redir && ($off > 0)) {
 
$parts = parse_url($url);
 
$specify_port = true;
 
// Set a default port.
if (!array_key_exists('port', $parts)) {
$specify_port = false;
if ($parts['scheme'] == 'http') {
$parts['port'] = 80;
} elseif ($parts['scheme'] == 'https') {
$parts['port'] = 443;
} else {
trigger_error("fetcher post method doesn't support " .
" scheme '" . $parts['scheme'] .
"', no default port available",
E_USER_WARNING);
return null;
}
}
 
$host = $parts['host'];
 
if ($parts['scheme'] == 'https') {
$host = 'ssl://' . $host;
}
 
$user_agent = "PHP Yadis Library Fetcher";
 
$headers = array(
"GET ".$parts['path'].
(array_key_exists('query', $parts) ?
"?".$parts['query'] : "").
" HTTP/1.0",
"User-Agent: $user_agent",
"Host: ".$parts['host'].
($specify_port ? ":".$parts['port'] : ""),
"Port: ".$parts['port']);
 
$errno = 0;
$errstr = '';
 
if ($extra_headers) {
foreach ($extra_headers as $h) {
$headers[] = $h;
}
}
 
@$sock = fsockopen($host, $parts['port'], $errno, $errstr,
$this->timeout);
if ($sock === false) {
return false;
}
 
stream_set_timeout($sock, $this->timeout);
 
fputs($sock, implode("\r\n", $headers) . "\r\n\r\n");
 
$data = "";
while (!feof($sock)) {
$data .= fgets($sock, 1024);
}
 
fclose($sock);
 
// Split response into header and body sections
list($headers, $body) = explode("\r\n\r\n", $data, 2);
$headers = explode("\r\n", $headers);
 
$http_code = explode(" ", $headers[0]);
$code = $http_code[1];
 
if (in_array($code, array('301', '302'))) {
$url = $this->_findRedirect($headers);
$redir = true;
} else {
$redir = false;
}
 
$off = $stop - time();
}
 
$new_headers = array();
 
foreach ($headers as $header) {
if (preg_match("/:/", $header)) {
list($name, $value) = explode(": ", $header, 2);
$new_headers[$name] = $value;
}
 
}
 
return new Services_Yadis_HTTPResponse($url, $code, $new_headers, $body);
}
 
function post($url, $body, $extra_headers = null)
{
if (!$this->allowedURL($url)) {
trigger_error("Bad URL scheme in url: " . $url,
E_USER_WARNING);
return null;
}
 
$parts = parse_url($url);
 
$headers = array();
 
$post_path = $parts['path'];
if (isset($parts['query'])) {
$post_path .= '?' . $parts['query'];
}
 
$headers[] = "POST ".$post_path." HTTP/1.0";
$headers[] = "Host: " . $parts['host'];
$headers[] = "Content-type: application/x-www-form-urlencoded";
$headers[] = "Content-length: " . strval(strlen($body));
 
if ($extra_headers &&
is_array($extra_headers)) {
$headers = array_merge($headers, $extra_headers);
}
 
// Join all headers together.
$all_headers = implode("\r\n", $headers);
 
// Add headers, two newlines, and request body.
$request = $all_headers . "\r\n\r\n" . $body;
 
// Set a default port.
if (!array_key_exists('port', $parts)) {
if ($parts['scheme'] == 'http') {
$parts['port'] = 80;
} elseif ($parts['scheme'] == 'https') {
$parts['port'] = 443;
} else {
trigger_error("fetcher post method doesn't support scheme '" .
$parts['scheme'] .
"', no default port available",
E_USER_WARNING);
return null;
}
}
 
if ($parts['scheme'] == 'https') {
$parts['host'] = sprintf("ssl://%s", $parts['host']);
}
 
// Connect to the remote server.
$errno = 0;
$errstr = '';
 
$sock = fsockopen($parts['host'], $parts['port'], $errno, $errstr,
$this->timeout);
 
if ($sock === false) {
trigger_error("Could not connect to " . $parts['host'] .
" port " . $parts['port'],
E_USER_WARNING);
return null;
}
 
stream_set_timeout($sock, $this->timeout);
 
// Write the POST request.
fputs($sock, $request);
 
// Get the response from the server.
$response = "";
while (!feof($sock)) {
if ($data = fgets($sock, 128)) {
$response .= $data;
} else {
break;
}
}
 
// Split the request into headers and body.
list($headers, $response_body) = explode("\r\n\r\n", $response, 2);
 
$headers = explode("\r\n", $headers);
 
// Expect the first line of the headers data to be something
// like HTTP/1.1 200 OK. Split the line on spaces and take
// the second token, which should be the return code.
$http_code = explode(" ", $headers[0]);
$code = $http_code[1];
 
$new_headers = array();
 
foreach ($headers as $header) {
if (preg_match("/:/", $header)) {
list($name, $value) = explode(": ", $header, 2);
$new_headers[$name] = $value;
}
 
}
 
return new Services_Yadis_HTTPResponse($url, $code,
$headers, $response_body);
}
}
 
?>
/trunk/composants/openid/Services/Yadis/Yadis.php
New file
0,0 → 1,313
<?php
 
/**
* The core PHP Yadis implementation.
*
* PHP versions 4 and 5
*
* LICENSE: See the COPYING file included in this distribution.
*
* @package Yadis
* @author JanRain, Inc. <openid@janrain.com>
* @copyright 2005 Janrain, Inc.
* @license http://www.gnu.org/copyleft/lesser.html LGPL
*/
 
/**
* Need both fetcher types so we can use the right one based on the
* presence or absence of CURL.
*/
require_once "Services/Yadis/PlainHTTPFetcher.php";
require_once "Services/Yadis/ParanoidHTTPFetcher.php";
 
/**
* Need this for parsing HTML (looking for META tags).
*/
require_once "Services/Yadis/ParseHTML.php";
 
/**
* Need this to parse the XRDS document during Yadis discovery.
*/
require_once "Services/Yadis/XRDS.php";
 
/**
* This is the core of the PHP Yadis library. This is the only class
* a user needs to use to perform Yadis discovery. This class
* performs the discovery AND stores the result of the discovery.
*
* First, require this library into your program source:
*
* <pre> require_once "Services/Yadis/Yadis.php";</pre>
*
* To perform Yadis discovery, first call the "discover" method
* statically with a URI parameter:
*
* <pre> $http_response = array();
* $fetcher = Services_Yadis_Yadis::getHTTPFetcher();
* $yadis_object = Services_Yadis_Yadis::discover($uri,
* $http_response, $fetcher);</pre>
*
* If the discovery succeeds, $yadis_object will be an instance of
* {@link Services_Yadis_Yadis}. If not, it will be null. The XRDS
* document found during discovery should have service descriptions,
* which can be accessed by calling
*
* <pre> $service_list = $yadis_object->services();</pre>
*
* which returns an array of objects which describe each service.
* These objects are instances of Services_Yadis_Service. Each object
* describes exactly one whole Service element, complete with all of
* its Types and URIs (no expansion is performed). The common use
* case for using the service objects returned by services() is to
* write one or more filter functions and pass those to services():
*
* <pre> $service_list = $yadis_object->services(
* array("filterByURI",
* "filterByExtension"));</pre>
*
* The filter functions (whose names appear in the array passed to
* services()) take the following form:
*
* <pre> function myFilter(&$service) {
* // Query $service object here. Return true if the service
* // matches your query; false if not.
* }</pre>
*
* This is an example of a filter which uses a regular expression to
* match the content of URI tags (note that the Services_Yadis_Service
* class provides a getURIs() method which you should use instead of
* this contrived example):
*
* <pre>
* function URIMatcher(&$service) {
* foreach ($service->getElements('xrd:URI') as $uri) {
* if (preg_match("/some_pattern/",
* $service->parser->content($uri))) {
* return true;
* }
* }
* return false;
* }</pre>
*
* The filter functions you pass will be called for each service
* object to determine which ones match the criteria your filters
* specify. The default behavior is that if a given service object
* matches ANY of the filters specified in the services() call, it
* will be returned. You can specify that a given service object will
* be returned ONLY if it matches ALL specified filters by changing
* the match mode of services():
*
* <pre> $yadis_object->services(array("filter1", "filter2"),
* SERVICES_YADIS_MATCH_ALL);</pre>
*
* See {@link SERVICES_YADIS_MATCH_ALL} and {@link
* SERVICES_YADIS_MATCH_ANY}.
*
* Services described in an XRDS should have a library which you'll
* probably be using. Those libraries are responsible for defining
* filters that can be used with the "services()" call. If you need
* to write your own filter, see the documentation for {@link
* Services_Yadis_Service}.
*
* @package Yadis
*/
class Services_Yadis_Yadis {
 
/**
* Returns an HTTP fetcher object. If the CURL extension is
* present, an instance of {@link Services_Yadis_ParanoidHTTPFetcher}
* is returned. If not, an instance of
* {@link Services_Yadis_PlainHTTPFetcher} is returned.
*/
function getHTTPFetcher($timeout = 20)
{
if (Services_Yadis_Yadis::curlPresent()) {
$fetcher = new Services_Yadis_ParanoidHTTPFetcher($timeout);
} else {
$fetcher = new Services_Yadis_PlainHTTPFetcher($timeout);
}
return $fetcher;
}
 
function curlPresent()
{
return function_exists('curl_init');
}
 
/**
* @access private
*/
function _getHeader($header_list, $names)
{
foreach ($header_list as $name => $value) {
foreach ($names as $n) {
if (strtolower($name) == strtolower($n)) {
return $value;
}
}
}
 
return null;
}
 
/**
* @access private
*/
function _getContentType($content_type_header)
{
if ($content_type_header) {
$parts = explode(";", $content_type_header);
return strtolower($parts[0]);
}
}
 
/**
* This should be called statically and will build a Yadis
* instance if the discovery process succeeds. This implements
* Yadis discovery as specified in the Yadis specification.
*
* @param string $uri The URI on which to perform Yadis discovery.
*
* @param array $http_response An array reference where the HTTP
* response object will be stored (see {@link
* Services_Yadis_HTTPResponse}.
*
* @param Services_Yadis_HTTPFetcher $fetcher An instance of a
* Services_Yadis_HTTPFetcher subclass.
*
* @param array $extra_ns_map An array which maps namespace names
* to namespace URIs to be used when parsing the Yadis XRDS
* document.
*
* @param integer $timeout An optional fetcher timeout, in seconds.
*
* @return mixed $obj Either null or an instance of
* Services_Yadis_Yadis, depending on whether the discovery
* succeeded.
*/
function discover($uri, &$http_response, &$fetcher,
$extra_ns_map = null, $timeout = 20)
{
if (!$uri) {
return null;
}
 
$request_uri = $uri;
$headers = array("Accept: application/xrds+xml");
 
if (!$fetcher) {
$fetcher = Services_Yadis_Yadis::getHTTPFetcher($timeout);
}
 
$response = $fetcher->get($uri, $headers);
$http_response = $response;
 
if (!$response) {
return null;
}
 
if ($response->status != 200) {
return null;
}
 
$xrds_uri = $response->final_url;
$uri = $response->final_url;
$body = $response->body;
 
$xrds_header_uri = Services_Yadis_Yadis::_getHeader(
$response->headers,
array('x-xrds-location',
'x-yadis-location'));
 
$content_type = Services_Yadis_Yadis::_getHeader($response->headers,
array('content-type'));
 
if ($xrds_header_uri) {
$xrds_uri = $xrds_header_uri;
$response = $fetcher->get($xrds_uri);
$http_response = $response;
if (!$response) {
return null;
} else {
$body = $response->body;
$headers = $response->headers;
$content_type = Services_Yadis_Yadis::_getHeader($headers,
array('content-type'));
}
}
 
if (Services_Yadis_Yadis::_getContentType($content_type) !=
'application/xrds+xml') {
// Treat the body as HTML and look for a META tag.
$parser = new Services_Yadis_ParseHTML();
$new_uri = $parser->getHTTPEquiv($body);
$xrds_uri = null;
if ($new_uri) {
$response = $fetcher->get($new_uri);
if ($response->status != 200) {
return null;
}
$http_response = $response;
$body = $response->body;
$xrds_uri = $new_uri;
$content_type = Services_Yadis_Yadis::_getHeader(
$response->headers,
array('content-type'));
}
}
 
$xrds = Services_Yadis_XRDS::parseXRDS($body, $extra_ns_map);
 
if ($xrds !== null) {
$y = new Services_Yadis_Yadis();
 
$y->request_uri = $request_uri;
$y->xrds = $xrds;
$y->uri = $uri;
$y->xrds_uri = $xrds_uri;
$y->body = $body;
$y->content_type = $content_type;
 
return $y;
} else {
return null;
}
}
 
/**
* Instantiates an empty Services_Yadis_Yadis object. This
* constructor should not be used by any user of the library.
* This constructor results in a completely useless object which
* must be populated with valid discovery information. Instead of
* using this constructor, call
* Services_Yadis_Yadis::discover($uri).
*/
function Services_Yadis_Yadis()
{
$this->request_uri = null;
$this->uri = null;
$this->xrds = null;
$this->xrds_uri = null;
$this->body = null;
$this->content_type = null;
}
 
/**
* Returns the list of service objects as described by the XRDS
* document, if this yadis object represents a successful Yadis
* discovery.
*
* @return array $services An array of {@link Services_Yadis_Service}
* objects
*/
function services()
{
if ($this->xrds) {
return $this->xrds->services();
}
 
return null;
}
}
 
?>
/trunk/composants/openid/Services/Yadis/Manager.php
New file
0,0 → 1,496
<?php
 
/**
* Yadis service manager to be used during yadis-driven authentication
* attempts.
*
* @package Yadis
*/
 
/**
* The base session class used by the Services_Yadis_Manager. This
* class wraps the default PHP session machinery and should be
* subclassed if your application doesn't use PHP sessioning.
*
* @package Yadis
*/
class Services_Yadis_PHPSession {
/**
* Set a session key/value pair.
*
* @param string $name The name of the session key to add.
* @param string $value The value to add to the session.
*/
function set($name, $value)
{
$_SESSION[$name] = $value;
}
 
/**
* Get a key's value from the session.
*
* @param string $name The name of the key to retrieve.
* @param string $default The optional value to return if the key
* is not found in the session.
* @return string $result The key's value in the session or
* $default if it isn't found.
*/
function get($name, $default=null)
{
if (array_key_exists($name, $_SESSION)) {
return $_SESSION[$name];
} else {
return $default;
}
}
 
/**
* Remove a key/value pair from the session.
*
* @param string $name The name of the key to remove.
*/
function del($name)
{
unset($_SESSION[$name]);
}
 
/**
* Return the contents of the session in array form.
*/
function contents()
{
return $_SESSION;
}
}
 
/**
* A session helper class designed to translate between arrays and
* objects. Note that the class used must have a constructor that
* takes no parameters. This is not a general solution, but it works
* for dumb objects that just need to have attributes set. The idea
* is that you'll subclass this and override $this->check($data) ->
* bool to implement your own session data validation.
*/
class Services_Yadis_SessionLoader {
/**
* Override this.
*/
function check($data)
{
return true;
}
 
/**
* Given a session data value (an array), this creates an object
* (returned by $this->newObject()) whose attributes and values
* are those in $data. Returns null if $data lacks keys found in
* $this->requiredKeys(). Returns null if $this->check($data)
* evaluates to false. Returns null if $this->newObject()
* evaluates to false.
*/
function fromSession($data)
{
if (!$data) {
return null;
}
 
$required = $this->requiredKeys();
 
foreach ($required as $k) {
if (!array_key_exists($k, $data)) {
return null;
}
}
 
if (!$this->check($data)) {
return null;
}
 
$data = array_merge($data, $this->prepareForLoad($data));
$obj = $this->newObject($data);
 
if (!$obj) {
return null;
}
 
foreach ($required as $k) {
$obj->$k = $data[$k];
}
 
return $obj;
}
 
/**
* Prepares the data array by making any necessary changes.
* Returns an array whose keys and values will be used to update
* the original data array before calling $this->newObject($data).
*/
function prepareForLoad($data)
{
return array();
}
 
/**
* Returns a new instance of this loader's class, using the
* session data to construct it if necessary. The object need
* only be created; $this->fromSession() will take care of setting
* the object's attributes.
*/
function newObject($data)
{
return null;
}
 
/**
* Returns an array of keys and values built from the attributes
* of $obj. If $this->prepareForSave($obj) returns an array, its keys
* and values are used to update the $data array of attributes
* from $obj.
*/
function toSession($obj)
{
$data = array();
foreach ($obj as $k => $v) {
$data[$k] = $v;
}
 
$extra = $this->prepareForSave($obj);
 
if ($extra && is_array($extra)) {
foreach ($extra as $k => $v) {
$data[$k] = $v;
}
}
 
return $data;
}
 
/**
* Override this.
*/
function prepareForSave($obj)
{
return array();
}
}
 
class Auth_OpenID_ServiceEndpointLoader extends Services_Yadis_SessionLoader {
function newObject($data)
{
return new Auth_OpenID_ServiceEndpoint();
}
 
function requiredKeys()
{
$obj = new Auth_OpenID_ServiceEndpoint();
$data = array();
foreach ($obj as $k => $v) {
$data[] = $k;
}
return $data;
}
 
function check($data)
{
return is_array($data['type_uris']);
}
}
 
class Services_Yadis_ManagerLoader extends Services_Yadis_SessionLoader {
function requiredKeys()
{
return array('starting_url',
'yadis_url',
'services',
'session_key',
'_current',
'stale');
}
 
function newObject($data)
{
return new Services_Yadis_Manager($data['starting_url'],
$data['yadis_url'],
$data['services'],
$data['session_key']);
}
 
function check($data)
{
return is_array($data['services']);
}
 
function prepareForLoad($data)
{
$loader = new Auth_OpenID_ServiceEndpointLoader();
$services = array();
foreach ($data['services'] as $s) {
$services[] = $loader->fromSession($s);
}
return array('services' => $services);
}
 
function prepareForSave($obj)
{
$loader = new Auth_OpenID_ServiceEndpointLoader();
$services = array();
foreach ($obj->services as $s) {
$services[] = $loader->toSession($s);
}
return array('services' => $services);
}
}
 
/**
* The Yadis service manager which stores state in a session and
* iterates over <Service> elements in a Yadis XRDS document and lets
* a caller attempt to use each one. This is used by the Yadis
* library internally.
*
* @package Yadis
*/
class Services_Yadis_Manager {
 
/**
* Intialize a new yadis service manager.
*
* @access private
*/
function Services_Yadis_Manager($starting_url, $yadis_url,
$services, $session_key)
{
// The URL that was used to initiate the Yadis protocol
$this->starting_url = $starting_url;
 
// The URL after following redirects (the identifier)
$this->yadis_url = $yadis_url;
 
// List of service elements
$this->services = $services;
 
$this->session_key = $session_key;
 
// Reference to the current service object
$this->_current = null;
 
// Stale flag for cleanup if PHP lib has trouble.
$this->stale = false;
}
 
/**
* @access private
*/
function length()
{
// How many untried services remain?
return count($this->services);
}
 
/**
* Return the next service
*
* $this->current() will continue to return that service until the
* next call to this method.
*/
function nextService()
{
 
if ($this->services) {
$this->_current = array_shift($this->services);
} else {
$this->_current = null;
}
 
return $this->_current;
}
 
/**
* @access private
*/
function current()
{
// Return the current service.
// Returns None if there are no services left.
return $this->_current;
}
 
/**
* @access private
*/
function forURL($url)
{
return in_array($url, array($this->starting_url, $this->yadis_url));
}
 
/**
* @access private
*/
function started()
{
// Has the first service been returned?
return $this->_current !== null;
}
}
 
/**
* State management for discovery.
*
* High-level usage pattern is to call .getNextService(discover) in
* order to find the next available service for this user for this
* session. Once a request completes, call .finish() to clean up the
* session state.
*
* @package Yadis
*/
class Services_Yadis_Discovery {
 
/**
* @access private
*/
var $DEFAULT_SUFFIX = 'auth';
 
/**
* @access private
*/
var $PREFIX = '_yadis_services_';
 
/**
* Initialize a discovery object.
*
* @param Services_Yadis_PHPSession $session An object which
* implements the Services_Yadis_PHPSession API.
* @param string $url The URL on which to attempt discovery.
* @param string $session_key_suffix The optional session key
* suffix override.
*/
function Services_Yadis_Discovery(&$session, $url,
$session_key_suffix = null)
{
/// Initialize a discovery object
$this->session =& $session;
$this->url = $url;
if ($session_key_suffix === null) {
$session_key_suffix = $this->DEFAULT_SUFFIX;
}
 
$this->session_key_suffix = $session_key_suffix;
$this->session_key = $this->PREFIX . $this->session_key_suffix;
}
 
/**
* Return the next authentication service for the pair of
* user_input and session. This function handles fallback.
*/
function getNextService($discover_cb, &$fetcher)
{
$manager = $this->getManager();
if (!$manager || (!$manager->services)) {
$this->destroyManager();
$http_response = array();
 
$services = call_user_func($discover_cb, $this->url,
$fetcher);
 
$manager = $this->createManager($services, $this->url);
}
 
if ($manager) {
$loader = new Services_Yadis_ManagerLoader();
$service = $manager->nextService();
$this->session->set($this->session_key,
serialize($loader->toSession($manager)));
} else {
$service = null;
}
 
return $service;
}
 
/**
* Clean up Yadis-related services in the session and return the
* most-recently-attempted service from the manager, if one
* exists.
*/
function cleanup()
{
$manager = $this->getManager();
if ($manager) {
$service = $manager->current();
$this->destroyManager();
} else {
$service = null;
}
 
return $service;
}
 
/**
* @access private
*/
function getSessionKey()
{
// Get the session key for this starting URL and suffix
return $this->PREFIX . $this->session_key_suffix;
}
 
/**
* @access private
*/
function &getManager()
{
// Extract the YadisServiceManager for this object's URL and
// suffix from the session.
 
$manager_str = $this->session->get($this->getSessionKey());
$manager = null;
 
if ($manager_str !== null) {
$loader = new Services_Yadis_ManagerLoader();
$manager = $loader->fromSession(unserialize($manager_str));
}
 
if ($manager && $manager->forURL($this->url)) {
return $manager;
} else {
$unused = null;
return $unused;
}
}
 
/**
* @access private
*/
function &createManager($services, $yadis_url = null)
{
$key = $this->getSessionKey();
if ($this->getManager()) {
return $this->getManager();
}
 
if ($services) {
$loader = new Services_Yadis_ManagerLoader();
$manager = new Services_Yadis_Manager($this->url, $yadis_url,
$services, $key);
$this->session->set($this->session_key,
serialize($loader->toSession($manager)));
return $manager;
} else {
// Oh, PHP.
$unused = null;
return $unused;
}
}
 
/**
* @access private
*/
function destroyManager()
{
if ($this->getManager() !== null) {
$key = $this->getSessionKey();
$this->session->del($key);
}
}
}
 
?>
/trunk/composants/openid/Services/Yadis/Misc.php
New file
0,0 → 1,59
<?php
 
/**
* Miscellaneous utility values and functions for OpenID and Yadis.
*
* @package OpenID
* @author JanRain, Inc. <openid@janrain.com>
* @copyright 2005 Janrain, Inc.
* @license http://www.gnu.org/copyleft/lesser.html LGPL
*/
 
function Services_Yadis_getUCSChars()
{
return array(
array(0xA0, 0xD7FF),
array(0xF900, 0xFDCF),
array(0xFDF0, 0xFFEF),
array(0x10000, 0x1FFFD),
array(0x20000, 0x2FFFD),
array(0x30000, 0x3FFFD),
array(0x40000, 0x4FFFD),
array(0x50000, 0x5FFFD),
array(0x60000, 0x6FFFD),
array(0x70000, 0x7FFFD),
array(0x80000, 0x8FFFD),
array(0x90000, 0x9FFFD),
array(0xA0000, 0xAFFFD),
array(0xB0000, 0xBFFFD),
array(0xC0000, 0xCFFFD),
array(0xD0000, 0xDFFFD),
array(0xE1000, 0xEFFFD)
);
}
 
function Services_Yadis_getIPrivateChars()
{
return array(
array(0xE000, 0xF8FF),
array(0xF0000, 0xFFFFD),
array(0x100000, 0x10FFFD)
);
}
 
function Services_Yadis_pct_escape_unicode($char_match)
{
$c = $char_match[0];
$result = "";
for ($i = 0; $i < strlen($c); $i++) {
$result .= "%".sprintf("%X", ord($c[$i]));
}
return $result;
}
 
function Services_Yadis_startswith($s, $stuff)
{
return strpos($s, $stuff) === 0;
}
 
?>
/trunk/composants/openid/Services/Yadis/XRIRes.php
New file
0,0 → 1,68
<?php
 
require_once 'Services/Yadis/XRDS.php';
require_once 'Services/Yadis/XRI.php';
 
class Services_Yadis_ProxyResolver {
function Services_Yadis_ProxyResolver(&$fetcher, $proxy_url = null)
{
$this->fetcher =& $fetcher;
$this->proxy_url = $proxy_url;
if (!$this->proxy_url) {
$this->proxy_url = Services_Yadis_getDefaultProxy();
}
}
 
function queryURL($xri, $service_type = null)
{
// trim off the xri:// prefix
$qxri = substr(Services_Yadis_toURINormal($xri), 6);
$hxri = $this->proxy_url . $qxri;
$args = array(
'_xrd_r' => 'application/xrds+xml'
);
 
if ($service_type) {
$args['_xrd_t'] = $service_type;
} else {
// Don't perform service endpoint selection.
$args['_xrd_r'] .= ';sep=false';
}
 
$query = Services_Yadis_XRIAppendArgs($hxri, $args);
return $query;
}
 
function query($xri, $service_types, $filters = array())
{
$services = array();
$canonicalID = null;
foreach ($service_types as $service_type) {
$url = $this->queryURL($xri, $service_type);
$response = $this->fetcher->get($url);
if ($response->status != 200) {
continue;
}
$xrds = Services_Yadis_XRDS::parseXRDS($response->body);
if (!$xrds) {
continue;
}
$canonicalID = Services_Yadis_getCanonicalID($xri,
$xrds);
 
if ($canonicalID === false) {
return null;
}
 
$some_services = $xrds->services($filters);
$services = array_merge($services, $some_services);
// TODO:
// * If we do get hits for multiple service_types, we're
// almost certainly going to have duplicated service
// entries and broken priority ordering.
}
return array($canonicalID, $services);
}
}
 
?>
/trunk/composants/openid/Services/Yadis/ParanoidHTTPFetcher.php
New file
0,0 → 1,177
<?php
 
/**
* This module contains the CURL-based HTTP fetcher implementation.
*
* PHP versions 4 and 5
*
* LICENSE: See the COPYING file included in this distribution.
*
* @package Yadis
* @author JanRain, Inc. <openid@janrain.com>
* @copyright 2005 Janrain, Inc.
* @license http://www.gnu.org/copyleft/lesser.html LGPL
*/
 
/**
* Interface import
*/
require_once "Services/Yadis/HTTPFetcher.php";
 
/**
* A paranoid {@link Services_Yadis_HTTPFetcher} class which uses CURL
* for fetching.
*
* @package Yadis
*/
class Services_Yadis_ParanoidHTTPFetcher extends Services_Yadis_HTTPFetcher {
function Services_Yadis_ParanoidHTTPFetcher()
{
$this->reset();
}
 
function reset()
{
$this->headers = array();
$this->data = "";
}
 
/**
* @access private
*/
function _writeHeader($ch, $header)
{
array_push($this->headers, rtrim($header));
return strlen($header);
}
 
/**
* @access private
*/
function _writeData($ch, $data)
{
$this->data .= $data;
return strlen($data);
}
 
function get($url, $extra_headers = null)
{
$stop = time() + $this->timeout;
$off = $this->timeout;
 
$redir = true;
 
while ($redir && ($off > 0)) {
$this->reset();
 
$c = curl_init();
if (defined('CURLOPT_NOSIGNAL')) {
curl_setopt($c, CURLOPT_NOSIGNAL, true);
}
 
if (!$this->allowedURL($url)) {
trigger_error(sprintf("Fetching URL not allowed: %s", $url),
E_USER_WARNING);
return null;
}
 
curl_setopt($c, CURLOPT_WRITEFUNCTION,
array(&$this, "_writeData"));
curl_setopt($c, CURLOPT_HEADERFUNCTION,
array(&$this, "_writeHeader"));
 
if ($extra_headers) {
curl_setopt($c, CURLOPT_HTTPHEADER, $extra_headers);
}
 
curl_setopt($c, CURLOPT_TIMEOUT, $off);
curl_setopt($c, CURLOPT_URL, $url);
 
curl_exec($c);
 
$code = curl_getinfo($c, CURLINFO_HTTP_CODE);
$body = $this->data;
$headers = $this->headers;
 
if (!$code) {
return null;
}
 
if (in_array($code, array(301, 302, 303, 307))) {
$url = $this->_findRedirect($headers);
$redir = true;
} else {
$redir = false;
curl_close($c);
 
$new_headers = array();
 
foreach ($headers as $header) {
if (preg_match("/:/", $header)) {
list($name, $value) = explode(": ", $header, 2);
$new_headers[$name] = $value;
}
}
 
return new Services_Yadis_HTTPResponse($url, $code,
$new_headers, $body);
}
 
$off = $stop - time();
}
 
trigger_error(sprintf("Timed out fetching: %s", $url),
E_USER_WARNING);
 
return null;
}
 
function post($url, $body)
{
$this->reset();
 
if (!$this->allowedURL($url)) {
trigger_error(sprintf("Fetching URL not allowed: %s", $url),
E_USER_WARNING);
return null;
}
 
$c = curl_init();
 
curl_setopt($c, CURLOPT_NOSIGNAL, true);
curl_setopt($c, CURLOPT_POST, true);
curl_setopt($c, CURLOPT_POSTFIELDS, $body);
curl_setopt($c, CURLOPT_TIMEOUT, $this->timeout);
curl_setopt($c, CURLOPT_URL, $url);
curl_setopt($c, CURLOPT_WRITEFUNCTION,
array(&$this, "_writeData"));
 
curl_exec($c);
 
$code = curl_getinfo($c, CURLINFO_HTTP_CODE);
 
if (!$code) {
trigger_error("No HTTP code returned", E_USER_WARNING);
return null;
}
 
$body = $this->data;
 
curl_close($c);
 
$new_headers = array();
 
foreach ($this->headers as $header) {
if (preg_match("/:/", $header)) {
list($name, $value) = explode(": ", $header, 2);
$new_headers[$name] = $value;
}
 
}
 
return new Services_Yadis_HTTPResponse($url, $code,
$new_headers, $body);
}
}
 
?>
/trunk/composants/openid/OpenId.php
New file
0,0 → 1,85
<? // fichiers inclus
require_once "Auth/OpenID/Consumer.php";
require_once "Auth/OpenID/FileStore.php";
 
// démarrage de la session (requis pour YADIS)
session_start();
 
// crée une zone de stockage pour les données OpenID
$store = new Auth_OpenID_FileStore('./oid_store');
 
// crée un consommateur OpenID
$consumer = new Auth_OpenID_Consumer($store);
 
// commence le process d'authentification
// crée une requête d'authentification pour le fournisseur OpenID
$auth = $consumer->begin($_POST['id']);
if (!$auth) {
die("ERROR: Entrez un OpenID valide svp.");
}
 
// redirige vers le fournisseur OpenID pour l'authentification
$url = $auth->redirectURL('http://consumer.example.com/', 'http://consumer.example.com/oid_return.php');
header('Location: ' . $url);
 
// fichiers inclus
require_once "Auth/OpenID/Consumer.php";
require_once "Auth/OpenID/FileStore.php";
require_once "Auth/OpenID/SReg.php";
 
// démarrage de session (requis pour YADIS)
session_start();
 
// crée une zone de stockage pour les données OpenID
$store = new Auth_OpenID_FileStore('./oid_store');
 
// crée un consommateur OpenID
// lit la réponse depuis e fournisseur OPenID
$consumer = new Auth_OpenID_Consumer($store);
$response = $consumer->complete('http://consumer.example.com/oid_return.php');
 
// crée une variable de session qui dépend de l'authentification
if ($response->status == Auth_OpenID_SUCCESS) {
$_SESSION['OPENID_AUTH'] = true;
 
// récupère les informations d'enregistrement
$sreg = new Auth_OpenID_SRegResponse();
$obj = $sreg->fromSuccessResponse($response);
$data = $obj->contents();
 
if (isset($data['email'])) {
// Si l'adresse mail est disponible
// Vérifie si l'utilisateur a déjà un compte sur le système
 
// ouvre une connexion a la base
$conn = mysql_connect('localhost', 'user', 'pass') or die('ERROR: Connexion serveur impossible');
mysql_select_db('test') or die('ERROR: Impossible de sélectionner une base');
 
// exécute la requête
$result = mysql_query("SELECT DISTINCT COUNT(*) FROM users WHERE email = '" . $data['email'] . "'") or die('ERROR: La requête ne peut pas être exécutée');
 
$row = mysql_fetch_array($result);
if ($row[0] == 1) {
// si oui affiche un message personnalisé
$newUser = false;
echo 'Bonjour et bienvenue, ' . $data['email'];
exit();
} else {
// si non avertit que l'utilisateur est nouveau
$newUser = true;
}
 
// ferme la connexion
mysql_free_result($result);
mysql_close($conn);
} else {
// si l'adresse email n'est pas disponible
// avertit que l'utilisateur est nouveau
$newUser = true;
}
} else {
$_SESSION['OPENID_AUTH'] = false;
die ('Vous n'avez pas la permission d'accéder a cette page! Re-loggez vous svp.');
}
 
?>
/trunk/composants/cartographie/Cartographie.php
New file
0,0 → 1,642
<?php
// declare(encoding='UTF-8');
/**
* Composant Cartographie gérant les images représentant le fond de carte à insérer dans un fichier html contenant une
* image map.
* Avantage :
* - pas de base de données liée au composant (simplicité d'utilisation dans les applications)
* - facilite l'utilisation du Javascript et CSS pour intéragir avec la carte (affichage du nom des zones au survol)
* - l'application qui utilise le composant définie elle-même l'intéraction avec le clic sur une zone
* Inconvénient :
* - l'utilisation d'une balise map alourdie la page à renvoyer
*
* Il est possible de créer des fond de carte en vraies couleurs
* (16 millions de zones maxi sur la carte) ou en couleurs indexées (255 zones maxi sur la carte).
* Les couleurs réservées et a ne pas utiliser pour créer l'image png de fond sont :
* - le blanc (rvb : 255-255-255)
* - le noir (rvb : 0-0-0)
* - le gris (rvb : 128-128-128)
* - le rouge (rvb : 255-0-0)
* Pour activer le cache indiquer la date de dernière mise à jour des données servant à créer la carte de cette façon :
* $Carte->setCarteInfo(array('donnees_date_maj' => $date_maj_donnees));
*
* @category PHP5
* @package Collection
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @copyright 2010 Tela-Botanica
* @license GPL-v3 et CECILL-v2
* @version SVN:$Id$
*/
 
class Cartographie {
/*** Constantes : ***/
const FORMULE_PROPORTIONNEL = 'proportionnel';
const FORMULE_LEGENDE = 'legende';
 
//+----------------------------------------------------------------------------------------------------------------+
/*** Attributs : ***/
/**
* L'image de la carte.
* @var string l'image de la carte.
*/
private $carte;
 
/**
* Le nom du fichier contenant la carte sans l'extension.
* @var string le nom du fichier de la carte.
*/
private $carte_nom;
 
/**
* @var string le chemin et le nom du fichier de l'image de la carte générée.
*/
private $carte_fichier;
 
/**
* Tableaux associatif contenant les informations sur la carte.
* donnees_date_maj = date de dernière mise à jour des données servant à créer la carte, si plus récente que la carte
* déjà créée getCarteCache renvoie false.
*
* @var array le tableau des infos sur la carte.
*/
private $carte_info = array();
 
/**
* Indique si la carte existe déjà et à besoin ou pas d'être créée.
* @var bool true si la carte existe..
*/
private $carte_cache = false;
 
/**
* Le nom du fichier de la carte de fond.
* @var string nom du fichier de la carte de fond.
*/
private $carte_fond_fichier;
 
/**
* Le nom du dossier contenant les cartes de fond.
* @var string nom du dossier contenant les cartes de fond.
*/
private $carte_fond_dossier;
 
/**
* Le nom du dossier où stocker les cartes créer via la classe Cartographie.
* @var string nom du dossier contenant les cartes créées.
*/
private $carte_stockage_dossier;
 
/**
* L'url correspondant au dossier où sont stockées les cartes crées via la classe Cartographie.
* L'url est passé à la fonction sprintf est doit donc contennir %s afin d'indiquer l'endroite où ajouter le nom du
* fichier de la carte.
* @var string url des cartes créées.
*/
private $carte_stockage_url;
 
/**
* Format du tableau :
* carte_zone est un tableau de tableaux associatifs.
* Chaque zone de la carte doit avoir son entrée dans ce tableau. Le code de la zone sert de clé.
* Chaque zone est représentée par :
* - nom : (string)
* le nom de la zone qui sera affiché dans l'attribut title de la balise map html.
* - rvb_fond : (string) Exemple : 255-255-255.
* les valeurs entre 0 et 255 séparées par des tirets (-) de la couleur de la zone sur la carte de fond
* Ne pas utiliser le blanc (255-255-255) et utiliser le noir pour les contours (0-0-0).
* - poly : (string)
* les coordonnées pour la balise map html. Si une même zone à plusieurs polygones, les séparer par le
* caractère pipe "|".
* - info_nombre : (int) Exemple : nombre de personnes présentent dans un département.
* nombre d'occurence dans cette zone.
* - url : (string) l'url qui doit être appelée sur un clic dans la zone.
* - rvb_carte : (string) Exemple : 255-255-255.
* les valeurs entre 0 et 255 séparées par des tirets (-) de la couleur de remplacement dans le cas de la formule
* de coloriage de type "légende".
* @var array les informations sur les zones de la carte.
*/
private $carte_zones = null;
 
/**
* Tableau contenant la valeur RVB de la zone du fond de carte en clé et la valeur RVB venant la remplacer en valeur.
* @var array valeur RVB de la zone du fond de carte en clé et valeur RVB venant la remplacer en valeur.
*/
private $carte_correspondance_couleurs = array();
 
/**
* La valeur RVB, sous forme de chaine de nombres séparées par des tirets (-), de la zone géographique à mettre en
* surbrillance.
* @var string la valeur RVB de la zone à repérer.
*/
private $zone_marker;
 
/**
* La formule de coloriage de la carte. Les formules disponibles sont : légende, proportionnel.
* @var string la formule de coloriage.
*/
private $formule_coloriage;
 
/**
* Les valeurs RVB séparés par des virgules pour la couleur la plus foncée utilisée, entre autre, par la formule de
* coloriage "proportionnel".
* @var string les valeurs RVB séparées par des virgules.
*/
private $coloriage_couleur_max;
 
/**
* Les valeurs RVB séparés par des virgules pour la couleur la plus claire utilisée, entre autre, par la formule de
* coloriage "proportionnel".
* @var string les valeurs RVB séparées par des virgules.
*/
private $coloriage_couleur_min;
 
/**
* Contient le nombre de couleurs différentes utilisées par le coloriage pour créer l'image finale.
* @var int le nombre de couleurs.
*/
private $coloriage_couleurs;
 
/**
* Contient le tableau des fréquences et des couleurs correspondantes.
* @var array les frequences et leurs couleurs.
*/
private $coloriage_tableau_frequence = array();
 
/**
* Permet de savoir si la cartographie est en mode déboguage ou pas.
* @var bool true si on est en mode débug, sinon false.
*/
private $mode_debug;
 
//+----------------------------------------------------------------------------------------------------------------+
/*** Constructeur : ***/
public function __construct($options = array()) {
// Initialisation de l'objet Cartographie
$this->setCarteNom(isset($options['carte_nom']) ? $options['carte_nom'] : '');
$this->setFormuleColoriage(isset($options['formule']) ? $options['formule'] : '');
$this->setColoriageCouleurClaire(isset($options['couleur_claire']) ? $options['couleur_claire'] : '');
$this->setColoriageCouleurFoncee(isset($options['couleur_foncee']) ? $options['couleur_foncee'] : '');
$this->setCarteFondFichier(isset($options['fond_fichier']) ? $options['fond_fichier'] : '');
$this->setCarteFondDossier(isset($options['fond_dossier']) ? $options['fond_dossier'] : '');
$this->setCarteStockageDossier(isset($options['stock_dossier']) ? $options['stock_dossier'] : '');
$this->setCarteStockageUrl(isset($options['stock_url']) ? $options['stock_url'] : '');
$this->setCarteZones(isset($options['zones']) ? $options['zones'] : null);
$this->setZoneMarker(isset($options['zone_marker']) ? $options['zone_marker'] : '');
$this->setModeDebug(isset($options['debug']) ? $options['debug'] : false);
}
 
//+----------------------------------------------------------------------------------------------------------------+
/*** Accesseur : ***/
public function getTableauFrequence() {
ksort($this->coloriage_tableau_frequence);
return $this->coloriage_tableau_frequence;
}
 
public function getCarteCache() {
// Gestion du cache
if ($this->getCarteNom() != '') {
$fichier_carte = $this->carte_stockage_dossier.$this->getCarteNom().'.png';
if (file_exists($fichier_carte)) {
//echo filemtime($fichier_carte).'-'.strtotime($this->carte_info['donnees_date_maj']);
if (filemtime($fichier_carte) < strtotime($this->carte_info['donnees_date_maj'])) {
$this->carte_cache = false;
} else {
$this->carte_cache = true;
}
}
}
return $this->carte_cache;
}
 
public function getCarteInfo() {
return $this->carte_info;
}
public function setCarteInfo($ci) {
$this->carte_info = $ci;
}
 
public function getColoriageCouleurClaire() {
return $this->coloriage_couleur_min;
}
public function setColoriageCouleurClaire($ccmi) {
$this->coloriage_couleur_min = $ccmi;
}
 
public function getColoriageCouleurFoncee() {
return $this->coloriage_couleur_max;
}
public function setColoriageCouleurFoncee($ccma) {
$this->coloriage_couleur_max = $ccma;
}
 
public function getFormuleColoriage() {
return $this->formule_coloriage;
}
public function setFormuleColoriage($fc) {
$this->formule_coloriage = $fc;
}
 
public function getCarteNom() {
return $this->carte_nom;
}
public function setCarteNom($cn) {
$this->carte_nom = $cn;
}
 
public function getCarteFichier() {
return $this->carte_fichier;
}
public function setCarteFichier($cf) {
$this->carte_fichier = $cf;
}
 
public function getCarteFondFichier() {
return $this->carte_fond_fichier;
}
public function setCarteFondFichier($cff) {
$this->carte_fond_fichier = $cff;
}
 
public function getCarteFondDossier() {
return $this->carte_fond_dossier;
}
public function setCarteFondDossier($cfd) {
$this->carte_fond_dossier = $cfd;
}
 
public function getCarteStockageDossier() {
return $this->carte_stockage_dossier;
}
public function setCarteStockageDossier($csd) {
$this->carte_stockage_dossier = $csd;
}
 
public function getCarteStockageUrl() {
return $this->carte_stockage_url;
}
public function setCarteStockageUrl($csu) {
$this->carte_stockage_url = $csu;
}
 
public function getCarteZones() {
if (is_null($this->carte_zones)) {
$this->chargerZones();
}
return $this->carte_zones;
}
public function setCarteZones($cz) {
$this->carte_zones = $cz;
}
 
public function getZoneMarker() {
return $this->zone_marker;
}
public function setZoneMarker($zm) {
$this->zone_marker = $zm;
}
 
public function getModeDebug() {
return $this->mode_debug;
}
public function setModeDebug($md) {
$this->mode_debug = $md;
}
 
//+----------------------------------------------------------------------------------------------------------------+
/*** Méthodes PUBLIQUES : ***/
 
public function creerCarte() {
 
if(file_exists($this->getCarteFichier())) {
//echo 'suppression du fichier de carte : '.$this->getCarteFichier();
//unlink($this->getCarteFichier());
}
 
// Création de la carte car aucun cache ou cache à vider
$carte_fond_fichier = $this->carte_fond_dossier.$this->getCarteFondFichier().'.png';
$this->carte = imagecreatefrompng($carte_fond_fichier);
// Vérification que la création à fonctionnée
if (!$this->carte) {
// Une erreur est survenue : création d'une image blanche
$this->carte = imagecreatetruecolor(520, 60);
$bgc = imagecolorallocate($this->carte, 255, 255, 255);
$tc = imagecolorallocate($this->carte, 0, 0, 0);
imagefilledrectangle($this->carte, 0, 0, 520, 60, $bgc);
// Affichage d'un message d'erreur
imagestring($this->carte, 1, 5, 5, "Erreur de chargement de l'image :", $tc);
imagestring($this->carte, 1, 5, 15, $carte_fond_fichier, $tc);
} else {
// Nous construisons le tableau de correspondance entre les couleurs présente sur l'image de fond
// et les couleurs qui doivent les remplacer.
$this->construireCorrespondanceCouleur();
 
// Nous lançons la création de la carte
$this->colorierCarte();
}
 
// Nous chercons à créer une image indéxées en sortie
if (imageistruecolor(&$this->carte) && $this->formule_coloriage != 'legende') {
if ($this->coloriage_couleurs <= 253) {
//imagetruecolortopalette(&$this->carte, false, ($this->coloriage_couleurs + 2));// + 2 car noir et blanc réservés.
} else {
// On force la création d'une palette... si cela pose problème ajouter un attribut permettant de désactiver
// ce fonctionnement.
imagetruecolortopalette(&$this->carte, false, 255);
}
}
 
// Nous écrivons le fichier de la carte.
if ($this->getCarteNom() == '') {
$this->setCarteNom(md5($this->carte));
}
 
$this->setCarteFichier($this->carte_stockage_dossier.$this->getCarteNom().'.png');
imagepng(&$this->carte, $this->getCarteFichier());
return true;
}
 
public function getImageMap() {
// Initialisation de variables
$carte_map = '';
 
// Gestion de l'image map
$chemin_carte_map_fond = $this->getCarteFondDossier().$this->getCarteFondFichier().'.tpl.html';
$chemin_carte_map = $this->getCarteStockageDossier().$this->getCarteNom().'.html';
 
if (file_exists($chemin_carte_map)) {
$carte_map = file_get_contents($chemin_carte_map);
} else {
$nom_carte_png = $this->getCarteNom().'.png';
$chemin_carte_png = $this->getCarteStockageDossier().$nom_carte_png;
$donnees['carte_url'] = sprintf($this->getCarteStockageUrl(), $nom_carte_png);
$donnees['carte_alt'] = 'info';
$donnees['zones'] = $this->getCarteZones();
//Debug::printr($donnees);
$carte_map = SquelettePhp::analyser($chemin_carte_map_fond, $donnees);
if (!file_put_contents($chemin_carte_map, $carte_map)) {
$e = "Écriture du fichier contenant le html de la carte impossible : $chemin_carte_map";
trigger_error($e, E_USER_WARNING);
}
}
 
return $carte_map;
}
 
//+----------------------------------------------------------------------------------------------------------------+
/*** Méthodes PRIVÉES : ***/
 
/**
* Charge en mémoire les données du fichier csv des zones géographique de la carte
*/
private function chargerZones() {
$fichier_csv = $this->getCarteFondDossier().$this->getCarteFondFichier().'.csv';
$zones = array();
if (($handle = fopen($fichier_csv, 'r')) !== false) {
$ligne = 1;
$cles = array();
while (($donnees = fgetcsv($handle, 1000, ',')) !== false) {
$cle = array_shift($donnees);
if ($ligne == 1) {
// Ligne 1 : les noms des champs
$cles = $donnees;
 
} else {
// Ligne > 1 : traitements des données
$zones[$cle] = array_combine($cles, $donnees);
}
$ligne++;
}
fclose($handle);
}
$this->setCarteZones($zones);
}
 
private function construireCorrespondanceCouleur() {
switch ($this->formule_coloriage) {
case self::FORMULE_LEGENDE :
$this->construireCorrespondanceCouleurLegende();
break;
case self::FORMULE_PROPORTIONNEL :
$this->construireCorrespondanceCouleurProportionnel();
break;
default :
$e = "Aucune formule de coloriage n'a été définie parmis : ".
self::FORMULE_LEGENDE.' et '.self::FORMULE_PROPORTIONNEL.'. '.
"Veuillez la définir avec la méthode setFormuleColoriage().";
trigger_error($e, E_USER_ERROR);
}
}
 
private function construireCorrespondanceCouleurProportionnel() {
// Création d'un tableau contenant seulement les nombres d'information pour chaque zone.
$tab_valeurs = array();
foreach ($this->getCarteZones() as $cle => $valeur) {
//Nous recherchons le minimum, le maximum et le la valeur médium juste au dessous du maximum.
if (isset($valeur['info_nombre'])) {
$tab_valeurs[] = $valeur['info_nombre'];
if ($valeur['info_nombre'] == 0){
//trigger_error($valeur['nom'], E_USER_NOTICE);
}
}
}
 
//Nombre d'entrées dans le tableau de valeurs non nulles :
$valeurs_nbre = count($tab_valeurs);
$valeurs_somme = array_sum($tab_valeurs);
// Tabeau des fréquences trié de la plus petite à la plus grande clé.
$tab_frequences = array_count_values($tab_valeurs);
krsort($tab_frequences);
//trigger_error(print_r($tab_frequences, true), E_USER_NOTICE);
$frequences_nbre = count($tab_frequences);
if ($valeurs_nbre > 0){
// Nous trions le tableau dans l'ordre croissant :
sort($tab_valeurs);
// Nous récupérons la valeur la plus petite :
$mini = $tab_valeurs[0];
$maxi = $tab_valeurs[$valeurs_nbre - 1];
$medium = isset($tab_valeurs[$valeurs_nbre - 2]) ? $tab_valeurs[$valeurs_nbre - 2] : 0;
$moyenne = $valeurs_somme / $valeurs_nbre;
$ecart_au_carre_moyen = 0;
for ($i = 0; $i < $valeurs_nbre; $i++) {
$ecart_au_carre_moyen += pow(($tab_valeurs[$i] - $moyenne), 2);
}
$variance = $ecart_au_carre_moyen / $valeurs_nbre;
$ecart_type = round(sqrt($variance), 0);
$moyenne = round($moyenne, 0);
$variance = round($variance, 0);
}
 
// Calcul de l'écart moyen pour chaque élément R, V et B.
list($r_min, $v_min, $b_min) = explode(',', $this->coloriage_couleur_max);
list($r_max, $v_max, $b_max) = explode(',', $this->coloriage_couleur_min);
$r_diff = $r_min - $r_max;
$r_ecart_moyen = abs($r_diff / $frequences_nbre);
 
$v_diff = $v_min - $v_max;
$v_ecart_moyen = abs($v_diff / $frequences_nbre);
 
$b_diff = $b_min - $b_max;
$b_ecart_moyen = abs($b_diff / $frequences_nbre);
 
// Pour chaque fréquence nous attribuons une couleur.
$i = 1;
foreach ($tab_frequences as $cle => $valeur){
if ($cle == 0) {
$this->coloriage_tableau_frequence[$cle] = '255-255-255';
} else {
$r = $r_min + round(($i * $r_ecart_moyen), 0);
 
$v = $v_min + round(($i * $v_ecart_moyen), 0);
$b = $b_min + round(($i * $b_ecart_moyen), 0);
$this->coloriage_tableau_frequence[$cle] = $r.'-'.$v.'-'.$b;
}
$i++;
}
 
// Attribution du nombre de couleurs utilisé pour réaliser la carte
$this->coloriage_couleurs = count(array_count_values($this->coloriage_tableau_frequence));
//trigger_error('<pre>'.print_r($this->coloriage_couleurs, true).'</pre>', E_USER_ERROR);
 
// Nous attribuons les couleurs à chaque zone géographique
foreach ($this->getCarteZones() as $cle => $zg) {
if (isset($this->coloriage_tableau_frequence[$zg['info_nombre']])) {
$this->carte_correspondance_couleurs[$zg['rvb_fond']] = $this->coloriage_tableau_frequence[$zg['info_nombre']];
} else {
$this->carte_correspondance_couleurs[$zg['rvb_fond']] = '128-128-128';
if ($this->getModeDebug()) {
$e = "La zone ".$zg['nom']." (".$zg['rvb_fond'].") ne possède pas de couleur RVB pour la remplir. ".
"La valeur 128-128-128 lui a été attribué.";
trigger_error($e, E_USER_WARNING);
}
}
}
}
 
private function construireCorrespondanceCouleurLegende() {
$tab_couleurs = array();
foreach ($this->getCarteZones() as $cle => $zg) {
if ($zg['rvb_carte'] != '') {
$this->carte_correspondance_couleurs[$zg['rvb_fond']] = $zg['rvb_carte'];
} else {
$this->carte_correspondance_couleurs[$zg['rvb_fond']] = '128-128-128';
if ($this->getModeDebug()) {
$e = "La zone ".$zg['nom']." (".$zg['rvb_fond'].") ne possède pas d'information pour la légende dans le champ".
" rvb_carte. La valeur 128-128-128 lui a été attribué.";
trigger_error($e, E_USER_WARNING);
}
}
if (!isset($tab_couleurs[$this->carte_correspondance_couleurs[$zg['rvb_fond']]])) {
$tab_couleurs[$this->carte_correspondance_couleurs[$zg['rvb_fond']]] = 1;
}
}
// Attribution du nombre de couleurs utilisé pour réaliser la carte
$this->coloriage_couleurs = count($tab_couleurs);
}
 
private function colorierCarte() {
if (imageistruecolor(&$this->carte)) {
//+--------------------------------------------------------------------------------------------------------+
// Remplacement des couleurs sur la carte en mode vraies couleurs (RGB)
$this->colorierCarteModeVraiCouleur();
} else {
//+--------------------------------------------------------------------------------------------------------+
// Remplacement des couleurs sur la carte en mode couleurs indexées (palette de couleurs)
$this->colorierCarteModeIndexe();
}
}
 
private function colorierCarteModeVraiCouleur() {
// Nous commençons le rempalcement des couleurs sur la carte de fond.
$hauteur = imagesy(&$this->carte);
$largeur = imagesx(&$this->carte);
 
// Tableau contenant les couleurs traitées, pour éviter de traiter plusieurs fois la même couleur
$tab_rvb_ok = array();
for ($x = 0; $x < $largeur; $x++) {
for ($y = 0; $y < $hauteur; $y++) {
$rvb = ImageColorAt(&$this->carte, $x, $y);
if (!isset($tab_rvb_ok[$rvb])) {
// Récupération de la couleur rvb au format xxx-xxx-xxx
$cle = (($rvb >> 16) & 0xFF).'-'.(($rvb >> 8) & 0xFF).'-'.($rvb & 0xFF);
// Si nous n'avons pas à faire à la couleur noire (utilisé pour délimité les zones), nous continuons
if ($cle != '255-255-255') {
$rvb_final = null;
if (isset($this->carte_correspondance_couleurs[$cle])) {
if ($this->zone_marker != '' && $cle == $this->zone_marker) {
$rvb_final = '255'<<16 | '0'<<8 | '0';
} else {
list($rouge, $vert, $bleu) = explode('-', $this->carte_correspondance_couleurs[$cle]);
$rvb_final = $rouge<<16 | $vert<<8 | $bleu;
}
// Si le nombre de couleurs sur la carte finale est infèrieur à 255 nous créons une image indexée
imagefill(&$this->carte, $x, $y, $rvb_final);
} else {
$rvb_final = '128'<<16 | '128'<<8 | '128';
imagefill(&$this->carte, $x, $y, $rvb_final);
}
// Nous ajoutons la couleur ajoutée à la carte dans le tableau des couleurs traitées
$tab_rvb_ok[$rvb_final] = true;
}
// Nous ajoutons la couleur trouvées sur la carte de fond dans le tableau des couleurs traitées
$tab_rvb_ok[$rvb] = true;
}
}
}
}
 
private function colorierCarteModeIndexe() {
// Nous attribuons à chaque zone présente dans le tableau $this->getCarteZones() la valeur de l'index
// de la couleur RVB représentant cette zone sur la carte de fond.
$this->construireAssociationIndexZone();
 
foreach ($this->getCarteZones() as $zg) {
if (isset($this->carte_correspondance_couleurs[$zg['rvb_fond']])) {
 
//Dans le cas où nous voulons repérer une zone sur la carte :
if ($this->getZoneMarker() != '' && $zg['rvb_fond'] == $this->getZoneMarker()) {
$rouge = 255;
$vert = 0;
$bleu = 0;
} else {
list($rouge, $vert, $bleu) = explode('-', $this->carte_correspondance_couleurs[$zg['rvb_fond']]);
}
if (isset($zg['index'])) {
imagecolorset(&$this->carte, $zg['index'], $rouge, $vert, $bleu);
} else if ($this->getModeDebug()) {
$e = "La zone '{$zg['nom']}' n'est pas présente sur la carte.";
trigger_error($e, E_USER_WARNING);
}
}
}
}
 
private function construireAssociationIndexZone() {
// Nous récupérons le nombre de couleur différentes contenues dans l'image.
$taille_palette = imagecolorstotal($this->carte);
// Pour chaque couleur contenue dans l'image, nous cherchons l'objet correspondant
// dans le tableau $this->getCarteZones(), qui contient des informations sur chaque zone de l'image,
// et nous attribuons la valeur de l'index de sa couleur sur la carte de fond.
for ($i = 0; $i < $taille_palette; $i++) {
$rvb = array();
$rvb = imagecolorsforindex($this->carte, $i);
$rvb_cle = $rvb['red'].'-'.$rvb['green'].'-'.$rvb['blue'];
// La couleur ne doit pas correspondre au noir ou au blanc car ces couleurs ne sont pas traitées
if ($rvb_cle != '255-255-255' && $rvb_cle != '0-0-0') {
$index_ok = false;
foreach($this->getCarteZones() as $cle => $zg) {
if (isset($zg['rvb_fond']) && $zg['rvb_fond'] == $rvb_cle) {
$this->carte_zones[$cle]['index'] = $i;
$index_ok = true;
break;
}
}
if (!$index_ok && $rvb_cle != '0-0-0' && $this->getModeDebug()) {
$e = "Aucune information n'est fournie pour la zone sur la carte d'index $i : $rvb_cle";
trigger_error($e, E_USER_WARNING);
//$this->carte_zones[] = array('rvb_fond' => $rvb_cle, 'rvb_carte' => '128-128-128', 'index' => $i);
}
}
}
}
 
}
?>
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/trunk/composants/cartographie/squelettes/pays_nord_amerique.csv
New file
0,0 → 1,24
"code","rvb_fond","nom","poly"
"ag","200-100-0","Antigua et Barbuda","99,370,99,388,106,389,109,388,110,385,107,371"
"bs","200-100-50","Bahamas","400,354,407,377,432,392,436,404,445,401,453,394,432,374,411,351"
"bb","200-100-75","Barbade","128,442,137,443,137,450,133,453,128,449"
"bz","200-100-100","Bélize","348,417,345,419,345,421,341,424,341,438,344,438,348,431,348,422,351,423,350,419"
"ca","200-100-125","Canada","173,194,312,193,338,201,352,197,356,201,366,212,380,224,377,235,373,242,374,244,378,243,395,238,395,234,409,228,413,222,432,221,440,206,449,207,456,223,467,234,493,215,527,210,526,202,496,162,442,120,440,82,367,36,375,20,391,6,366,3,329,8,265,27,238,40,204,63,168,67,126,119,126,121,133,121,132,125,127,124,127,127,134,140,135,148,138,149,138,156,135,161,138,175,152,172,153,179,149,183,162,198,164,199,170,200"
"cr","200-100-150","Costa Rica","363,477,377,479,382,487,382,498,377,497,374,491,365,487,363,486"
"cu","200-100-175","Cuba","368,388,384,380,397,382,407,388,426,397,436,406,428,410,411,410,411,404,390,393,380,398,372,397,369,395,366,393"
"dm","200-100-250","Dominique","449,408,452,415,450,416,451,425,453,426,457,421,459,422,462,420,466,419,467,421,470,420,472,419,472,417,465,412,460,409,457,407"
"sv","200-200-0","Salvador","336,456,338,454,341,451,345,454,350,454,352,460,347,461,342,461"
"us","200-200-100","Etats-Unis","173,194,312,194,335,201,345,205,365,211,377,233,375,240,373,244,384,243,395,239,395,234,408,233,409,226,413,222,434,221,440,205,449,206,451,216,457,224,440,233,442,246,432,250,424,253,423,260,418,274,418,289,414,296,396,311,386,323,392,342,396,353,396,368,390,374,384,374,381,369,387,365,382,352,378,345,378,338,373,332,370,333,359,332,356,328,342,330,340,337,331,339,322,335,309,335,307,342,299,342,296,348,294,363,280,357,278,348,274,343,273,338,270,334,262,332,258,339,249,331,249,326,239,317,230,318,230,321,214,321,193,311,179,311,177,305,163,298,53,309,25,288,34,284,158,280,150,251,153,233,163,199,172,200 6,151,26,111,50,87,70,82,72,72,130,56,173,63,120,126,6,157"
"gd","200-200-125","Grenade","113,457,118,458,116,465,110,465,107,462"
"gl","200-200-250","Groenland","113,457,118,458,116,465,110,465,107,462"
"gt","0-100-200","Guatémala","327,427,331,427,332,424,341,424,341,438,346,441,346,443,343,443,341,451,339,453,336,456,330,455,326,454,325,453,322,450,323,447,323,444,328,438,333,437,333,433"
"ht","50-100-200","Haïti","449,409,451,414,450,415,450,423,446,421,444,422,439,422,438,423,434,419,434,417,440,418,441,417,445,417,443,415,442,411,438,410,442,406"
"hn","75-100-200","Honduras","346,440,346,443,342,447,342,451,345,454,350,454,352,460,356,461,357,455,360,455,362,453,364,453,368,450,368,448,370,447,372,449,379,445,377,443,369,439,347,440"
"jm","100-100-200","Jamaïque","408,418,416,417,425,422,424,426,411,426"
"mx","125-100-200","Mexique","179,311,185,333,194,344,188,347,190,352,195,356,199,357,203,372,214,386,219,384,232,377,242,401,239,409,273,435,301,444,306,439,311,441,323,448,323,444,327,437,333,437,333,433,327,427,331,427,332,424,341,424,348,416,350,418,356,399,355,395,348,394,335,397,326,417,302,416,294,362,281,357,274,343,268,332,261,332,258,339,248,331,248,325,239,316,230,317,229,321,214,322,193,312,179,311"
"ni","150-100-200","Nicaragua","352,461,356,461,357,456,360,456,362,454,364,454,368,451,368,449,370,448,372,449,380,446,379,450,378,456,377,464,377,479,362,477"
"pa","175-100-200","Panama","382,500,382,487,393,495,402,488,413,491,419,497,419,502,418,506,412,508,410,503,411,499,405,495,403,499,398,502,402,506,398,510,394,509,392,508,393,506"
"vc","200-100-200","Saint Vincent et les Grenadines","114,444,120,445,118,452,112,451"
"lc","0-100-100","Sainte Lucie","118,434,115,439,117,443,120,444,123,443,124,438,122,435"
"tt","75-100-100","Trinité et Tobago","108,479,113,476,120,477,122,471,131,472,127,494,109,494,106,489"
"0","255-255-255","",""
/trunk/composants/cartographie/squelettes/pays_sud_amerique.tpl.html
New file
0,0 → 1,12
<div id="cartographie">
<img id="carte-img" src="<?=$carte_url;?>" alt="<?=$carte_alt;?>" usemap="#carte-map" />
<map name="carte-map">
<?php foreach ($zones as $code => $zone) : ?>
<?php if (!empty($zone['poly'])) : ?>
<?php foreach (explode('|', $zone['poly']) as $coords) : ?>
<area shape="poly" title="<?=$zone['nom']?> (<? echo $zone['info_nombre']; if($zone['info_nombre'] > 1) {echo ' inscrits';} else { echo ' inscrit';} ?>)" class="zone-<?=$code?>" href="<?=$zone['url']?>" coords="<?=$coords?>" />
<?php endforeach; ?>
<?php endif; ?>
<?php endforeach; ?>
</map>
</div>
/trunk/composants/cartographie/squelettes/france.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
/trunk/composants/cartographie/squelettes/france.png
New file
Property changes:
Added: svn:executable
+*
\ No newline at end of property
Added: svn:mime-type
+image/png
\ No newline at end of property
/trunk/composants/cartographie/squelettes/pays_afrique.csv
New file
0,0 → 1,57
"code","rvb_fond","nom","poly"
"km","255-150-175","Comores","471,401,469,401,470,403 480,401,480,399,477,400 463,392,460,389,463,385,463,383,461,383,459,386,459,389,464,395"
"ci","255-150-225","Côte d'Ivoire","99,263,110,263,113,264,113,261,111,259,110,249,112,247,112,244,115,240,114,232,110,229,104,229,98,230,94,226,91,225,88,226,87,223,85,223,85,225,75,226,74,230,76,232,77,239,75,240,75,245,73,247,73,253,76,255,77,257,80,259,80,263,79,269,88,265,90,265"
"rw","175-255-150","Rwanda","359,319,364,319,364,315,363,312,361,312,357,313,354,318,354,320,358,321"
"mw","25-250-255","Malawi","396,427,399,423,402,421,402,413,394,404,390,397,388,395,388,393,390,390,390,381,388,379,387,375,385,375,387,382,385,385,385,396,382,399,382,403,381,405,386,410,392,410,394,412,394,419,393,424"
"bf","255-150-25","Burkina Faso","113,225,112,220,140,219,144,215,149,215,150,212,149,208,144,208,141,204,140,201,135,196,135,194,134,191,129,191,127,193,114,202,112,202,108,203,106,204,103,211,97,217,97,219,96,224,99,228,102,228,111,227,113,228"
"sl","125-255-250","Sierra Leone","48,248,50,246,54,243,55,240,54,235,51,230,42,229,36,236,37,240,39,242,43,247,45,247"
"eg","255-250-75","Egypte","389,85,391,84,391,81,393,76,393,71,390,64,390,62,389,59,387,59,377,60,377,63,379,64,379,68,380,72,382,74,385,81 384,86,379,81,377,76,377,74,375,71,375,58,372,56,361,56,359,58,354,60,352,62,349,62,346,60,344,60,337,57,335,57,329,56,327,55,323,56,321,55,320,59,321,66,319,68,319,70,320,74,322,75,322,134,384,134,388,135,391,131,393,131,394,128,399,126,399,118,396,115,387,96,387,94,384,89"
"ga","25-50-255","Gabon","229,316,235,317,237,319,239,314,239,306,238,299,240,296,240,293,236,292,234,294,232,294,231,287,228,287,222,286,219,287,219,294,206,295,206,301,204,302,204,306,202,308,202,311,204,316,207,319,216,329,220,328,220,321"
"bw","255-25-225","Botswana","320,499,324,498,326,493,328,491,334,486,338,481,340,478,347,473,350,472,350,470,345,469,342,467,342,465,341,460,338,457,331,453,327,448,325,443,323,441,322,438,320,438,315,440,311,444,309,443,308,440,303,440,294,442,291,443,291,469,284,470,284,492,289,497,291,500,291,504,290,507,297,508,305,501,308,497,315,497,318,499"
"ug","25-255-150","Ouganda","361,309,371,309,371,307,372,304,374,302,377,300,382,300,385,299,389,300,390,297,392,295,396,290,396,284,391,278,391,274,388,273,386,275,379,275,373,276,368,275,366,278,366,282,369,285,369,287,366,290,364,291,364,293,360,298,358,307,358,311"
"sz","151-151-75","Swaziland","371,511,373,509,373,503,369,502,366,507,367,511"
"ls","75-150-255","Lesotho","350,536,352,534,353,530,351,528,349,525,346,525,340,530,339,535,343,540,347,537"
"et","255-250-175","Ethiopie","448,272,450,270,452,270,455,269,458,266,463,264,471,264,482,253,491,245,491,243,484,243,475,239,473,239,466,236,464,236,456,228,454,225,454,221,449,222,447,220,447,217,449,212,449,209,446,206,443,202,441,201,437,196,431,195,429,194,421,195,418,193,416,196,408,196,408,201,406,206,401,210,397,217,397,220,391,225,391,238,389,240,384,241,384,243,387,244,390,247,392,250,396,253,396,255,399,260,402,261,404,263,404,267,408,267,421,274,423,274,430,275,434,271,436,271,442,270,445,272"
"cg","175-151-151","Congo","219,332,223,336,224,338,229,334,233,337,235,337,238,334,241,334,242,337,244,337,253,329,254,321,256,316,258,314,260,311,266,306,266,300,267,292,268,287,272,280,272,277,266,277,261,276,255,282,255,289,252,290,249,288,246,288,234,287,233,291,239,290,242,293,242,297,240,300,240,304,241,317,240,320,236,321,234,319,230,319,228,318,226,320,222,323,222,329,219,330"
"mr","25-255-50","Mauritanie","44,189,46,187,47,183,51,182,54,186,56,186,58,184,92,184,93,180,90,178,90,169,87,141,87,139,85,122,85,119,84,110,93,109,92,107,85,103,83,101,76,97,74,95,71,94,71,101,47,102,47,122,44,124,41,124,38,126,38,139,8,140,9,142,13,145,14,152,13,156,15,159,15,167,12,174,12,176,19,176,27,175,31,179,34,179,37,184,42,189"
"sd","151-151-25","Soudan","377,274,385,273,392,267,402,267,402,264,397,261,394,256,394,254,392,252,389,250,386,246,384,246,381,244,381,242,383,239,386,239,389,237,389,224,391,222,392,220,395,219,395,216,398,211,400,209,405,203,405,200,406,189,409,179,409,177,410,173,413,172,415,170,420,168,421,165,414,160,412,157,412,142,410,140,409,135,404,130,401,128,399,128,396,129,395,132,392,133,390,135,389,137,384,137,322,136,322,150,315,151,315,183,313,185,307,185,307,187,303,192,300,205,303,207,303,211,307,218,307,221,311,226,312,233,311,235,314,236,317,239,320,239,324,242,324,245,331,250,333,252,333,254,334,256,339,259,342,264,344,266,345,268,354,268,357,267,360,270,365,274,373,273"
"bi","255-150-75","Burundi","361,331,364,326,364,324,362,323,362,321,360,321,359,323,355,324,355,329,354,335,359,333"
"zm","75-151-151","Zambie","335,437,340,430,342,428,345,426,348,426,348,422,355,419,359,419,359,415,362,413,364,413,371,410,373,410,378,408,380,399,383,395,383,384,385,382,385,380,378,372,376,372,373,371,370,368,368,368,366,369,361,365,359,365,354,366,352,369,352,381,350,388,350,391,352,393,357,393,358,401,351,402,345,397,344,395,342,395,338,392,329,392,324,389,323,387,317,387,316,385,315,399,300,400,300,426,302,429,308,434,320,433,323,436,326,436"
"gm","75-50-255","Gambie","15,202,22,200,20,199,18,201,11,201"
"dz","255-25-75","Algérie","149,147,151,147,153,149,155,149,158,150,159,157,161,157,171,154,173,154,178,152,181,149,194,139,201,135,203,133,212,128,215,125,218,124,220,122,220,120,216,115,210,114,208,112,208,110,207,107,205,105,203,102,203,99,206,96,206,81,205,74,203,72,202,66,203,60,202,54,201,51,196,48,195,44,192,41,190,40,189,32,191,30,195,27,195,25,196,7,191,7,188,6,185,7,182,6,179,8,177,8,173,9,170,7,164,7,158,8,155,10,147,10,138,14,135,17,131,17,125,22,122,23,122,29,123,39,124,42,127,45,126,49,114,50,112,53,110,53,107,54,107,57,108,60,99,64,94,69,90,69,86,70,85,72,81,72,79,74,77,74,71,79,71,91,78,95,80,97,87,101,90,104,97,108,99,110,106,114,109,117,116,121,118,123,143,140,144,143"
"dj","255-250-25","Djibouti","456,217,454,216,454,214,457,212,457,209,455,208,451,212,451,214,449,217,449,220,452,220,455,219"
"lr","125-150-255","Libéria","78,260,75,258,74,256,71,255,70,252,71,249,69,248,66,249,63,247,63,242,62,240,58,240,55,245,52,248,50,249,53,254,56,255,58,257,65,263,72,267,75,267,77,268,77,263"
"tg","151-151-225","Togo","144,256,146,255,146,236,142,227,139,225,139,221,136,221,135,223,138,226,138,229,139,241,140,251"
"cv","25-100-150","Cap Vert","58,349,58,346,56,345,56,348 66,335,65,335 46,328,45,328"
"tz","151-151-125","Tanzanie","432,377,432,375,428,366,428,363,429,354,425,350,425,345,428,338,426,336,419,332,417,330,417,328,416,325,413,324,411,322,406,320,404,318,399,316,397,314,394,313,392,311,390,311,390,313,387,316,387,320,385,322,383,322,379,323,376,322,374,324,372,323,371,314,372,311,365,311,365,313,366,319,365,323,366,327,361,334,356,337,354,340,354,342,355,350,357,352,360,356,363,358,364,364,365,366,367,366,369,365,371,367,374,369,376,369,385,373,388,373,389,377,392,380,392,391,394,391,403,387,405,387,407,389,416,388,418,386,427,386,434,383,436,381"
"gw","175-50-255","Guinée Bissau","23,219,23,217,25,215,30,214,30,210,31,208,20,208,14,209,13,211,16,213,20,213,21,215,20,218"
"mz","75-255-50","Mozambique","372,472,372,479,374,488,374,500,375,507,379,508,379,506,377,504,377,501,379,500,381,497,390,493,392,493,398,488,398,485,397,483,399,476,399,473,397,471,397,469,395,462,393,460,393,454,398,449,402,446,403,444,405,444,407,442,407,440,409,439,411,436,420,431,423,431,428,427,430,426,436,419,436,415,437,410,436,395,435,390,438,385,438,383,437,383,433,386,431,386,428,388,419,388,417,390,410,390,406,391,401,390,392,394,391,396,394,399,397,404,400,407,404,412,404,422,401,425,399,426,399,429,396,430,391,425,390,421,392,418,392,413,385,412,382,409,363,415,361,416,361,418,362,422,370,422,379,426,381,428,381,430,382,442,380,447,381,456,378,461,378,463,376,466,376,468"
"zw","225-151-151","Zimbabwe","349,467,352,469,356,469,361,471,367,471,370,472,373,468,379,455,379,451,378,445,380,440,380,433,379,429,377,427,373,426,370,424,362,424,359,421,355,421,352,423,350,423,350,427,346,428,344,430,340,433,337,437,336,439,326,439,324,438,327,442,330,449,333,452,336,453,339,456,343,459,343,463,344,466"
"gq","225-50-255","Guinée équatoriale","217,293,217,287,208,287,206,292"
"cd","125-255-150","République Démocratique du Congo","317,383,318,385,323,385,326,388,331,390,333,390,337,389,339,391,343,392,346,394,350,399,356,400,356,395,351,395,347,391,347,388,350,378,350,368,353,364,356,364,361,363,361,359,359,357,355,354,353,349,353,344,352,329,353,325,351,322,351,319,356,310,356,303,357,299,359,297,362,293,362,290,366,287,366,285,364,283,364,278,365,276,358,270,349,270,346,271,343,269,340,265,332,265,330,264,319,266,315,266,312,268,305,268,303,271,294,271,288,270,286,268,284,265,280,265,276,269,276,274,274,276,274,281,270,288,270,293,268,304,268,307,264,311,260,314,257,319,257,321,256,327,255,330,249,336,244,339,241,339,240,336,237,337,235,339,230,339,229,346,231,346,257,345,260,348,260,351,263,358,266,361,277,361,280,354,290,353,291,355,296,355,298,357,298,362,299,376,300,385,303,383"
"so","175-255-250","Somalie","443,281,443,309,445,312,447,312,456,301,462,295,470,288,477,285,480,282,483,278,491,271,492,268,494,266,500,259,500,257,503,250,505,248,506,243,510,239,513,234,513,230,514,226,516,225,516,215,513,214,512,216,508,217,513,214,510,217,508,217,499,219,497,219,490,220,483,223,476,223,471,226,466,226,459,219,456,221,456,224,458,226,465,234,467,234,476,238,478,238,485,241,494,241,495,243,472,266,463,266,458,269,456,271,454,271,451,272,448,275"
"td","151-151-175","Tchad","257,243,259,243,262,244,267,241,273,241,276,238,276,235,285,233,287,233,294,226,296,225,296,222,298,220,303,219,304,217,301,212,301,208,298,208,297,204,298,199,300,196,300,193,302,191,305,186,305,184,311,183,313,182,313,155,262,129,260,127,255,125,252,125,249,126,248,139,249,142,251,144,254,146,254,149,252,154,252,158,250,173,250,175,244,181,238,188,237,192,235,193,236,198,240,202,243,204,245,207,245,209,246,220,249,224,249,228,241,229,241,232,242,234,244,234,247,237,249,244,250,246,255,245"
"ly","175-150-255","Libye","317,67,319,65,319,62,318,56,319,52,315,52,306,50,305,46,298,44,294,44,290,45,286,49,284,50,284,52,283,54,285,59,282,64,279,66,273,66,270,63,263,60,260,60,255,59,252,58,248,54,247,49,238,45,235,45,224,44,220,43,220,47,217,50,210,56,210,58,211,62,208,65,205,66,204,69,207,73,207,80,208,96,205,100,209,107,209,109,210,112,214,112,219,115,222,120,238,121,245,125,247,125,252,123,256,123,313,152,313,150,320,149,320,76,318,74,318,71"
"er","255-250-125","Erythrée","451,208,454,207,453,205,450,203,447,199,445,198,441,193,439,193,437,191,435,191,433,189,433,187,431,187,428,185,426,180,426,178,424,171,423,169,416,172,415,174,422,169,413,174,411,179,411,181,408,191,408,194,411,194,413,193,415,194,416,191,419,190,422,193,424,193,430,192,436,193,438,195,442,198,443,200,448,204"
"mg","225-150-255","Madagascar","462,479,462,481,463,484,462,486,463,490,468,495,471,497,474,497,477,495,480,495,485,493,489,484,489,481,493,468,493,466,501,441,501,436,504,429,504,421,506,420,508,421,508,405,504,398,502,397,501,399,497,401,498,406,494,409,492,409,492,412,491,416,487,417,487,419,482,422,482,425,479,426,476,425,474,427,468,427,467,431,464,436,465,443,464,445,467,449,468,453,465,456,465,459,464,463,460,468,459,475"
"ma","125-250-255","Maroc","38,123,43,122,45,121,45,101,69,100,69,78,74,73,78,72,80,70,84,70,86,68,89,68,93,67,99,61,101,61,105,58,105,53,110,51,113,48,124,48,125,45,123,44,121,39,121,31,120,26,117,24,115,24,112,22,110,22,100,23,98,21,96,20,94,17,92,19,93,17,91,19,91,21,86,32,84,34,80,37,73,40,68,45,67,50,64,53,62,58,62,63,63,68,59,75,56,78,51,81,48,84,38,87,38,89,36,91,35,95,33,97,30,98,28,100,25,110,23,112,16,122,15,127,12,132,10,133,10,135,9,138,36,138,36,126"
"st","25-255-250","Sao Tomé et Principe","182,299,182,296,181,296,180,300"
"tn","25-151-151","Tunisie","214,49,218,46,218,41,214,38,210,37,207,35,207,32,209,31,213,26,215,25,216,19,213,17,212,11,215,8,211,8,210,5,204,4,198,9,198,25,197,28,195,30,191,33,191,37,192,39,196,42,197,46,202,49,204,56,204,59,205,64,208,62,208,55"
"cf","75-255-150","République Centrafricaine","288,267,292,267,295,269,302,269,305,265,307,265,311,266,316,264,322,264,331,262,339,263,336,259,333,258,331,255,331,253,328,250,322,245,322,243,319,241,316,241,313,238,311,238,309,236,309,232,310,229,305,222,301,221,298,223,298,226,290,233,287,235,284,235,278,236,278,239,274,243,267,243,265,245,256,246,253,248,250,248,244,259,244,266,249,275,253,279,255,279,259,275,266,274,271,275,274,273,274,269,278,265,279,263,285,263"
"ng","225-255-50","Nigéria","219,253,224,242,224,240,229,235,229,232,231,225,233,222,233,220,237,216,240,215,241,211,239,209,239,204,235,200,233,200,231,202,229,202,227,204,224,204,211,203,209,205,206,207,200,207,193,203,191,203,188,206,186,206,183,203,178,200,170,200,167,201,165,204,165,206,162,209,162,218,163,224,162,228,159,231,159,233,156,240,156,254,167,254,172,257,176,264,176,266,177,268,184,269,187,267,189,267,194,268,196,265,198,264,198,262,199,258,201,256,204,252,205,250,214,250,217,253"
"ne","175-255-50","Niger","165,200,170,198,178,198,183,201,185,203,188,203,191,201,194,201,198,204,200,204,205,205,209,202,224,201,226,202,233,197,234,196,233,192,235,191,235,189,238,186,245,178,248,174,248,166,249,157,250,152,252,147,250,145,248,144,246,139,246,127,243,127,240,124,222,123,220,125,213,129,211,131,204,135,202,137,195,141,193,143,180,153,177,155,175,155,168,157,166,158,166,182,162,185,161,187,144,187,143,189,137,190,136,193,139,198,143,202,146,206,150,206,151,211,153,211,153,209,155,208,159,211,160,208,163,205,163,203"
"mu","175-250-255","Maurice","557,460,557,456,556,456,555,460 594,455,593,455"
"cm","255-150-125","Cameroun","229,284,246,285,250,286,252,288,253,282,247,276,246,273,244,271,242,266,242,257,244,255,248,246,246,241,246,239,245,237,242,236,239,233,238,229,240,227,247,227,247,225,244,221,244,211,243,208,241,207,243,210,243,215,236,220,232,229,232,232,231,236,226,241,226,243,220,254,216,255,213,252,206,252,202,257,201,263,199,265,199,267,201,268,202,271,206,272,207,275,209,277,209,282,208,285,219,285"
"bj","255-25-175","Bénin","152,255,154,254,154,238,156,235,156,233,157,230,160,228,160,225,161,220,160,215,156,211,152,215,155,211,151,215,150,217,145,217,142,220,141,224,144,226,146,229,146,231,148,236,148,253,149,255"
"sc","100-255-250","Seychelles","572,342,572,340,570,340,569,342"
"ke","25-150-255","Kenya","426,334,430,335,434,328,434,326,437,321,440,319,442,316,444,315,443,312,441,310,441,281,444,278,446,275,441,272,438,272,435,273,432,276,423,277,419,276,406,269,393,269,392,272,394,279,398,282,398,290,394,295,390,302,392,304,392,307,391,309,398,312,400,314,403,315,405,317,410,319,412,321,415,322,418,325,419,329,421,331,424,332"
"sn","75-255-250","Sénégal","10,204,10,208,12,208,25,206,36,206,41,208,48,208,48,204,44,201,44,196,43,191,41,191,34,184,33,181,30,181,26,177,21,177,11,178,11,185,7,190,7,193,9,195,10,198,17,199,19,197,22,197,31,199,33,200,33,202,25,203,20,202,15,204"
"na","125-255-50","Namibie","282,470,284,468,289,468,289,442,292,440,296,440,305,438,309,438,310,440,312,440,314,438,318,437,319,435,312,435,307,436,302,438,300,438,289,439,276,438,271,434,237,434,234,431,229,431,224,432,222,434,222,436,223,440,230,450,239,469,241,471,243,482,243,488,245,493,245,498,249,515,251,517,256,523,258,523,260,521,262,521,266,524,267,527,276,527,278,525,281,524"
"gn","125-151-151","Guinée","72,245,73,242,72,239,75,238,75,235,72,231,72,227,73,225,71,223,71,220,70,217,67,215,67,212,66,210,61,212,57,212,54,213,49,212,48,210,40,210,33,208,33,214,31,216,28,216,25,218,25,221,27,223,28,226,32,229,35,233,37,233,39,231,40,228,51,227,54,230,56,235,56,238,62,238,65,241,65,246,67,247,69,245"
"ao","255-25-125","Angola","271,432,273,434,278,436,289,436,298,437,305,435,298,427,298,399,313,398,313,385,303,385,302,387,299,387,297,370,297,363,296,357,290,357,289,355,282,355,279,362,268,363,266,364,261,359,258,352,258,349,256,347,233,347,228,349,229,352,231,354,231,356,234,363,234,366,235,368,233,371,234,376,236,378,238,381,238,387,237,394,235,396,234,398,231,399,231,401,228,404,228,406,226,415,222,424,222,431,231,429,234,429,238,432"
"ao","255-25-125","Angola","226,343,227,340,226,340"
"ml","75-250-255","Mali","83,224,85,221,88,221,89,223,94,223,94,219,97,214,102,209,102,207,105,202,110,201,117,198,120,195,125,191,128,189,136,189,141,188,144,185,160,185,164,180,164,158,158,159,157,152,155,152,151,149,148,149,144,145,141,143,141,141,113,122,111,120,104,116,102,114,98,111,86,111,86,118,87,129,89,146,89,148,92,176,93,178,95,179,95,183,93,186,59,186,55,189,53,189,51,187,51,185,49,184,48,188,45,191,45,194,46,200,50,203,50,210,53,210,55,211,61,210,64,208,67,208,69,211,69,213,72,216,72,218,73,223,76,224,78,223"
"gh","125-50-255","Ghana","120,266,125,263,128,263,135,259,141,259,142,257,139,254,137,231,136,227,133,224,133,221,114,221,114,224,116,235,116,237,117,241,115,243,114,248,112,250,112,256,115,260,115,265,117,265"
"0","255-255-255,"0","0","0","287,577,285,579,279,579,276,576,273,574,271,574,270,568,268,566,266,563,270,558,270,556,269,552,267,550,259,533,259,531,255,524,249,519,246,514,246,510,244,503,244,500,243,493,241,488,241,479,240,474,235,465,233,463,232,459,225,446,223,444,220,439,220,423,222,420,222,418,224,413,224,411,225,406,229,399,231,397,233,396,235,393,235,388,236,382,232,377,232,374,231,370,232,363,225,348,225,346,224,342,220,335,218,333,215,331,211,326,206,322,202,317,202,315,200,312,200,310,199,308,202,305,202,301,204,296,204,294,203,292,205,289,205,286,206,281,207,278,205,276,205,274,203,274,200,272,199,270,196,269,190,270,187,269,185,271,178,271,174,267,174,265,173,262,170,259,169,257,167,257,153,256,147,257,144,258,141,261,136,261,129,265,127,265,120,268,117,268,110,265,97,265,88,267,81,271,78,271,73,269,71,269,67,266,64,265,56,257,54,257,48,251,41,248,40,246,36,243,34,240,34,234,30,231,30,229,27,228,24,223,20,220,18,219,18,215,15,215,8,210,8,204,7,202,9,200,5,193,3,193,2,191,4,189,8,186,9,177,13,164,13,159,11,157,10,154,12,152,12,148,11,146,9,145,8,143,6,142,6,140,7,135,11,130,13,125,13,123,15,121,16,118,18,116,23,109,23,107,27,98,31,95,33,94,36,87,39,84,42,84,49,81,54,76,58,73,59,70,61,68,61,65,60,56,63,51,65,49,65,46,67,44,72,38,81,34,84,31,87,26,87,24,90,17,92,15,95,15,97,17,99,20,107,21,113,20,116,22,120,22,123,21,128,16,134,15,137,12,144,9,146,9,154,8,157,6,162,6,172,5,174,7,178,6,181,4,185,4,187,5,191,4,199,5,202,2,1,2,1,580,599,580,599,2,211,2,212,6,217,4,218,8,216,11,214,12,214,14,215,16,218,18,218,23,217,26,211,31,209,34,216,36,217,39,219,39,224,42,235,42,244,46,246,46,249,49,249,51,253,56,255,56,264,58,269,60,273,64,279,64,281,62,282,56,281,51,288,44,293,42,301,42,306,44,307,48,310,48,316,49,320,50,323,54,329,53,335,54,342,57,344,57,347,59,349,59,351,60,355,57,362,54,373,54,375,56,378,58,385,58,388,56,391,58,391,60,394,67,394,69,396,74,393,84,390,88,383,82,382,78,380,77,382,82,386,86,386,89,388,91,389,96,391,101,393,103,398,114,402,118,401,125,404,128,411,134,411,137,414,141,414,156,415,159,418,160,421,163,423,164,424,167,426,169,426,171,428,180,431,185,434,185,435,188,438,189,440,191,442,191,446,195,447,197,452,201,454,204,459,208,460,212,457,215,463,220,465,223,470,224,477,220,484,221,486,219,496,218,509,215,513,212,517,213,518,224,519,226,516,227,516,230,515,235,513,237,510,242,508,244,508,247,506,249,502,258,502,260,495,267,493,272,489,276,481,283,478,287,471,290,467,294,453,307,447,314,444,318,442,319,441,321,438,323,433,334,430,337,430,339,427,346,427,349,429,351,432,355,431,363,430,365,432,368,432,370,435,377,439,380,440,385,438,390,438,408,440,413,438,416,438,420,433,425,430,429,426,432,421,433,412,438,405,447,403,447,395,455,395,459,397,461,397,463,399,470,401,472,401,478,400,488,395,494,388,496,381,500,379,502,381,504,381,511,379,518,379,520,378,523,369,532,362,545,353,554,344,564,338,569,331,571,327,571,327,573,325,574,322,573,320,575,314,574,310,573,305,574,301,573,297,576"
"0","255-255-255,"0","0","0","88,391,88,323,25,323,25,391"
"za","255-25-25","Afrique du Sud","284,577,286,575,295,575,300,571,305,571,308,572,314,571,320,572,325,571,326,569,332,569,337,567,341,563,346,559,348,558,355,549,360,544,361,541,363,539,364,536,366,534,367,531,376,522,376,519,378,512,378,510,375,510,371,514,367,513,365,511,364,507,366,502,369,499,372,500,372,487,370,478,369,475,366,473,359,473,353,472,351,474,346,476,343,479,339,482,335,487,334,489,328,494,326,499,321,501,317,501,314,499,309,499,305,503,300,509,289,510,288,504,289,500,285,496,284,524,277,529,267,529,264,526,262,523,259,525,259,527,265,540,265,542,268,546,271,553,271,555,272,559,269,563,273,570,273,572,275,572,276,574,278,574,280,577"
/trunk/composants/cartographie/squelettes/.directory
New file
0,0 → 1,2
[Dolphin]
Timestamp=2010,5,12,18,42,59
/trunk/composants/cartographie/squelettes/pays_oceanie.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
/trunk/composants/cartographie/squelettes/pays_oceanie.png
New file
Property changes:
Added: svn:mime-type
+image/png
\ No newline at end of property
/trunk/composants/cartographie/squelettes/continents.tpl.html
New file
0,0 → 1,12
<div id="cartographie">
<img id="carte-img" src="<?=$carte_url;?>" alt="<?=$carte_alt;?>" usemap="#carte-map" />
<map name="carte-map">
<?php foreach ($zones as $code => $zone) : ?>
<?php if (!empty($zone['poly'])) : ?>
<?php foreach (explode('|', $zone['poly']) as $coords) : ?>
<area shape="poly" title="<?=$zone['nom']?> (<? echo $zone['info_nombre']; if($zone['info_nombre'] > 1) {echo ' inscrits';} else { echo ' inscrit';} ?>)" class="zone-<?=$code?>" href="<?=$zone['url']?>" coords="<?=$coords?>" />
<?php endforeach; ?>
<?php endif; ?>
<?php endforeach; ?>
</map>
</div>
/trunk/composants/cartographie/squelettes/pays_europe.csv
New file
0,0 → 1,0
"code","rvb_fond","nom","poly"
/trunk/composants/cartographie/squelettes/pays_moyen_orient.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
/trunk/composants/cartographie/squelettes/pays_moyen_orient.png
New file
Property changes:
Added: svn:mime-type
+image/png
\ No newline at end of property
/trunk/composants/cartographie/squelettes/pays_nord_amerique.tpl.html
New file
0,0 → 1,12
<div id="cartographie">
<img id="carte-img" src="<?=$carte_url;?>" alt="<?=$carte_alt;?>" usemap="#carte-map" />
<map name="carte-map">
<?php foreach ($zones as $code => $zone) : ?>
<?php if (!empty($zone['poly'])) : ?>
<?php foreach (explode('|', $zone['poly']) as $coords) : ?>
<area shape="poly" title="<?=$zone['nom']?> (<? echo $zone['info_nombre']; if($zone['info_nombre'] > 1) {echo ' inscrits';} else { echo ' inscrit';} ?>)" class="zone-<?=$code?>" href="<?=$zone['url']?>" coords="<?=$coords?>" />
<?php endforeach; ?>
<?php endif; ?>
<?php endforeach; ?>
</map>
</div>
/trunk/composants/cartographie/squelettes/france.csv
New file
0,0 → 1,108
"code","rvb_fond","nom","poly"
"01","0-204-51","Ain","483,314, 486,313, 489,308, 489,305, 491,303, 493,302, 494,298, 495,296, 492,293, 487,299, 484,303, 478,303, 477,301, 474,301, 472,303, 468,304, 467,301, 463,298, 462,296, 460,295, 459,293, 456,291, 451,292, 448,291, 447,296, 445,299, 445,302, 443,309, 443,311, 444,313, 443,322, 446,323, 449,326, 450,329, 457,329, 459,331, 462,331, 465,326, 467,326, 468,329, 475,336, 476,339, 478,339, 482,332, 482,330, 484,321, 484,319"
"02","240-240-255","Aisne","389,160, 394,155, 395,150, 393,147, 393,145, 396,142, 395,135, 400,132, 402,132, 404,130, 406,130, 408,131, 409,127, 408,125, 409,117, 415,112, 415,102, 414,98, 408,98, 406,95, 402,95, 395,94, 393,95, 391,94, 388,96, 384,95, 391,94, 388,96, 384,95, 379,96, 379,99, 377,102, 377,104, 375,105, 375,109, 376,113, 378,115, 378,117, 377,120, 378,124, 377,126, 379,129, 375,136, 373,136, 375,138, 375,140, 377,143, 377,147, 379,149, 379,152, 386,159"
"03","255-125-125","Allier","393,320, 397,320, 400,323, 402,321, 404,321, 405,314, 404,305, 409,299, 409,294, 406,294, 403,292, 401,292, 399,290, 399,287, 398,284, 395,283, 392,285, 390,285, 388,283, 382,283, 380,284, 377,281, 373,278, 370,278, 367,282, 362,282, 359,285, 360,289, 356,293, 349,293, 347,296, 352,302, 355,304, 358,311, 358,314, 361,314, 364,310, 366,310, 368,307, 370,307, 372,312, 375,315, 377,315, 379,317, 387,317, 389,318, 391,317"
"04","51-51-153","Alpes-de-Haute-Provence","491,443, 494,442, 496,444, 499,444, 500,442, 502,442, 505,438, 509,441, 512,441, 512,439, 519,438, 522,437, 523,434, 527,433, 528,431, 530,431, 528,428, 524,425, 524,422, 522,420, 522,415, 525,411, 525,409, 527,407, 530,406, 530,403, 531,401, 528,398, 528,396, 531,394, 531,390, 530,390, 526,394, 521,398, 520,402, 514,403, 512,401, 509,399, 503,404, 501,404, 500,402, 498,402, 492,408, 491,412, 488,413, 488,415, 489,417, 482,418, 482,420, 477,421, 476,425, 478,426, 478,429, 477,431, 479,433, 481,434, 480,438, 482,438, 484,440, 487,442, 489,442"
"05","51-51-204","Hautes-Alpes","478,409, 480,412, 482,413, 482,417, 488,417, 487,413, 490,412, 490,410, 493,405, 498,401, 500,401, 501,403, 503,403, 504,401, 508,398, 515,402, 519,402, 519,400, 520,397, 529,390, 531,388, 535,387, 533,380, 527,379, 525,377, 523,376, 522,370, 520,370, 518,368, 518,365, 517,365, 512,367, 511,369, 506,369, 505,366, 502,367, 501,371, 505,371, 507,376, 507,380, 505,381, 503,380, 498,381, 495,383, 493,383, 492,386, 487,387, 487,390, 485,393, 483,393, 480,394, 479,398, 480,401, 478,403, 475,403, 473,402, 474,405, 472,406, 473,408, 475,408"
"06","51-51-102","Alpes-Maritimes","550,442, 551,440, 553,440, 555,437, 557,436, 556,431, 558,430, 559,427, 562,425, 562,422, 564,420, 562,417, 562,414, 557,417, 554,417, 550,418, 546,417, 539,413, 535,413, 534,410, 532,409, 531,407, 529,407, 526,409, 526,411, 524,413, 523,420, 525,422, 525,425, 531,430, 530,432, 528,432, 527,434, 524,434, 523,440, 525,440, 528,442, 528,445, 529,447, 533,447, 534,450, 539,450, 542,449, 542,445, 547,441"
"07","0-102-51","Ardèche","422,413, 424,413, 427,411, 431,411, 434,410, 438,413, 440,413, 441,407, 443,405, 443,399, 445,396, 445,388, 448,384, 448,381, 449,377, 447,374, 448,371, 446,369, 446,364, 445,362, 446,358, 443,356, 440,357, 439,361, 437,363, 434,363, 432,365, 432,368, 429,370, 429,372, 426,375, 424,378, 422,379, 421,382, 415,383, 413,386, 411,387, 410,395, 411,398, 413,399, 414,404, 417,406, 417,411, 420,411"
"08","0-255-0","Ardennes","446,132, 448,131, 448,126, 447,123, 448,120, 451,118, 454,119, 456,117, 456,114, 451,113, 447,109, 444,107, 440,108, 439,103, 440,101, 439,99, 437,98, 437,95, 439,90, 439,88, 437,88, 433,92, 433,96, 428,98, 426,100, 423,100, 416,99, 416,112, 410,118, 410,124, 409,126, 410,129, 412,129, 416,130, 421,135, 426,137, 431,136, 432,138, 440,138, 445,137"
"09","255-102-102","Ariège","311,508, 313,508, 314,506, 317,506, 322,507, 324,509, 329,510, 334,506, 336,506, 341,505, 340,503, 337,501, 332,501, 329,497, 330,495, 333,494, 333,484, 332,480, 327,478, 325,478, 323,476, 323,474, 319,474, 315,473, 315,475, 313,477, 310,475, 308,478, 306,478, 306,482, 304,484, 302,483, 301,481, 297,481, 295,482, 294,486, 295,488, 293,490, 291,490, 288,493, 289,496, 294,498, 297,498, 299,500, 299,502, 307,502, 310,504"
"10","50-255-50","Aube","405,209, 407,211, 414,211, 418,210, 420,211, 422,209, 429,209, 432,205, 437,206, 437,203, 441,202, 442,197, 441,195, 442,192, 440,190, 434,183, 434,178, 431,178, 428,179, 423,176, 422,170, 419,169, 412,170, 411,172, 409,173, 408,175, 405,177, 405,179, 397,180, 395,178, 394,176, 391,176, 391,178, 388,181, 388,187, 390,187, 395,192, 395,197, 397,199, 399,199, 403,202, 403,204, 405,207"
"11","102-51-0","Aude","371,493, 373,495, 375,495, 375,493, 377,492, 377,487, 378,485, 376,485, 374,483, 374,481, 376,480, 380,481, 383,477, 383,475, 380,475, 378,473, 376,473, 375,471, 369,471, 367,474, 364,474, 362,472, 359,472, 358,470, 356,469, 356,466, 357,464, 348,464, 344,463, 344,465, 337,466, 330,465, 328,464, 327,468, 324,469, 323,473, 324,476, 328,477, 333,480, 333,483, 334,494, 330,497, 333,500, 337,500, 339,502, 342,504, 343,506, 345,506, 346,504, 348,504, 349,497, 351,496, 356,497, 358,496, 365,497, 368,493"
"12","255-153-0","Aveyron","358,442, 362,446, 366,447, 371,446, 372,448, 377,448, 377,442, 384,441, 384,439, 386,437, 388,437, 389,434, 392,431, 392,429, 389,428, 387,426, 387,423, 389,421, 384,420, 382,417, 380,416, 380,412, 379,405, 377,403, 377,399, 374,396, 372,396, 370,393, 370,390, 367,385, 364,383, 364,381, 361,382, 359,385, 359,387, 357,389, 357,392, 355,394, 354,396, 347,396, 345,395, 341,400, 339,400, 335,401, 331,405, 329,405, 329,408, 331,411, 331,413, 330,416, 333,416, 334,418, 332,419, 332,423, 331,425, 336,424, 338,422, 341,422, 342,424, 348,425, 352,429, 354,430, 358,439"
"13","0-0-153","Bouches-du-Rhône","479,472, 480,474, 484,473, 488,469, 485,466, 485,463, 488,462, 485,458, 485,454, 484,450, 488,447, 488,445, 486,445, 483,446, 482,448, 475,448, 470,445, 468,445, 465,444, 462,445, 457,441, 454,437, 452,437, 450,435, 448,435, 446,433, 444,433, 441,437, 441,442, 438,447, 434,447, 433,452, 430,455, 426,458, 424,458, 424,462, 426,462, 427,460, 441,460, 443,462, 446,462, 447,464, 450,465, 450,463, 453,461, 455,461, 457,463, 458,466, 466,466, 468,464, 470,464, 472,467, 472,472"
"14","150-150-255","Calvados","266,155, 271,155, 273,154, 277,155, 278,151, 277,146, 278,144, 276,139, 276,136, 274,135, 274,130, 271,129, 268,130, 264,134, 259,136, 253,136, 251,134, 245,133, 243,132, 241,133, 234,132, 230,129, 225,129, 223,136, 225,137, 229,142, 232,147, 232,151, 230,152, 228,155, 225,155, 225,158, 223,160, 223,162, 229,163, 232,164, 235,163, 237,161, 240,161, 245,159, 248,159, 255,160, 257,162, 262,158, 264,158"
"15","255-175-175","Cantal","367,383, 371,390, 371,393, 372,395, 374,394, 374,392, 376,389, 376,386, 378,385, 378,383, 383,382, 385,379, 388,378, 386,375, 386,370, 384,368, 384,365, 380,361, 378,361, 374,360, 372,358, 371,356, 369,356, 364,355, 361,352, 357,352, 357,354, 355,356, 351,356, 348,359, 344,364, 345,367, 341,374, 342,376, 338,380, 338,383, 340,386, 340,393, 341,396, 343,397, 345,394, 354,395, 356,392, 356,389, 358,387, 358,385, 360,383, 361,381, 364,380, 365,383"
"16","175-255-175","Charente","250,358, 253,361, 262,362, 264,360, 266,357, 266,353, 268,350, 271,348, 273,348, 276,344, 276,341, 280,338, 283,333, 285,331, 287,331, 290,324, 293,323, 293,319, 289,316, 289,314, 285,313, 283,315, 279,315, 278,313, 277,313, 276,316, 274,317, 272,316, 269,317, 268,315, 265,315, 261,314, 259,316, 257,317, 256,321, 254,322, 253,327, 252,330, 249,331, 246,330, 242,331, 241,340, 245,343, 245,345, 247,347, 247,353, 246,358"
"17","150-255-150","Charente-Maritime","210,326, 211,322, 210,318, 208,318, 205,316, 205,320, 207,322, 209,323|204,306, 203,304, 200,304, 207,308, 208,307|254,367, 256,366, 256,363, 252,362, 250,359, 246,359, 245,354, 246,347, 244,345, 244,343, 242,341, 240,340, 240,332, 242,330, 245,330, 248,329, 251,330, 251,328, 253,321, 253,319, 242,313, 240,313, 238,311, 236,311, 233,309, 230,305, 230,302, 221,301, 220,299, 217,299, 214,302, 214,304, 212,307, 215,310, 217,317, 216,323, 213,326, 213,328, 210,329, 210,333, 212,335, 215,336, 219,340, 220,342, 227,348, 229,353, 229,355, 228,357, 233,356, 237,357, 239,359, 239,362, 240,365, 242,365, 246,368, 250,369, 252,368, 254,369"
"18","125-255-255","Cher","343,297, 346,297, 349,292, 356,292, 359,289, 359,287, 358,285, 362,281, 367,281, 374,273, 374,262, 373,257, 371,252, 371,250, 369,248, 367,247, 367,244, 369,241, 368,238, 364,238, 362,239, 358,235, 354,235, 353,233, 351,233, 349,234, 347,232, 344,232, 342,233, 345,236, 346,242, 342,243, 341,249, 338,251, 333,251, 333,253, 329,257, 335,258, 338,260, 338,263, 340,265, 340,267, 339,269, 342,271, 341,273, 339,274, 339,276, 340,280, 342,282, 342,284, 344,286, 344,288, 343,291, 344,295"
"19","255-255-150","Corrèze","330,378, 333,378, 336,377, 337,379, 339,377, 341,376, 340,373, 342,371, 344,366, 343,364, 347,360, 351,355, 355,355, 356,352, 355,348, 356,345, 354,343, 356,340, 356,336, 354,336, 350,337, 348,339, 341,336, 339,336, 336,335, 331,337, 331,339, 328,340, 326,342, 324,342, 321,345, 319,345, 315,346, 314,348, 310,351, 307,351, 305,352, 306,356, 304,357, 304,364, 305,367, 309,368, 311,371, 311,375, 313,375, 320,374, 324,378, 325,380"
"2A","200-150-90","Corse-du-Sud","549,543, 555,548, 558,549, 558,545, 560,542, 560,539, 562,537, 562,534, 564,529, 564,526, 563,523, 558,524, 555,522, 555,516, 554,514, 552,514, 551,511, 547,507, 547,505, 544,504, 542,502, 538,499, 536,499, 531,497, 529,497, 530,499, 532,500, 531,502, 528,503, 528,505, 529,508, 533,509, 535,512, 535,514, 533,515, 533,517, 531,518, 531,520, 535,520, 537,519, 538,526, 536,527, 536,530, 538,530, 543,533, 540,537, 540,540, 542,540, 544,542"
"2B","200-150-60","Haute-Corse","548,507, 552,511, 552,513, 554,513, 556,516, 556,522, 561,523, 563,522, 563,514, 564,510, 567,509, 568,506, 567,504, 568,502, 566,489, 566,487, 565,482, 563,482, 561,477, 561,470, 562,467, 560,460, 559,458, 556,458, 556,460, 557,462, 556,468, 557,473, 555,476, 552,474, 548,474, 546,476, 546,478, 543,480, 540,480, 538,482, 536,482, 536,484, 533,485, 531,487, 531,492, 528,493, 527,496, 532,496, 539,499, 541,501, 548,505"
"21","50-151-255","Côte-d'Or","459,260, 461,258, 464,256, 466,251, 466,248, 467,246, 466,242, 464,240, 464,238, 462,236, 463,234, 466,232, 466,229, 465,227, 462,229, 457,229, 454,226, 450,226, 448,224, 446,223, 446,216, 444,214, 443,212, 439,209, 438,207, 434,207, 432,206, 430,208, 429,210, 422,210, 421,217, 423,218, 423,223, 421,225, 417,234, 415,236, 416,240, 415,245, 417,246, 417,250, 419,250, 421,252, 421,255, 423,258, 432,263, 435,266, 438,268, 443,267, 448,265, 450,265, 452,264, 455,265, 459,262"
"22","75-75-255","Côtes-d'Armor","176,196, 178,195, 178,193, 182,189, 184,189, 188,188, 188,186, 190,177, 188,175, 186,175, 182,172, 180,171, 179,169, 176,167, 172,168, 170,170, 165,174, 162,174, 158,169, 158,166, 156,165, 154,162, 154,160, 152,159, 152,157, 150,157, 149,154, 146,155, 144,154, 137,157, 135,155, 133,155, 144,154, 137,157, 135,155, 133,155, 132,158, 133,160, 131,161, 131,163, 128,165, 128,168, 130,170, 130,173, 129,180, 130,185, 131,187, 130,189, 134,190, 136,192, 138,192, 142,193, 146,190, 148,190, 152,193, 154,193, 156,195, 158,195, 163,196, 164,199, 167,197, 169,194, 172,194, 173,196"
"23","255-255-125","Creuse","338,334, 342,335, 347,338, 350,336, 353,336, 354,333, 352,331, 353,329, 355,328, 359,321, 359,318, 357,316, 357,310, 353,303, 347,298, 341,298, 336,299, 327,298, 325,300, 315,300, 312,307, 312,310, 316,314, 316,316, 317,320, 318,322, 317,324, 320,325, 321,329, 324,330, 326,329, 328,331, 331,333, 331,336"
"24","102-153-102","Dordogne","295,395, 297,397, 299,397, 301,395, 302,393, 307,390, 307,387, 309,386, 312,382, 312,378, 310,375, 310,371, 309,369, 307,369, 304,367, 304,365, 303,357, 305,356, 305,354, 303,351, 300,350, 299,347, 297,346, 296,343, 292,342, 289,344, 285,341, 285,338, 283,338, 281,337, 277,342, 277,344, 274,347, 273,349, 271,349, 267,353, 267,358, 265,359, 262,363, 258,363, 256,368, 259,368, 260,373, 258,378, 258,383, 263,384, 266,382, 268,382, 269,385, 268,388, 270,389, 271,394, 273,394, 278,393, 281,392, 287,393, 289,392, 290,396"
"25","255-255-50","Doubs","493,279, 494,282, 501,276, 505,273, 505,263, 510,260, 512,260, 514,257, 514,255, 517,252, 519,251, 523,246, 523,244, 525,242, 526,239, 524,239, 522,240, 521,237, 523,235, 523,232, 521,232, 517,231, 513,228, 512,228, 510,231, 508,231, 508,233, 504,234, 499,233, 495,238, 490,241, 488,243, 484,243, 480,246, 478,247, 478,250, 481,253, 481,257, 480,259, 482,261, 486,262, 488,264, 488,267, 491,270, 496,273, 497,275"
"26","1-51-51","Drôme","481,420, 481,413, 477,410, 473,409, 471,407, 473,404, 472,402, 474,401, 478,402, 479,399, 478,395, 480,393, 482,393, 485,392, 482,390, 480,390, 476,386, 473,386, 471,383, 471,381, 472,378, 471,376, 472,373, 463,372, 460,371, 459,369, 460,367, 459,362, 453,357, 448,359, 452,357, 449,359, 447,359, 447,361, 446,363, 447,369, 449,371, 448,374, 450,377, 450,380, 449,384, 447,386, 446,396, 444,399, 444,405, 442,407, 442,412, 445,412, 446,416, 449,416, 454,413, 457,413, 461,417, 466,417, 469,420, 471,420, 472,422, 475,422, 477,420"
"27","204-255-0","Eure","318,149, 321,149, 323,146, 323,143, 326,142, 326,140, 328,139, 328,137, 327,133, 323,132, 321,130, 318,130, 312,129, 309,134, 307,134, 305,135, 304,137, 302,137, 301,139, 299,139, 298,137, 296,136, 296,132, 287,131, 282,127, 281,127, 276,129, 274,128, 275,135, 277,136, 277,140, 279,145, 278,150, 279,154, 277,156, 279,158, 284,158, 287,163, 291,166, 291,170, 293,170, 306,166, 311,166, 312,163, 316,159, 315,157, 317,156, 317,154, 316,151"
"28","0-255-255","Eure-et-Loir","308,211, 312,211, 314,210, 315,208, 321,208, 323,206, 327,206, 331,205, 332,201, 334,199, 334,193, 333,187, 332,185, 330,185, 326,181, 326,178, 321,174, 321,172, 319,161, 316,157, 317,160, 313,163, 313,165, 311,167, 304,167, 297,170, 294,170, 292,171, 292,173, 296,178, 296,186, 293,189, 291,189, 290,194, 291,198, 294,199, 299,204, 303,204, 304,207, 307,209"
"29","25-25-255","Finistère","103,210, 105,209, 105,207, 109,206, 112,207, 113,205, 116,207, 116,209, 117,211, 122,211, 127,213, 129,213, 132,208, 134,206, 131,205, 129,203, 126,203, 124,201, 124,199, 122,197, 122,194, 124,192, 126,192, 129,190, 129,188, 130,186, 128,177, 128,174, 129,170, 127,168, 127,165, 128,163, 125,161, 122,161, 120,164, 115,160, 109,161, 107,163, 105,163, 103,161, 100,162, 98,164, 95,163, 94,165, 89,166, 86,169, 86,178, 89,177, 92,178, 97,176, 98,179, 102,179, 103,181, 101,183, 99,183, 93,182, 93,186, 95,184, 99,185, 102,187, 102,189, 103,192, 93,193, 87,194, 90,196, 92,196, 97,200, 99,205, 99,207, 98,209, 101,209"
"30","255-204-0","Gard","423,452, 421,454, 419,454, 422,459, 424,457, 426,457, 429,454, 432,452, 432,449, 434,446, 438,446, 440,441, 440,437, 443,434, 444,432, 446,431, 446,427, 443,426, 442,420, 440,418, 440,415, 436,412, 432,411, 427,412, 424,414, 422,414, 420,412, 417,412, 416,409, 414,408, 411,409, 411,411, 413,420, 410,424, 407,424, 404,422, 401,422, 399,425, 393,425, 392,423, 389,422, 388,426, 393,429, 393,431, 390,434, 390,436, 393,439, 395,439, 398,440, 401,436, 404,434, 406,434, 408,436, 408,439, 411,438, 415,442, 420,446, 422,447, 422,449"
"31","204-102-102","Haute-Garonne","280,495, 283,494, 286,495, 287,492, 291,489, 293,489, 294,487, 293,484, 295,481, 301,480, 304,483, 305,478, 308,477, 310,474, 313,476, 314,473, 318,472, 322,473, 322,470, 324,468, 326,468, 326,466, 328,463, 334,464, 334,462, 329,459, 327,456, 322,454, 321,452, 322,448, 320,446, 317,442, 316,439, 314,439, 309,440, 309,443, 306,445, 303,445, 301,443, 298,443, 294,444, 301,453, 303,454, 303,456, 297,461, 297,463, 295,465, 294,467, 292,467, 289,465, 287,465, 278,473, 278,475, 274,478, 274,480, 277,483, 277,485, 279,486, 279,491, 276,495, 273,495, 273,502, 277,502, 280,503, 280,501, 279,498"
"32","204-153-51","Gers","269,467, 270,469, 275,468, 278,470, 280,470, 282,468, 283,466, 288,464, 293,466, 296,463, 296,461, 298,458, 302,455, 297,450, 292,444, 290,443, 289,437, 285,436, 284,434, 287,431, 282,429, 280,430, 278,428, 273,428, 272,430, 270,430, 264,431, 262,430, 260,432, 257,432, 258,435, 254,436, 252,434, 247,435, 247,440, 246,445, 244,448, 244,451, 246,451, 251,453, 253,453, 256,457, 259,459, 259,463, 262,466, 266,466"
"33","153-204-153","Gironde","256,405, 255,403, 257,400, 259,400, 261,397, 261,391, 263,389, 267,389, 267,386, 268,383, 266,383, 263,385, 259,385, 257,383, 257,377, 259,372, 259,369, 255,369, 253,370, 251,369, 248,370, 244,367, 240,366, 238,361, 238,359, 231,357, 230,362, 231,367, 232,369, 230,370, 227,363, 227,358, 224,353, 214,343, 212,352, 212,357, 209,376, 209,378, 208,384, 207,388, 209,388, 210,386, 215,390, 214,392, 209,392, 206,399, 206,402, 215,400, 217,401, 217,404, 219,404, 223,405, 230,404, 231,407, 236,411, 238,411, 240,414, 240,418, 243,418, 245,419, 245,416, 248,415, 249,417, 253,417, 254,414, 253,412, 256,409"
"34","204-153-0","Hérault","369,470, 375,470, 376,472, 378,472, 380,474, 383,474, 385,475, 389,471, 396,470, 398,468, 398,464, 401,461, 403,461, 407,462, 410,457, 412,455, 414,455, 415,453, 422,452, 422,450, 421,447, 416,443, 414,443, 411,439, 408,440, 407,436, 404,435, 402,437, 399,439, 398,441, 396,441, 392,440, 390,437, 386,438, 385,441, 378,442, 378,448, 372,449, 371,451, 364,453, 361,452, 360,456, 362,458, 362,461, 359,463, 359,465, 357,466, 357,469, 360,471, 362,471, 364,473, 367,473"
"35","100-100-255","Ille-et-Vilaine","197,219, 199,216, 203,215, 204,213, 208,213, 210,215, 213,215, 213,212, 215,210, 215,208, 218,205, 220,205, 220,202, 218,193, 218,190, 220,188, 220,184, 219,178, 215,177, 213,179, 210,181, 204,176, 204,171, 199,171, 195,170, 194,166, 191,166, 188,169, 183,169, 183,171, 184,173, 188,174, 191,177, 191,180, 190,185, 189,188, 182,190, 179,193, 179,195, 177,196, 177,198, 178,200, 176,203, 176,205, 179,205, 183,208, 183,210, 182,214, 183,216, 181,221, 182,222, 185,220, 188,220"
"36","100-255-255","Indre","327,297, 335,297, 340,298, 342,297, 343,292, 342,289, 343,286, 341,284, 341,282, 339,280, 339,277, 338,274, 341,271, 338,269, 339,265, 337,263, 337,260, 329,259, 328,257, 330,255, 330,253, 326,252, 323,250, 321,250, 318,252, 314,252, 311,255, 313,258, 307,265, 302,264, 300,269, 300,272, 297,279, 292,280, 292,283, 291,285, 297,291, 299,291, 300,294, 304,298, 304,300, 308,300, 310,299, 312,301, 315,299, 325,299"
"37","75-255-255","Indre-et-Loire","288,274, 288,276, 291,279, 296,279, 299,272, 299,268, 300,265, 302,263, 305,263, 307,264, 312,259, 309,252, 306,249, 303,249, 302,246, 303,243, 300,233, 297,230, 294,230, 292,227, 290,227, 283,225, 282,227, 279,227, 277,229, 275,230, 274,232, 271,230, 268,230, 266,231, 268,234, 265,244, 262,247, 262,253, 261,257, 263,257, 264,260, 268,261, 269,267, 276,268, 281,267, 283,266, 285,271"
"38","51-102-102","Isère","483,389, 487,386, 491,386, 492,383, 499,380, 502,380, 504,379, 506,380, 506,375, 505,372, 501,372, 500,369, 502,364, 500,364, 497,360, 497,357, 499,355, 499,351, 496,348, 492,348, 491,346, 489,347, 487,350, 485,350, 482,349, 480,344, 475,339, 474,336, 467,329, 467,327, 465,327, 464,330, 462,332, 459,332, 457,331, 457,333, 458,336, 455,339, 454,341, 449,342, 447,344, 447,347, 444,350, 444,354, 445,357, 449,357, 451,355, 453,355, 457,358, 459,359, 461,362, 461,366, 462,369, 471,370, 474,373, 474,375, 473,377, 474,381, 473,383, 476,384, 478,386"
"39","255-255-75","Jura","477,300, 478,302, 484,302, 486,300, 490,295, 492,292, 492,290, 494,287, 493,281, 492,279, 496,275, 495,273, 492,271, 490,271, 487,267, 487,264, 482,262, 479,259, 480,253, 477,250, 476,248, 473,249, 467,248, 467,252, 464,257, 462,259, 460,260, 460,262, 459,265, 466,270, 463,274, 466,281, 466,284, 464,286, 464,288, 466,290, 466,292, 462,293, 462,295, 464,297, 466,300, 468,301, 468,303, 470,303, 474,300"
"40","153-255-153","Landes","246,435, 250,434, 252,433, 254,435, 257,435, 256,432, 260,425, 257,424, 255,422, 251,422, 250,418, 247,416, 246,419, 244,420, 240,419, 239,414, 238,412, 236,412, 233,409, 230,407, 230,405, 224,405, 220,406, 217,405, 216,401, 212,401, 208,402, 206,403, 206,405, 203,421, 200,431, 200,433, 197,443, 197,445, 194,452, 197,455, 203,455, 205,453, 207,453, 209,455, 212,455, 219,453, 221,453, 223,452, 232,454, 239,453, 241,454, 243,452, 243,448, 245,445, 245,441"
"41","50-255-255","Loir-et-Cher","340,244, 342,242, 345,242, 345,238, 343,235, 341,234, 342,232, 344,231, 344,228, 336,228, 334,229, 331,228, 327,229, 326,226, 324,224, 321,224, 319,222, 318,219, 320,218, 320,215, 318,213, 318,209, 315,209, 314,211, 308,212, 306,210, 305,208, 303,207, 303,205, 299,205, 295,201, 293,201, 291,204, 291,206, 292,208, 291,213, 289,215, 289,218, 286,221, 283,223, 286,225, 289,225, 292,226, 295,229, 297,229, 301,233, 301,235, 303,240, 303,242, 304,245, 303,248, 306,248, 311,253, 314,251, 318,251, 321,249, 323,249, 326,251, 329,251, 331,253, 333,250, 338,250, 340,249"
"42","0-153-51","Loire","443,352, 442,350, 440,350, 438,348, 438,346, 435,344, 432,344, 427,339, 427,335, 426,332, 427,328, 425,326, 425,324, 424,320, 422,318, 424,315, 424,313, 427,311, 425,310, 421,311, 414,310, 411,311, 410,309, 408,309, 405,306, 405,313, 406,320, 404,322, 402,322, 403,329, 402,331, 405,335, 405,338, 412,344, 412,346, 413,350, 410,353, 412,353, 416,354, 418,352, 422,352, 426,353, 428,355, 428,358, 430,358, 434,362, 437,362, 439,357, 442,356"
"43","255-200-200","Haute-Loire","399,384, 403,385, 408,390, 410,388, 412,385, 414,384, 415,382, 420,382, 421,379, 423,377, 425,376, 425,374, 428,372, 428,370, 431,367, 431,365, 432,361, 430,359, 428,359, 427,355, 420,353, 418,353, 416,355, 413,355, 408,354, 403,356, 401,355, 398,356, 397,354, 384,354, 381,357, 378,357, 378,360, 380,360, 383,362, 385,365, 385,368, 387,370, 387,375, 389,377, 390,381, 393,385, 397,385"
"44","255-0-0","Loire-Atlantique","173,260, 174,258, 173,258|201,261, 203,260, 204,265, 207,265, 207,263, 209,260, 211,260, 213,259, 215,260, 215,258, 213,258, 212,254, 215,253, 215,250, 213,250, 211,248, 211,246, 210,244, 212,242, 216,242, 224,241, 223,237, 218,236, 216,234, 216,231, 219,230, 216,227, 216,224, 213,221, 213,216, 210,216, 208,214, 204,214, 203,216, 201,216, 198,218, 197,220, 189,220, 185,221, 180,224, 180,228, 178,230, 173,230, 169,234, 167,235, 166,243, 171,243, 173,246, 176,245, 178,242, 182,242, 183,244, 179,245, 178,247, 179,249, 176,252, 180,253, 183,255, 184,259, 190,265, 192,265, 194,268, 198,268, 201,269, 202,265"
"45","25-255-255","Loiret","353,232, 354,234, 358,234, 362,238, 367,237, 367,234, 369,232, 369,228, 368,226, 366,225, 366,222, 370,221, 372,220, 372,214, 376,210, 375,207, 373,205, 373,203, 371,201, 363,201, 361,203, 355,202, 353,200, 353,196, 350,194, 350,192, 345,192, 342,191, 340,193, 337,193, 335,194, 335,199, 333,201, 333,204, 331,206, 328,206, 323,207, 321,209, 319,209, 319,213, 321,215, 321,218, 319,219, 320,222, 324,223, 327,226, 327,228, 330,228, 333,227, 335,228, 344,227, 345,231, 347,231, 349,233"
"46","204-102-0","Lot","328,413, 330,413, 330,411, 328,408, 328,405, 331,404, 335,400, 338,400, 341,399, 341,397, 339,392, 339,386, 337,383, 337,380, 336,378, 334,378, 329,379, 326,381, 323,379, 320,375, 314,375, 312,376, 313,382, 308,388, 308,390, 306,392, 300,397, 298,400, 296,401, 296,405, 298,407, 298,410, 299,413, 302,416, 305,417, 306,419, 311,419, 314,417, 317,419, 324,415, 326,415"
"47","204-255-204","Lot-et-Garonne","280,429, 284,426, 285,424, 290,423, 290,420, 292,415, 290,413, 291,411, 293,411, 297,410, 297,407, 295,405, 295,401, 298,398, 295,396, 292,396, 290,397, 289,393, 282,394, 279,393, 274,394, 271,395, 270,391, 269,389, 263,390, 262,398, 260,399, 259,401, 257,401, 256,404, 257,410, 254,412, 255,416, 253,418, 251,419, 251,421, 255,421, 257,423, 260,423, 261,425, 258,430, 260,431, 262,429, 269,430, 272,429, 273,427, 278,427"
"48","153-102-0","Lozère","407,423, 410,423, 412,420, 412,417, 411,412, 410,409, 415,407, 416,406, 413,404, 413,401, 412,399, 410,398, 410,396, 409,392, 403,386, 400,386, 398,385, 392,386, 389,381, 389,379, 387,379, 384,381, 383,383, 379,383, 379,385, 377,386, 377,389, 375,392, 375,396, 378,399, 378,403, 380,405, 380,411, 381,416, 385,419, 389,419, 391,422, 394,424, 399,424, 401,421, 404,421"
"49","255-100-100","Maine-et-Loire","244,259, 249,257, 252,259, 255,259, 258,258, 258,255, 261,253, 261,247, 264,244, 265,239, 267,234, 263,230, 258,227, 254,228, 253,225, 248,224, 247,221, 244,221, 241,220, 238,222, 234,222, 231,220, 228,220, 225,219, 221,220, 214,219, 214,221, 217,224, 217,227, 220,229, 219,231, 217,231, 217,234, 222,235, 224,237, 224,239, 225,241, 217,242, 212,243, 211,245, 212,248, 215,249, 216,253, 213,254, 213,257, 215,257, 216,261, 231,263, 235,263, 238,261, 239,259"
"50","125-125-255","Manche","224,164, 222,162, 222,160, 224,158, 224,155, 228,154, 231,150, 231,147, 226,140, 222,136, 222,134, 223,131, 221,130, 221,127, 219,125, 217,122, 217,118, 219,117, 219,114, 218,112, 213,111, 209,114, 205,114, 202,112, 200,112, 195,109, 194,109, 198,114, 198,117, 196,119, 198,124, 198,128, 201,130, 205,139, 205,149, 206,156, 205,164, 207,166, 207,168, 204,169, 205,176, 209,180, 216,176, 222,176, 231,178, 235,174, 234,171, 235,169, 233,168, 232,165, 230,165"
"51","25-255-25","Marne","423,175, 428,178, 430,178, 434,177, 438,178, 437,175, 440,173, 443,169, 446,170, 446,166, 442,162, 442,157, 446,154, 446,150, 445,146, 443,143, 443,141, 444,139, 441,138, 432,139, 431,137, 427,137, 425,138, 420,135, 416,131, 413,131, 410,130, 408,132, 404,131, 402,133, 400,133, 396,136, 396,140, 397,143, 394,145, 394,147, 396,150, 396,153, 390,160, 390,162, 388,164, 388,167, 390,169, 389,172, 391,172, 396,177, 397,179, 404,179, 404,177, 412,169, 418,169, 421,168, 423,170"
"52","75-255-75","Haute-Marne","472,223, 472,221, 473,219, 472,217, 476,213, 479,211, 479,208, 476,206, 476,204, 472,201, 472,197, 474,196, 472,193, 470,192, 469,190, 465,187, 463,187, 462,182, 461,180, 458,178, 455,178, 452,175, 449,174, 448,172, 446,172, 443,170, 441,172, 438,176, 439,178, 435,179, 435,183, 441,189, 443,192, 443,194, 442,196, 443,201, 441,203, 438,203, 438,206, 440,208, 442,211, 445,213, 447,216, 447,223, 450,225, 454,225, 457,228, 462,228, 463,225, 468,223"
"53","255-75-75","Mayenne","224,219, 227,218, 231,219, 234,221, 238,221, 241,219, 243,219, 246,220, 246,217, 247,213, 250,211, 250,206, 253,205, 253,199, 256,197, 256,190, 259,187, 259,182, 257,182, 255,180, 255,177, 252,176, 251,178, 249,178, 246,179, 244,178, 241,180, 234,180, 232,181, 230,179, 228,179, 220,178, 220,183, 221,188, 219,190, 219,196, 221,205, 218,206, 216,208, 216,210, 214,212, 214,217, 220,218"
"54","102-0-102","Meurthe-et-Moselle","508,179, 509,181, 512,181, 514,182, 517,181, 523,175, 521,172, 514,169, 512,169, 509,168, 507,166, 504,164, 502,164, 498,163, 494,159, 494,155, 492,155, 488,154, 484,151, 483,149, 480,147, 482,144, 482,140, 483,137, 479,130, 479,125, 480,123, 477,123, 473,120, 468,121, 463,123, 462,127, 469,128, 471,130, 472,139, 473,144, 476,146, 476,153, 474,156, 474,159, 475,163, 473,165, 473,167, 474,173, 473,176, 476,178, 480,178, 481,183, 484,186, 486,186, 489,185, 490,183, 493,183, 496,182, 499,183, 504,181, 506,179"
"55","153-0-153","Meuse","465,185, 465,183, 469,182, 471,180, 474,180, 474,177, 472,176, 472,174, 473,168, 472,165, 474,163, 474,160, 473,156, 475,153, 475,146, 472,144, 472,140, 471,132, 469,129, 464,129, 461,127, 461,120, 460,117, 459,117, 458,119, 454,122, 449,121, 448,125, 449,131, 447,132, 447,136, 445,138, 445,140, 444,143, 446,146, 446,149, 447,155, 443,158, 443,162, 447,166, 447,171, 454,176, 458,177, 460,179, 462,180, 463,186"
"56","50-50-255","Morbihan","144,241, 140,237, 138,237, 138,240, 141,240|173,229, 178,229, 180,220, 182,215, 181,211, 182,208, 179,206, 176,206, 175,203, 177,200, 176,197, 173,197, 172,195, 169,195, 165,200, 163,199, 163,197, 159,197, 156,196, 154,194, 151,194, 150,192, 146,191, 144,193, 139,194, 136,193, 134,191, 132,191, 130,190, 128,192, 124,193, 123,197, 125,199, 125,201, 129,202, 131,204, 134,204, 135,206, 131,211, 130,216, 135,217, 144,225, 148,225, 150,226, 154,223, 156,223, 158,225, 158,227, 154,228, 154,230, 156,231, 160,230, 162,229, 164,230, 166,229, 169,231, 171,231"
"57","204-0-204","Moselle","519,155, 518,151, 520,150, 520,147, 522,146, 523,148, 527,148, 529,150, 533,150, 535,149, 539,150, 541,143, 535,138, 532,138, 531,140, 524,141, 520,140, 518,137, 514,137, 512,140, 509,140, 507,138, 505,133, 502,131, 503,128, 498,124, 494,124, 492,122, 487,122, 485,124, 480,125, 480,131, 482,133, 484,138, 483,145, 481,146, 482,148, 485,150, 486,152, 491,153, 494,154, 495,159, 498,162, 501,162, 504,163, 506,165, 509,167, 511,167, 522,172, 525,175, 529,171, 529,169, 530,166, 529,163, 530,160, 528,157, 522,156"
"58","100-151-255","Nièvre","414,273, 415,271, 413,269, 414,266, 413,264, 414,259, 417,256, 420,255, 420,252, 417,251, 416,246, 411,246, 410,244, 405,244, 401,243, 398,240, 396,240, 395,237, 392,236, 385,238, 382,238, 377,233, 373,234, 369,233, 368,237, 370,240, 368,245, 368,247, 372,250, 372,253, 374,258, 374,261, 375,274, 373,275, 373,277, 376,280, 380,283, 388,282, 390,284, 392,284, 395,282, 396,280, 399,280, 403,279, 404,281, 406,281, 413,277"
"59","153-153-51","Nord","413,89, 413,85, 415,83, 414,81, 411,80, 409,78, 406,78, 404,79, 399,78, 398,80, 396,79, 395,76, 396,73, 393,70, 391,70, 390,68, 387,70, 383,69, 382,65, 380,62, 381,59, 378,57, 378,55, 376,54, 372,55, 370,56, 369,58, 366,58, 363,55, 361,52, 359,52, 358,44, 356,42, 356,39, 353,38, 347,39, 342,41, 341,43, 344,48, 344,51, 347,54, 350,54, 351,60, 354,62, 356,62, 364,63, 366,65, 367,68, 371,69, 374,71, 375,75, 374,78, 375,82, 378,83, 379,88, 376,95, 383,95, 386,94, 388,95, 391,93, 394,94, 401,93, 406,94, 409,97, 413,97, 413,95, 416,93, 415,90"
"60","225-225-255","Oise","372,137, 373,135, 375,135, 376,131, 378,130, 376,125, 377,121, 376,118, 377,115, 371,115, 369,117, 365,117, 365,119, 360,121, 358,121, 356,119, 354,119, 351,117, 349,117, 346,115, 342,115, 339,116, 336,114, 332,114, 330,112, 327,112, 327,115, 326,121, 327,124, 329,125, 327,128, 327,132, 329,139, 327,140, 327,142, 333,143, 338,141, 341,143, 345,143, 348,145, 350,145, 354,146, 356,148, 359,147, 361,149, 363,149, 371,148, 376,146, 376,143, 374,140, 374,138"
"61","175-175-255","Orne","259,181, 260,184, 264,184, 266,181, 268,181, 272,180, 275,182, 276,189, 279,190, 282,193, 286,193, 289,196, 290,195, 289,190, 291,188, 293,188, 295,186, 295,178, 292,175, 290,170, 290,166, 288,164, 285,162, 284,159, 279,159, 275,156, 272,155, 266,156, 264,159, 262,159, 258,163, 255,161, 249,161, 244,160, 239,162, 237,162, 235,164, 233,164, 233,166, 234,168, 236,169, 235,172, 236,174, 234,177, 232,178, 232,180, 241,179, 244,177, 248,178, 251,177, 252,175, 254,175, 256,177, 256,180"
"62","102-102-51","Pas-de-Calais","361,89, 368,94, 371,94, 376,93, 378,86, 378,84, 375,83, 373,76, 374,73, 373,71, 369,70, 366,68, 365,65, 357,64, 352,62, 350,60, 350,55, 346,55, 343,51, 343,48, 340,43, 334,42, 332,44, 330,44, 324,49, 322,49, 323,56, 322,73, 321,77, 326,77, 329,76, 331,78, 334,78, 335,81, 338,82, 339,85, 344,85, 347,83, 350,83, 354,86, 353,89, 356,89, 359,91"
"63","255-150-150","Puy-de-Dôme","397,353, 398,355, 400,355, 402,354, 404,355, 407,354, 410,351, 412,350, 412,347, 411,344, 407,340, 404,338, 404,335, 402,333, 401,330, 402,324, 399,324, 397,321, 393,321, 390,318, 388,319, 379,318, 377,316, 375,316, 371,312, 370,308, 368,308, 366,311, 364,311, 362,313, 361,315, 358,315, 360,318, 360,322, 358,324, 355,329, 353,330, 357,337, 357,340, 355,342, 357,345, 357,347, 356,350, 362,351, 364,354, 368,354, 371,355, 373,357, 374,359, 376,359, 378,356, 381,356, 384,353"
"64","102-255-102","Pyrénées-Atlantiques","198,481, 199,479, 203,480, 206,482, 208,482, 210,484, 212,484, 213,486, 222,486, 223,490, 230,496, 237,495, 239,493, 239,490, 240,486, 243,483, 245,482, 245,479, 247,478, 251,473, 252,470, 251,468, 254,467, 253,461, 251,458, 251,456, 248,453, 244,452, 241,455, 233,454, 229,455, 224,454, 222,453, 209,456, 207,454, 205,454, 203,456, 197,456, 195,454, 192,455, 190,457, 186,462, 182,462, 183,465, 187,465, 188,468, 190,468, 191,466, 194,468, 196,468, 198,470, 198,472, 194,479, 196,481"
"65","153-102-51","Hautes-Pyrénées","265,503, 267,501, 270,503, 272,503, 272,495, 276,494, 278,491, 278,486, 276,485, 276,483, 273,480, 273,478, 277,474, 278,471, 275,469, 272,469, 270,470, 269,468, 267,468, 261,467, 258,463, 258,459, 252,454, 251,454, 252,458, 254,461, 254,465, 255,467, 252,468, 253,471, 250,476, 248,477, 246,480, 246,482, 244,484, 241,486, 241,489, 240,493, 239,495, 243,495, 246,496, 251,502, 255,502, 259,501, 261,500"
"66","51-51-0","Pyrénées-Orientales","338,522, 340,519, 343,519, 347,518, 350,520, 352,520, 355,523, 357,523, 359,522, 362,523, 362,520, 367,519, 370,516, 377,516, 379,518, 382,518, 382,516, 381,514, 378,513, 377,497, 373,496, 371,494, 368,494, 365,498, 359,498, 357,497, 352,498, 350,497, 350,503, 348,505, 346,505, 345,507, 343,507, 337,506, 334,507, 333,509, 328,511, 326,511, 324,512, 324,514, 328,515, 330,517, 332,517, 334,522"
"67","204-204-51","Bas-Rhin","532,186, 536,190, 538,190, 540,192, 540,194, 544,195, 544,193, 547,188, 547,185, 548,178, 550,173, 550,168, 555,162, 555,160, 557,159, 558,157, 560,156, 560,152, 563,148, 560,147, 558,145, 556,145, 542,144, 541,149, 539,151, 536,151, 534,150, 529,151, 527,149, 523,149, 522,147, 521,150, 519,151, 519,154, 521,154, 526,155, 530,158, 531,162, 530,165, 531,168, 530,171, 526,175, 525,184, 527,184, 530,186"
"68","153-153-0","Haut-Rhin","544,229, 544,227, 545,223, 542,220, 543,209, 545,204, 545,202, 543,200, 543,196, 540,195, 539,192, 536,191, 532,187, 528,187, 525,194, 525,198, 523,200, 523,202, 520,205, 520,209, 518,216, 521,217, 528,230, 528,233, 530,233, 539,234"
"69","0-255-51","Rhône","446,344, 449,341, 452,341, 454,340, 457,336, 457,334, 456,330, 450,330, 447,325, 444,324, 442,322, 442,314, 443,312, 442,310, 440,310, 438,308, 438,306, 431,305, 428,304, 428,307, 427,309, 428,311, 425,314, 423,317, 425,320, 425,323, 426,326, 428,328, 428,331, 427,334, 428,339, 432,343, 435,343, 439,346, 439,348, 444,349, 446,347"
"70","255-255-0","Haute-Saône","488,242, 491,239, 496,236, 499,232, 503,232, 507,233, 507,231, 510,230, 512,227, 514,227, 515,222, 514,217, 515,215, 511,212, 508,211, 507,209, 505,211, 501,211, 499,208, 492,210, 489,208, 489,206, 486,206, 486,208, 483,210, 480,210, 477,214, 473,217, 474,220, 473,223, 467,224, 464,225, 466,227, 467,232, 463,236, 465,238, 465,240, 467,242, 467,245, 468,247, 472,247, 474,248, 477,247, 479,245, 484,242"
"71","150-151-255","Saône-et-Loire","437,304, 439,306, 439,308, 442,309, 442,307, 447,291, 450,290, 454,291, 457,290, 458,292, 461,293, 465,292, 465,290, 463,288, 463,286, 465,284, 465,281, 462,274, 463,272, 465,271, 464,269, 462,269, 460,266, 456,265, 453,266, 451,265, 438,269, 436,267, 429,262, 426,261, 424,259, 420,256, 419,256, 415,259, 415,263, 414,265, 415,267, 414,269, 416,271, 415,277, 412,278, 410,280, 405,282, 402,280, 400,280, 397,281, 399,284, 399,286, 400,290, 407,293, 409,293, 410,299, 406,303, 406,305, 408,308, 410,308, 411,310, 413,310, 420,309, 424,310, 426,309, 427,304, 430,303"
"72","255-25-25","Sarthe","271,229, 273,231, 276,228, 279,226, 282,226, 282,223, 285,220, 288,218, 288,215, 290,213, 290,209, 291,207, 290,204, 292,201, 290,198, 287,196, 286,194, 281,194, 279,191, 276,190, 275,184, 274,182, 269,181, 266,182, 264,185, 260,186, 257,190, 257,197, 254,200, 254,205, 251,206, 251,211, 248,214, 248,216, 247,220, 248,223, 252,223, 254,225, 254,227, 256,227, 258,226, 261,227, 262,229, 267,230"
"73","51-153-153","Savoie","500,355, 498,357, 498,360, 501,363, 506,366, 506,368, 511,368, 512,366, 525,362, 527,362, 530,360, 531,358, 534,358, 536,356, 536,351, 538,348, 534,344, 531,343, 529,334, 527,334, 521,329, 518,329, 514,328, 512,326, 512,322, 510,322, 508,324, 508,327, 505,330, 505,332, 502,335, 499,333, 498,331, 496,331, 492,332, 490,330, 489,328, 485,325, 483,332, 483,334, 481,335, 480,338, 478,340, 481,344, 482,348, 484,348, 487,349, 490,345, 493,347, 496,347, 500,351"
"74","0-204-204","Haute-Savoie","504,330, 507,327, 507,324, 510,321, 512,321, 513,326, 520,328, 522,327, 522,325, 525,323, 527,323, 529,321, 530,316, 526,312, 524,311, 524,308, 521,308, 520,306, 522,299, 519,296, 520,293, 508,293, 506,296, 501,296, 500,302, 501,304, 495,309, 489,309, 489,311, 487,312, 486,314, 484,314, 484,318, 485,323, 487,325, 488,327, 491,329, 492,331, 495,331, 498,330, 500,332, 501,334, 504,332"
"75","199-255-175","Paris","350,164, 351,161, 348,160, 346,161, 346,163|503,55, 507,52, 509,52, 512,54, 515,54, 516,50, 512,49, 510,46, 510,43, 507,39, 507,36, 495,36, 493,38, 489,41, 487,41, 484,42, 482,44, 482,47, 485,48, 487,51, 490,51, 497,55"
"76","204-204-0","Seine-Maritime","300,138, 302,136, 304,136, 305,134, 309,133, 310,130, 312,128, 317,128, 321,129, 323,131, 326,131, 326,128, 328,126, 326,124, 326,122, 325,116, 326,112, 327,110, 325,103, 323,101, 318,97, 315,95, 313,95, 307,100, 302,102, 299,102, 292,105, 286,105, 282,108, 279,109, 277,111, 273,112, 270,114, 270,117, 267,122, 267,124, 270,124, 273,126, 275,126, 276,128, 283,126, 285,129, 294,130, 297,132, 297,136"
"77","199-255-75","Seine-et-Marne","371,198, 373,196, 373,190, 376,188, 385,188, 387,187, 387,181, 390,178, 390,176, 392,175, 391,173, 389,173, 388,171, 389,169, 387,167, 387,164, 388,161, 378,152, 378,149, 376,147, 375,147, 370,149, 364,149, 361,150, 359,148, 357,153, 359,158, 359,160, 358,162, 359,169, 357,172, 357,178, 356,188, 353,190, 351,193, 352,195, 354,196, 354,200, 359,201, 361,202, 363,200, 371,200"
"78","199-255-25","Yvelines","337,178, 337,172, 340,170, 341,168, 343,168, 343,166, 341,164, 341,161, 342,155, 337,154, 332,152, 330,150, 326,151, 318,150, 317,153, 318,158, 320,161, 320,165, 321,171, 322,174, 324,175, 325,177, 327,178, 327,181, 330,184, 332,182, 334,182"
"79","100-255-100","Deux-Sèvres","254,319, 254,321, 257,316, 261,313, 264,313, 266,314, 266,311, 263,309, 265,304, 265,301, 263,300, 261,301, 258,297, 258,294, 257,292, 259,290, 259,288, 260,285, 258,283, 258,281, 259,278, 258,273, 259,267, 258,264, 253,260, 250,258, 248,258, 243,260, 239,260, 237,263, 228,264, 229,270, 232,272, 232,275, 234,278, 234,280, 236,287, 236,289, 235,294, 237,296, 237,298, 233,301, 231,301, 231,305, 236,310, 238,310, 240,312, 242,312, 245,314, 247,314, 249,316, 251,316, 252,318"
"80","200-200-255","Somme","375,114, 375,110, 374,105, 376,104, 376,102, 378,99, 378,97, 374,94, 372,94, 367,95, 366,93, 364,93, 362,90, 360,92, 355,90, 353,90, 352,88, 353,86, 350,84, 347,84, 344,86, 339,86, 338,83, 335,82, 334,79, 331,79, 329,77, 327,77, 321,78, 321,80, 320,83, 321,85, 319,86, 318,90, 315,94, 317,96, 326,103, 326,105, 327,109, 332,113, 336,113, 339,115, 341,115, 346,114, 349,116, 351,116, 354,118, 356,118, 358,120, 361,120, 364,119, 364,117, 369,116, 371,114"
"81","153-102-102","Tarn","343,463, 347,462, 358,463, 361,460, 361,458, 359,456, 359,453, 361,451, 363,451, 366,452, 371,450, 371,447, 367,447, 364,448, 361,447, 357,442, 357,439, 353,430, 351,430, 348,426, 344,426, 340,423, 338,423, 336,425, 333,425, 331,426, 329,425, 327,428, 322,427, 324,429, 324,431, 321,433, 320,435, 318,435, 318,437, 317,440, 321,445, 323,448, 323,451, 322,453, 327,455, 332,460, 335,462, 337,465, 343,465"
"82","153-51-0","Tarn-et-Garonne","320,434, 323,430, 321,428, 322,426, 325,426, 327,427, 329,424, 331,423, 331,419, 333,418, 330,417, 329,414, 326,416, 323,416, 321,418, 318,420, 316,420, 315,418, 310,420, 306,420, 305,418, 302,417, 298,413, 298,411, 294,411, 291,412, 293,415, 291,422, 290,424, 287,424, 285,425, 285,427, 284,429, 287,429, 288,431, 285,434, 290,437, 290,441, 291,443, 297,443, 301,442, 303,444, 306,444, 308,443, 308,440, 313,439, 317,436, 318,434"
"83","0-0-204","Var","490,478, 491,480, 495,479, 496,477, 498,477, 504,478, 506,476, 510,476, 512,477, 512,475, 521,471, 524,471, 524,469, 525,467, 522,468, 521,466, 526,461, 526,459, 531,458, 534,456, 534,451, 533,448, 529,448, 527,445, 527,442, 523,441, 521,438, 513,439, 513,441, 509,442, 506,439, 504,440, 502,443, 500,443, 499,445, 496,445, 494,443, 492,443, 490,444, 487,443, 489,445, 489,448, 485,451, 485,453, 486,458, 489,461, 488,463, 486,463, 486,466, 489,469, 488,471, 485,473, 485,475, 488,476"
"84","0-0-102","Vaucluse","482,439, 480,439, 479,436, 480,434, 476,431, 477,426, 475,425, 475,423, 472,423, 471,421, 469,421, 466,418, 461,418, 457,414, 454,414, 449,417, 446,417, 445,413, 441,413, 441,418, 443,420, 443,425, 445,425, 447,427, 447,433, 450,434, 452,436, 454,436, 458,440, 460,443, 464,444, 467,443, 476,447, 482,447, 483,445, 485,445, 485,441|454,408, 452,407, 451,411, 453,411"
"85","255-50-50","Vendée","170,275, 169,275|234,294, 234,290, 235,285, 233,278, 231,275, 231,272, 228,270, 228,266, 227,264, 225,264, 217,263, 213,260, 209,261, 208,265, 204,266, 203,261, 202,264, 203,268, 201,270, 199,270, 194,269, 191,266, 186,263, 184,260, 182,260, 182,262, 178,266, 178,269, 179,271, 183,274, 187,279, 189,284, 189,286, 194,291, 197,293, 200,293, 202,295, 202,297, 206,297, 209,300, 212,301, 215,300, 217,298, 220,298, 221,300, 228,300, 230,301, 233,300, 236,297"
"86","125-255-125","Vienne","283,314, 285,312, 287,312, 289,313, 290,310, 289,308, 293,304, 296,304, 297,301, 301,300, 303,299, 299,294, 299,292, 297,292, 290,285, 291,280, 287,276, 287,274, 284,271, 283,267, 272,269, 270,269, 268,267, 268,262, 265,262, 263,260, 263,258, 261,258, 260,256, 259,256, 259,258, 256,259, 255,261, 259,264, 259,266, 260,272, 259,277, 260,280, 259,283, 261,285, 261,287, 260,290, 258,292, 259,297, 262,300, 264,299, 266,301, 266,305, 264,308, 265,310, 267,311, 267,314, 270,316, 273,315, 275,316, 275,314, 277,312, 280,314"
"87","255-255-100","Haute-Vienne","315,345, 318,345, 321,344, 324,341, 326,341, 328,339, 330,339, 330,333, 326,330, 323,331, 320,329, 320,326, 318,326, 316,324, 317,321, 315,314, 311,310, 311,307, 313,302, 310,300, 304,301, 302,300, 298,301, 297,304, 293,305, 290,308, 291,312, 290,316, 294,319, 294,323, 290,326, 288,331, 285,332, 283,335, 283,337, 285,337, 286,341, 288,343, 293,341, 296,342, 300,347, 300,349, 305,351, 310,350"
"88","255-0-255","Vosges","475,203, 477,204, 477,206, 481,209, 483,209, 485,208, 485,206, 489,205, 490,208, 494,209, 499,207, 502,210, 505,210, 506,208, 510,211, 513,212, 514,214, 517,215, 519,206, 522,202, 522,200, 524,198, 524,194, 527,187, 527,185, 525,185, 524,176, 523,176, 517,182, 515,182, 513,183, 509,182, 508,180, 506,180, 504,182, 497,184, 494,183, 490,184, 489,186, 487,186, 484,187, 480,183, 480,179, 477,179, 474,181, 471,181, 469,183, 466,183, 466,186, 468,189, 475,195, 473,198, 473,201"
"89","0-151-255","Yonne","401,242, 404,242, 410,243, 411,245, 414,245, 414,241, 415,238, 414,236, 417,233, 417,231, 422,222, 422,218, 420,217, 420,212, 415,211, 407,212, 404,209, 404,207, 402,204, 402,202, 399,200, 397,200, 394,197, 394,192, 390,188, 386,188, 376,189, 374,190, 374,196, 372,198, 372,201, 374,203, 374,205, 376,207, 377,210, 373,214, 373,220, 370,222, 367,222, 367,225, 369,226, 370,231, 373,233, 375,233, 378,232, 382,237, 387,237, 394,235, 396,237, 396,239, 398,239"
"90","255-255-25","Territoire de Belfort","527,231, 527,229, 525,227, 521,218, 519,218, 516,216, 515,221, 516,226, 515,229, 524,231"
"91","199-255-50","Essonne","340,192, 342,190, 344,190, 352,191, 355,187, 355,179, 356,171, 350,171, 345,169, 344,168, 341,169, 338,173, 338,179, 335,181, 333,184, 333,186, 334,192, 336,193"
"92","199-255-100","Hauts-de-Seine","345,163, 345,161, 347,160, 347,154, 344,154, 343,160, 342,164, 347,169, 348,165|495,60, 495,55, 490,52, 487,52, 483,48, 481,47, 481,44, 484,41, 486,41, 489,40, 492,37, 495,35, 495,33, 498,30, 498,27, 494,26, 492,25, 485,29, 475,39, 492,25, 485,29, 479,35, 474,39, 473,48, 472,54, 475,54, 477,56, 477,58, 479,58, 483,62, 484,65, 489,66, 491,68, 491,71, 494,71, 495,66, 497,64, 497,62"
"93","199-255-125","Seine-Saint-Denis","350,159, 352,161, 357,161, 358,157, 357,154, 356,154, 354,156, 348,156, 348,159|519,45, 522,46, 525,49, 529,52, 530,55, 534,56, 535,52, 532,50, 532,45, 530,43, 530,39, 533,36, 533,31, 535,30, 535,28, 531,23, 530,19, 531,15, 527,14, 524,19, 520,23, 518,23, 517,25, 507,25, 504,22, 502,22, 498,25, 493,24, 498,26, 499,30, 496,33, 496,35, 507,35, 508,39, 510,41, 511,46, 514,47"
"94","199-255-150","Val-de-Marne","357,170, 358,163, 352,162, 349,166, 349,169|517,74, 524,73, 525,78, 527,80, 531,81, 531,78, 533,73, 533,71, 535,69, 535,66, 533,64, 533,62, 534,57, 532,57, 529,55, 528,52, 526,50, 522,47, 518,46, 515,47, 517,50, 517,53, 515,55, 512,55, 509,53, 507,53, 505,55, 496,56, 496,60, 498,62, 498,64, 496,66, 496,69, 498,69, 503,70, 504,75, 507,75"
"95","199-255-0","Val-d'Oise","347,153, 349,155, 354,155, 356,153, 357,149, 354,147, 351,147, 344,144, 341,144, 338,142, 337,142, 332,144, 329,144, 324,143, 324,146, 323,149, 325,149, 328,150, 330,149, 332,151, 342,154"
"971","161-161-25","Guadeloupe","80,269, 80,172, 1,172, 1,269"
"972","161-161-125","Martinique","79,362, 79,271, 1,271, 1,362"
"973","161-161-200","Guyane","78,449, 78,365, 3,365, 3,449"
"974","161-161-225","Réunion","78,524, 78,453, 2,453, 2,524"
"975","25-161-161","Saint-Pierre-et-Miquelon","158,130, 158,4, 88,4, 88,130"
"976","125-161-161","Mayotte","81,101, 81,4, 3,4, 3,101"
"977","0-0-0","Saint-Barthélémy",""
"978","0-0-0","Saint-Martin",""
"986","200-161-161","Wallis-et-Futuna","161,527, 161,465, 160,405, 93,405, 93,464, 81,465, 81,527"
"987","225-161-161","Polynésie française","162,401, 162,306, 83,306, 83,401"
"988","225-225-161","Nouvelle-Calédonie","281,82, 281,7, 197,7, 197,82"
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/trunk/composants/cartographie/squelettes/pays_oceanie.csv
New file
0,0 → 1,16
"code","rvb_fond","nom","poly"
"au","255-25-25","Australie","14,246,47,233,49,220,59,220,71,203,89,211,92,187,119,195,135,193,129,216,149,225,159,188,176,211,213,227,231,255,220,279,228,299,200,359,192,394,181,397,164,377,162,364,143,355,125,344,110,321,88,319,63,329,60,336,37,331-32,339,15,338,6,334,5,321,11,318,8,310,5,292,0,281,3,252"
"fj","255-25-75","Fidji","321,180,342,181,382,222,379,250,365,269,348,271,325,258,324,246,331,222,320,203,322,180"
"ki","255-25-125","Kiribati","311,120,330,106,348,112,373,132,398,129,478,144,482,129,461,113,483,92,507,107,530,143,530,199,505,200,508,186,500,181,493,174,369,168,360,155,336,154,321,145,312,120"
"mh","255-25-175","Marshall","244,64,262,26,317,28,346,48,345,110,329,106,310,119,292,111,293,106"
"fm","255-25-225","Micronésie","128,72,193,59,244,65,291,105,290,117,286,119,170,118,152,103,128,103"
"nr","255-75-25","Nauru","297,112,312,120,319,144,292,141,292,129,298,121"
"nz","255-75-75","Nouvelle-Zélande","325,327,348,350,364,356,338,388,301,437,293,441,279,419,318,364,330,354,318,332"
"pw","255-75-125","Palau","127,73,92,93,92,116,111,123,128,104"
"pg","255-75-175","Papouasie - Nouvelle Guinée","152,131,152,184,158,187,171,186,179,201,228,200,233,193,231,178,225,179,225,174,234,170,249,159,281,158,281,131"
"sb","255-75-225","Salomon","281,158,249,158,226,176,226,178,232,178,232,194,242,194,251,203,321,204,321,180,303,162"
"ws","255-125-25","Samoa","394,205,405,203,411,193,423,214,414,223"
"to","25-125-225","Tonga","382,220,375,214,376,209,383,202,393,204,416,226,401,262,388,256,371,258,380,249"
"tv","25-175-25","Tuvalu","325,155,359,155,374,175,361,198,341,180,336,180"
"vu","255-125-175","Vanuatu","287,203,307,247,325,246,331,222,321,204"
"0","0-0-0","",""
/trunk/composants/cartographie/squelettes/pays_afrique.tpl.html
New file
0,0 → 1,12
<div id="cartographie">
<img id="carte-img" src="<?=$carte_url;?>" alt="<?=$carte_alt;?>" usemap="#carte-map" />
<map name="carte-map">
<?php foreach ($zones as $code => $zone) : ?>
<?php if (!empty($zone['poly'])) : ?>
<?php foreach (explode('|', $zone['poly']) as $coords) : ?>
<area shape="poly" title="<?=$zone['nom']?> (<? echo $zone['info_nombre']; if($zone['info_nombre'] > 1) {echo ' inscrits';} else { echo ' inscrit';} ?>)" class="zone-<?=$code?>" href="<?=$zone['url']?>" coords="<?=$coords?>" />
<?php endforeach; ?>
<?php endif; ?>
<?php endforeach; ?>
</map>
</div>
/trunk/composants/cartographie/squelettes/pays_europe.tpl.html
New file
0,0 → 1,12
<div id="cartographie">
<img id="carte-img" src="<?=$carte_url;?>" alt="<?=$carte_alt;?>" usemap="#carte-map" />
<map name="carte-map">
<?php foreach ($zones as $code => $zone) : ?>
<?php if (!empty($zone['poly'])) : ?>
<?php foreach (explode('|', $zone['poly']) as $coords) : ?>
<area shape="poly" title="<?=$zone['nom']?> (<? echo $zone['info_nombre']; if($zone['info_nombre'] > 1) {echo ' inscrits';} else { echo ' inscrit';} ?>)" class="zone-<?=$code?>" href="<?=$zone['url']?>" coords="<?=$coords?>" />
<?php endforeach; ?>
<?php endif; ?>
<?php endforeach; ?>
</map>
</div>
/trunk/composants/cartographie/squelettes/pays_moyen_orient.csv
New file
0,0 → 1,0
"code","rvb_fond","nom","poly"
/trunk/composants/cartographie/squelettes/france.tpl.html
New file
0,0 → 1,12
<div id="cartographie">
<img id="carte-img" src="<?=$carte_url;?>" alt="<?=$carte_alt;?>" usemap="#carte-map" />
<map name="carte-map">
<?php foreach ($zones as $code => $zone) : ?>
<?php if (!empty($zone['poly'])) : ?>
<?php foreach (explode('|', $zone['poly']) as $coords) : ?>
<area shape="poly" title="<?=$zone['nom']?> (<? echo $zone['info_nombre']; if($zone['info_nombre'] > 1) {echo ' inscrits';} else { echo ' inscrit';} ?>)" class="zone-<?=$code?>" href="<?=$zone['url']?>" coords="<?=$coords?>" />
<?php endforeach; ?>
<?php endif; ?>
<?php endforeach; ?>
</map>
</div>
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/trunk/composants/cartographie/squelettes/pays_oceanie.tpl.html
New file
0,0 → 1,12
<div id="cartographie">
<img id="carte-img" src="<?=$carte_url;?>" alt="<?=$carte_alt;?>" usemap="#carte-map" />
<map name="carte-map">
<?php foreach ($zones as $code => $zone) : ?>
<?php if (!empty($zone['poly'])) : ?>
<?php foreach (explode('|', $zone['poly']) as $coords) : ?>
<area shape="poly" title="<?=$zone['nom']?> (<? echo $zone['info_nombre']; if($zone['info_nombre'] > 1) {echo ' inscrits';} else { echo ' inscrit';} ?>)" class="zone-<?=$code?>" href="<?=$zone['url']?>" coords="<?=$coords?>" />
<?php endforeach; ?>
<?php endif; ?>
<?php endforeach; ?>
</map>
</div>
/trunk/composants/cartographie/squelettes/pays_asie.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
/trunk/composants/cartographie/squelettes/pays_asie.png
New file
Property changes:
Added: svn:mime-type
+image/png
\ No newline at end of property
/trunk/composants/cartographie/squelettes/pays_sud_amerique.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
/trunk/composants/cartographie/squelettes/pays_sud_amerique.png
New file
Property changes:
Added: svn:mime-type
+image/png
\ No newline at end of property
/trunk/composants/cartographie/squelettes/pays_moyen_orient.tpl.html
New file
0,0 → 1,12
<div id="cartographie">
<img id="carte-img" src="<?=$carte_url;?>" alt="<?=$carte_alt;?>" usemap="#carte-map" />
<map name="carte-map">
<?php foreach ($zones as $code => $zone) : ?>
<?php if (!empty($zone['poly'])) : ?>
<?php foreach (explode('|', $zone['poly']) as $coords) : ?>
<area shape="poly" title="<?=$zone['nom']?> (<? echo $zone['info_nombre']; if($zone['info_nombre'] > 1) {echo ' inscrits';} else { echo ' inscrit';} ?>)" class="zone-<?=$code?>" href="<?=$zone['url']?>" coords="<?=$coords?>" />
<?php endforeach; ?>
<?php endif; ?>
<?php endforeach; ?>
</map>
</div>
/trunk/composants/cartographie/squelettes/continents.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
/trunk/composants/cartographie/squelettes/continents.png
New file
Property changes:
Added: svn:mime-type
+image/png
\ No newline at end of property
/trunk/composants/cartographie/squelettes/pays_asie.csv
New file
0,0 → 1,0
"code","rvb_fond","nom","poly"
/trunk/composants/cartographie/squelettes/pays_nord_amerique.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
/trunk/composants/cartographie/squelettes/pays_nord_amerique.png
New file
Property changes:
Added: svn:mime-type
+image/png
\ No newline at end of property
/trunk/composants/cartographie/squelettes/pays_sud_amerique.csv
New file
0,0 → 1,0
"code","rvb_fond","nom","poly"
/trunk/composants/cartographie/squelettes/pays_afrique.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
/trunk/composants/cartographie/squelettes/pays_afrique.png
New file
Property changes:
Added: svn:mime-type
+image/png
\ No newline at end of property
/trunk/composants/cartographie/squelettes/pays_europe.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
/trunk/composants/cartographie/squelettes/pays_europe.png
New file
Property changes:
Added: svn:mime-type
+image/png
\ No newline at end of property
/trunk/composants/cartographie/squelettes/pays_asie.tpl.html
New file
0,0 → 1,12
<div id="cartographie">
<img id="carte-img" src="<?=$carte_url;?>" alt="<?=$carte_alt;?>" usemap="#carte-map" />
<map name="carte-map">
<?php foreach ($zones as $code => $zone) : ?>
<?php if (!empty($zone['poly'])) : ?>
<?php foreach (explode('|', $zone['poly']) as $coords) : ?>
<area shape="poly" title="<?=$zone['nom']?> (<? echo $zone['info_nombre']; if($zone['info_nombre'] > 1) {echo ' inscrits';} else { echo ' inscrit';} ?>)" class="zone-<?=$code?>" href="<?=$zone['url']?>" coords="<?=$coords?>" />
<?php endforeach; ?>
<?php endif; ?>
<?php endforeach; ?>
</map>
</div>
/trunk/composants/cartographie/squelettes/continents.csv
New file
0,0 → 1,9
"code","rvb_fond","nom","poly"
"1","60-174-15","Afrique","383,202,349,217,334,194,334,183,320,176,293,168,271,174,213,174,249,245,249,353,383,353"
"2","128-218-141","Amérique du Nord","0,220,116,220,116,225,153,224,153,211,200,211,200,199,206,199,206,193,220,193,212,174,296,0,0,0"
"3","189-179-25","Asie","579,20,579,150,501,225,501,252,494,252,485,249,473,254,384,256,383,193,392,193,392,182,398,182,396,181,396,171,401,172,401,166,409,166,409,156,355,156,357,154,358,150,354,146,360,142,363,143,377,144,378,132,381,131,379,127,382,125,381,122,378,117,384,110,384,87,379,79,379,20,431,20"
"4","0-128-218","Europe","287,19,214,173,269,173,286,168,298,168,319,175,319,166,323,165,327,157,336,158,344,163,355,164,353,156,356,152,352,145,360,140,364,143,377,143,376,131,380,130,377,127,381,123,376,117,384,107,384,98,384,94,382,86,378,80,378,20"
"5","206-0-0","Océanie","578,151,502,226,502,253,495,253,486,250,473,255,384,256,384,353,579,353"
"6","255-125-0","Amérique du Sud","222,194,207,194,207,200,201,200,201,212,154,212,154,225,114,225,114,221,0,221,0,353,248,353,248,246"
"7","0-0-255","Moyen-Orient","408,157,354,157,357,164,344,165,335,160,328,159,324,166,320,168,321,175,335,182,335,194,350,216,382,203,382,192,391,192,391,181,396,181,395,171,400,171,400,165,408,165,408,162"
"0","255-255-255",,
/trunk/composants/Composant.php
New file
0,0 → 1,13
<?php
 
class Composant {
 
public static function fabrique($classe, $options = array()) {
$classe_nom = implode('', array_map('ucfirst', explode('_', $classe)));
require_once dirname(__FILE__).DS.$classe.DS.$classe_nom.'.php';
$Composant = new $classe_nom($options);
return $Composant;
}
}
?>
Property changes:
Added: svn:executable
+*
\ No newline at end of property