import v1.1.0_beta1 | 2009-08-21
This commit is contained in:
parent
2c1152f0d3
commit
8dee6b1a10
157
Acl.php
157
Acl.php
@ -10,102 +10,115 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
self::$acl->addRole(new Zend_Acl_Role(User::ROLE_GUEST))
|
self::$acl->addRole(new Zend_Acl_Role(Users_Model_User::ROLE_GUEST))
|
||||||
->addRole(new Zend_Acl_Role(User::ROLE_REGISTERED), User::ROLE_GUEST)
|
->addRole(new Zend_Acl_Role(Users_Model_User::ROLE_REGISTERED), Users_Model_User::ROLE_GUEST)
|
||||||
->addRole(new Zend_Acl_Role(User::ROLE_ADMIN), User::ROLE_REGISTERED);
|
->addRole(new Zend_Acl_Role(Users_Model_User::ROLE_ADMIN), Users_Model_User::ROLE_REGISTERED);
|
||||||
|
|
||||||
/**************************
|
/**************************
|
||||||
* ACTION CONTROLLER PRIVILEGES
|
* ACTION CONTROLLER PRIVILEGES
|
||||||
*
|
*
|
||||||
* format: $privileges[module][controller][action] = role;
|
* format: $privileges[module][controller][action] = role;
|
||||||
**************************/
|
**************************/
|
||||||
$privileges['default']['index']['index'] = User::ROLE_GUEST;
|
$privileges['default']['index']['index'] = Users_Model_User::ROLE_GUEST;
|
||||||
$privileges['default']['identity']['index'] = User::ROLE_GUEST;
|
$privileges['default']['identity']['index'] = Users_Model_User::ROLE_GUEST;
|
||||||
$privileges['default']['identity']['id'] = User::ROLE_GUEST;
|
$privileges['default']['identity']['id'] = Users_Model_User::ROLE_GUEST;
|
||||||
|
|
||||||
$privileges['default']['error']['error'] = User::ROLE_GUEST;
|
$privileges['default']['error']['error'] = Users_Model_User::ROLE_GUEST;
|
||||||
|
|
||||||
$privileges['default']['openid']['provider'] = User::ROLE_GUEST;
|
$privileges['default']['openid']['provider'] = Users_Model_User::ROLE_GUEST;
|
||||||
$privileges['default']['openid']['login'] = User::ROLE_GUEST;
|
$privileges['default']['openid']['login'] = Users_Model_User::ROLE_GUEST;
|
||||||
$privileges['default']['openid']['authenticate'] = User::ROLE_GUEST;
|
$privileges['default']['openid']['authenticate'] = Users_Model_User::ROLE_GUEST;
|
||||||
$privileges['default']['openid']['trust'] = User::ROLE_GUEST;
|
$privileges['default']['openid']['trust'] = Users_Model_User::ROLE_REGISTERED;
|
||||||
|
$privileges['default']['openid']['proceed'] = Users_Model_User::ROLE_REGISTERED;
|
||||||
|
|
||||||
$privileges['default']['sites']['index'] = User::ROLE_REGISTERED;
|
$privileges['default']['sites']['index'] = Users_Model_User::ROLE_REGISTERED;
|
||||||
$privileges['default']['sites']['list'] = User::ROLE_REGISTERED;
|
$privileges['default']['sites']['list'] = Users_Model_User::ROLE_REGISTERED;
|
||||||
$privileges['default']['sites']['deny'] = User::ROLE_REGISTERED;
|
$privileges['default']['sites']['deny'] = Users_Model_User::ROLE_REGISTERED;
|
||||||
$privileges['default']['sites']['allow'] = User::ROLE_REGISTERED;
|
$privileges['default']['sites']['allow'] = Users_Model_User::ROLE_REGISTERED;
|
||||||
$privileges['default']['sites']['delete'] = User::ROLE_REGISTERED;
|
$privileges['default']['sites']['delete'] = Users_Model_User::ROLE_REGISTERED;
|
||||||
|
|
||||||
$privileges['default']['history']['index'] = User::ROLE_REGISTERED;
|
$privileges['default']['history']['index'] = Users_Model_User::ROLE_REGISTERED;
|
||||||
$privileges['default']['history']['list'] = User::ROLE_REGISTERED;
|
$privileges['default']['history']['list'] = Users_Model_User::ROLE_REGISTERED;
|
||||||
$privileges['default']['history']['clear'] = User::ROLE_REGISTERED;
|
$privileges['default']['history']['clear'] = Users_Model_User::ROLE_REGISTERED;
|
||||||
|
|
||||||
$privileges['default']['messageusers']['index'] = User::ROLE_ADMIN;
|
$privileges['default']['messageusers']['index'] = Users_Model_User::ROLE_ADMIN;
|
||||||
$privileges['default']['messageusers']['send'] = User::ROLE_ADMIN;
|
$privileges['default']['messageusers']['send'] = Users_Model_User::ROLE_ADMIN;
|
||||||
|
|
||||||
$privileges['default']['maintenancemode']['enable'] = User::ROLE_ADMIN;
|
$privileges['default']['maintenancemode']['enable'] = Users_Model_User::ROLE_ADMIN;
|
||||||
$privileges['default']['maintenancemode']['disable'] = User::ROLE_ADMIN;
|
$privileges['default']['maintenancemode']['disable'] = Users_Model_User::ROLE_ADMIN;
|
||||||
|
|
||||||
$privileges['default']['feedback']['index'] = User::ROLE_GUEST;
|
$privileges['default']['feedback']['index'] = Users_Model_User::ROLE_GUEST;
|
||||||
$privileges['default']['feedback']['send'] = User::ROLE_GUEST;
|
$privileges['default']['feedback']['send'] = Users_Model_User::ROLE_GUEST;
|
||||||
|
|
||||||
$privileges['default']['privacy']['index'] = User::ROLE_GUEST;
|
$privileges['default']['privacy']['index'] = Users_Model_User::ROLE_GUEST;
|
||||||
|
|
||||||
$privileges['default']['about']['index'] = User::ROLE_GUEST;
|
$privileges['default']['about']['index'] = Users_Model_User::ROLE_GUEST;
|
||||||
|
|
||||||
$privileges['default']['learnmore']['index'] = User::ROLE_GUEST;
|
$privileges['default']['learnmore']['index'] = Users_Model_User::ROLE_GUEST;
|
||||||
|
|
||||||
$privileges['install']['index']['index'] = User::ROLE_GUEST;
|
$privileges['default']['cid']['index'] = Users_Model_User::ROLE_ADMIN;
|
||||||
$privileges['install']['permissions']['index'] = User::ROLE_GUEST;
|
|
||||||
$privileges['install']['credentials']['index'] = User::ROLE_GUEST;
|
|
||||||
$privileges['install']['credentials']['save'] = User::ROLE_GUEST;
|
|
||||||
$privileges['install']['complete']['index'] = User::ROLE_GUEST;
|
|
||||||
|
|
||||||
$privileges['users']['login']['index'] = User::ROLE_GUEST;
|
$privileges['install']['index']['index'] = Users_Model_User::ROLE_GUEST;
|
||||||
$privileges['users']['login']['logout'] = User::ROLE_GUEST;
|
$privileges['install']['permissions']['index'] = Users_Model_User::ROLE_GUEST;
|
||||||
$privileges['users']['login']['authenticate'] = User::ROLE_GUEST;
|
$privileges['install']['credentials']['index'] = Users_Model_User::ROLE_GUEST;
|
||||||
|
$privileges['install']['credentials']['save'] = Users_Model_User::ROLE_GUEST;
|
||||||
|
$privileges['install']['complete']['index'] = Users_Model_User::ROLE_GUEST;
|
||||||
|
$privileges['install']['upgrade']['index'] = Users_Model_User::ROLE_GUEST;
|
||||||
|
$privileges['install']['upgrade']['proceed'] = Users_Model_User::ROLE_GUEST;
|
||||||
|
|
||||||
$privileges['users']['userlist']['index'] = User::ROLE_ADMIN;
|
$privileges['users']['login']['index'] = Users_Model_User::ROLE_GUEST;
|
||||||
|
$privileges['users']['login']['logout'] = Users_Model_User::ROLE_GUEST;
|
||||||
|
$privileges['users']['login']['authenticate'] = Users_Model_User::ROLE_GUEST;
|
||||||
|
|
||||||
$privileges['users']['register']['index'] = User::ROLE_GUEST;
|
$privileges['users']['userlist']['index'] = Users_Model_User::ROLE_ADMIN;
|
||||||
$privileges['users']['register']['save'] = User::ROLE_GUEST;
|
|
||||||
$privileges['users']['register']['eula'] = User::ROLE_GUEST;
|
|
||||||
$privileges['users']['register']['declineeula'] = User::ROLE_GUEST;
|
|
||||||
$privileges['users']['register']['accepteula'] = User::ROLE_GUEST;
|
|
||||||
|
|
||||||
$privileges['users']['profile']['index'] = User::ROLE_REGISTERED;
|
$privileges['users']['register']['index'] = Users_Model_User::ROLE_GUEST;
|
||||||
$privileges['users']['profile']['edit'] = User::ROLE_REGISTERED;
|
$privileges['users']['register']['save'] = Users_Model_User::ROLE_GUEST;
|
||||||
$privileges['users']['profile']['save'] = User::ROLE_REGISTERED;
|
$privileges['users']['register']['eula'] = Users_Model_User::ROLE_GUEST;
|
||||||
|
$privileges['users']['register']['declineeula'] = Users_Model_User::ROLE_GUEST;
|
||||||
|
$privileges['users']['register']['accepteula'] = Users_Model_User::ROLE_GUEST;
|
||||||
|
|
||||||
$privileges['users']['personalinfo']['index'] = User::ROLE_REGISTERED;
|
$privileges['users']['profile']['index'] = Users_Model_User::ROLE_REGISTERED;
|
||||||
$privileges['users']['personalinfo']['show'] = User::ROLE_REGISTERED;
|
$privileges['users']['profile']['edit'] = Users_Model_User::ROLE_REGISTERED;
|
||||||
$privileges['users']['personalinfo']['edit'] = User::ROLE_REGISTERED;
|
$privileges['users']['profile']['save'] = Users_Model_User::ROLE_REGISTERED;
|
||||||
$privileges['users']['personalinfo']['save'] = User::ROLE_REGISTERED;
|
|
||||||
|
|
||||||
$privileges['users']['profilegeneral']['accountinfo'] = User::ROLE_REGISTERED;
|
$privileges['users']['personalinfo']['index'] = Users_Model_User::ROLE_REGISTERED;
|
||||||
$privileges['users']['profilegeneral']['editaccountinfo'] = User::ROLE_REGISTERED;
|
$privileges['users']['personalinfo']['show'] = Users_Model_User::ROLE_REGISTERED;
|
||||||
$privileges['users']['profilegeneral']['saveaccountinfo'] = User::ROLE_REGISTERED;
|
$privileges['users']['personalinfo']['edit'] = Users_Model_User::ROLE_REGISTERED;
|
||||||
$privileges['users']['profilegeneral']['changepassword'] = User::ROLE_REGISTERED;
|
$privileges['users']['personalinfo']['save'] = Users_Model_User::ROLE_REGISTERED;
|
||||||
$privileges['users']['profilegeneral']['savepassword'] = User::ROLE_REGISTERED;
|
|
||||||
$privileges['users']['profilegeneral']['confirmdelete'] = User::ROLE_REGISTERED;
|
|
||||||
$privileges['users']['profilegeneral']['delete'] = User::ROLE_REGISTERED;
|
|
||||||
|
|
||||||
$privileges['users']['recoverpassword']['index'] = User::ROLE_GUEST;
|
$privileges['users']['profilegeneral']['accountinfo'] = Users_Model_User::ROLE_REGISTERED;
|
||||||
$privileges['users']['recoverpassword']['send'] = User::ROLE_GUEST;
|
$privileges['users']['profilegeneral']['editaccountinfo'] = Users_Model_User::ROLE_REGISTERED;
|
||||||
$privileges['users']['recoverpassword']['reset'] = User::ROLE_GUEST;
|
$privileges['users']['profilegeneral']['saveaccountinfo'] = Users_Model_User::ROLE_REGISTERED;
|
||||||
|
$privileges['users']['profilegeneral']['changepassword'] = Users_Model_User::ROLE_REGISTERED;
|
||||||
|
$privileges['users']['profilegeneral']['savepassword'] = Users_Model_User::ROLE_REGISTERED;
|
||||||
|
$privileges['users']['profilegeneral']['confirmdelete'] = Users_Model_User::ROLE_REGISTERED;
|
||||||
|
$privileges['users']['profilegeneral']['delete'] = Users_Model_User::ROLE_REGISTERED;
|
||||||
|
|
||||||
$privileges['users']['manageusers']['index'] = User::ROLE_ADMIN;
|
$privileges['users']['recoverpassword']['index'] = Users_Model_User::ROLE_GUEST;
|
||||||
$privileges['users']['manageusers']['delete'] = User::ROLE_ADMIN;
|
$privileges['users']['recoverpassword']['send'] = Users_Model_User::ROLE_GUEST;
|
||||||
$privileges['users']['manageusers']['deleteunconfirmed'] = User::ROLE_ADMIN;
|
$privileges['users']['recoverpassword']['reset'] = Users_Model_User::ROLE_GUEST;
|
||||||
|
|
||||||
$privileges['users']['userslist']['index'] = User::ROLE_ADMIN;
|
$privileges['users']['manageusers']['index'] = Users_Model_User::ROLE_ADMIN;
|
||||||
|
$privileges['users']['manageusers']['delete'] = Users_Model_User::ROLE_ADMIN;
|
||||||
|
$privileges['users']['manageusers']['deleteunconfirmed'] = Users_Model_User::ROLE_ADMIN;
|
||||||
|
$privileges['users']['manageusers']['sendreminder'] = Users_Model_User::ROLE_ADMIN;
|
||||||
|
|
||||||
$privileges['stats']['index']['index'] = User::ROLE_ADMIN;
|
$privileges['users']['userslist']['index'] = Users_Model_User::ROLE_ADMIN;
|
||||||
$privileges['stats']['registrations']['index'] = User::ROLE_ADMIN;
|
|
||||||
$privileges['stats']['registrations']['graph'] = User::ROLE_ADMIN;
|
$privileges['stats']['index']['index'] = Users_Model_User::ROLE_ADMIN;
|
||||||
$privileges['stats']['authorizations']['index'] = User::ROLE_ADMIN;
|
$privileges['stats']['registrations']['index'] = Users_Model_User::ROLE_ADMIN;
|
||||||
$privileges['stats']['authorizations']['graph'] = User::ROLE_ADMIN;
|
$privileges['stats']['registrations']['graph'] = Users_Model_User::ROLE_ADMIN;
|
||||||
$privileges['stats']['sites']['index'] = User::ROLE_ADMIN;
|
$privileges['stats']['authorizations']['index'] = Users_Model_User::ROLE_ADMIN;
|
||||||
$privileges['stats']['sites']['graph'] = User::ROLE_ADMIN;
|
$privileges['stats']['authorizations']['graph'] = Users_Model_User::ROLE_ADMIN;
|
||||||
$privileges['stats']['top']['index'] = User::ROLE_ADMIN;
|
$privileges['stats']['sites']['index'] = Users_Model_User::ROLE_ADMIN;
|
||||||
$privileges['stats']['top']['graph'] = User::ROLE_ADMIN;
|
$privileges['stats']['sites']['graph'] = Users_Model_User::ROLE_ADMIN;
|
||||||
|
$privileges['stats']['top']['index'] = Users_Model_User::ROLE_ADMIN;
|
||||||
|
$privileges['stats']['top']['graph'] = Users_Model_User::ROLE_ADMIN;
|
||||||
|
|
||||||
|
$privileges['news']['index']['index'] = Users_Model_User::ROLE_GUEST;
|
||||||
|
$privileges['news']['view']['index'] = Users_Model_User::ROLE_GUEST;
|
||||||
|
$privileges['news']['edit']['add'] = Users_Model_User::ROLE_ADMIN;
|
||||||
|
$privileges['news']['edit']['index'] = Users_Model_User::ROLE_ADMIN;
|
||||||
|
$privileges['news']['edit']['save'] = Users_Model_User::ROLE_ADMIN;
|
||||||
|
$privileges['news']['edit']['delete'] = Users_Model_User::ROLE_ADMIN;
|
||||||
|
298
Application.php
Executable file
298
Application.php
Executable file
@ -0,0 +1,298 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @copyright Copyright (C) 2005-2009 Keyboard Monkeys Ltd. http://www.kb-m.com
|
||||||
|
* @license http://creativecommons.org/licenses/BSD/ BSD License
|
||||||
|
* @author Keyboard Monkey Ltd
|
||||||
|
* @since CommunityID 0.9
|
||||||
|
* @package CommunityID
|
||||||
|
* @packager Keyboard Monkeys
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Application
|
||||||
|
{
|
||||||
|
const VERSION = '1.1.0.beta1';
|
||||||
|
|
||||||
|
public static $config;
|
||||||
|
public static $logger;
|
||||||
|
public static $mockLogger;
|
||||||
|
public static $acl;
|
||||||
|
public static $front;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used in unit tests
|
||||||
|
*/
|
||||||
|
public static function cleanUp()
|
||||||
|
{
|
||||||
|
Zend_Registry::_unsetInstance();
|
||||||
|
Zend_Layout::resetMvcInstance();
|
||||||
|
Zend_Controller_Action_HelperBroker::resetHelpers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function setIncludePath()
|
||||||
|
{
|
||||||
|
$pathList = array(
|
||||||
|
'.',
|
||||||
|
APP_DIR,
|
||||||
|
APP_DIR.'/libs',
|
||||||
|
// this should go at the end to avoid clashes with other Zend Framework versions in the machine
|
||||||
|
get_include_path(),
|
||||||
|
);
|
||||||
|
if (!set_include_path(implode(PATH_SEPARATOR, $pathList))) {
|
||||||
|
die('ERROR: couldn\'t execute PHP\'s set_include_path() function in your system.'
|
||||||
|
.' Please ask your system admin to enable that functionality.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function setAutoLoader()
|
||||||
|
{
|
||||||
|
require_once 'Zend/Loader/Autoloader.php';
|
||||||
|
$loader = Zend_Loader_Autoloader::getInstance();
|
||||||
|
$loader->registerNamespace('Monkeys_');
|
||||||
|
$loader->registerNamespace('CommunityID');
|
||||||
|
$loader->registerNamespace('Auth');
|
||||||
|
new Monkeys_Application_Module_Autoloader(array(
|
||||||
|
'namespace' => '',
|
||||||
|
'basePath' => APP_DIR . '/modules/default',
|
||||||
|
));
|
||||||
|
new Monkeys_Application_Module_Autoloader(array(
|
||||||
|
'namespace' => 'Users',
|
||||||
|
'basePath' => APP_DIR . '/modules/users',
|
||||||
|
));
|
||||||
|
new Monkeys_Application_Module_Autoloader(array(
|
||||||
|
'namespace' => 'News',
|
||||||
|
'basePath' => APP_DIR . '/modules/news',
|
||||||
|
));
|
||||||
|
new Monkeys_Application_Module_Autoloader(array(
|
||||||
|
'namespace' => 'Stats',
|
||||||
|
'basePath' => APP_DIR . '/modules/stats',
|
||||||
|
));
|
||||||
|
new Monkeys_Application_Module_Autoloader(array(
|
||||||
|
'namespace' => 'Install',
|
||||||
|
'basePath' => APP_DIR . '/modules/install',
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function setConfig()
|
||||||
|
{
|
||||||
|
if (file_exists(APP_DIR . DIRECTORY_SEPARATOR . 'config.php')) {
|
||||||
|
$configFile = APP_DIR . DIRECTORY_SEPARATOR . 'config.php';
|
||||||
|
} else {
|
||||||
|
$configFile = APP_DIR . DIRECTORY_SEPARATOR . 'config.default.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
$config = array();
|
||||||
|
require $configFile;
|
||||||
|
self::$config = new Zend_Config($config, array('allowModifications' => true));
|
||||||
|
if(self::$config->environment->installed === null) {
|
||||||
|
$configFile = APP_DIR . DIRECTORY_SEPARATOR . 'config.default.php';
|
||||||
|
require $configFile;
|
||||||
|
self::$config = new Zend_Config($config, array('allowModifications' => true));
|
||||||
|
}
|
||||||
|
|
||||||
|
// @todo: remove this when all interconnected apps use the same LDAP source
|
||||||
|
self::$config->environment->app = 'communityid';
|
||||||
|
|
||||||
|
Zend_Registry::set('config', self::$config);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function setErrorReporting()
|
||||||
|
{
|
||||||
|
ini_set('log_errors', 'Off');
|
||||||
|
if (self::$config->environment->production) {
|
||||||
|
error_reporting(E_ALL & E_NOTICE);
|
||||||
|
ini_set('display_errors', 'Off');
|
||||||
|
} else {
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
ini_set('display_errors', 'On');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function setLogger($addMockWriter = false)
|
||||||
|
{
|
||||||
|
self::$logger = new Zend_Log();
|
||||||
|
if (self::$config->logging->level == 0) {
|
||||||
|
self::$logger->addWriter(new Zend_Log_Writer_Null(APP_DIR . '/log.txt'));
|
||||||
|
} else {
|
||||||
|
if (is_writable(self::$config->logging->location)) {
|
||||||
|
$file = self::$config->logging->location;
|
||||||
|
} else if (!is_writable(APP_DIR . DIRECTORY_SEPARATOR . self::$config->logging->location)) {
|
||||||
|
throw new Exception('Couldn\'t find log file, or maybe it\'s not writable');
|
||||||
|
} else {
|
||||||
|
$file = APP_DIR . DIRECTORY_SEPARATOR . self::$config->logging->location;
|
||||||
|
}
|
||||||
|
|
||||||
|
self::$logger->addWriter(new Zend_Log_Writer_Stream($file));
|
||||||
|
if ($addMockWriter) {
|
||||||
|
self::$mockLogger = new Zend_Log_Writer_Mock();
|
||||||
|
self::$logger->addWriter(self::$mockLogger);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self::$logger->addFilter(new Zend_Log_Filter_Priority((int)self::$config->logging->level));
|
||||||
|
Zend_Registry::set('logger', self::$logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function logRequest()
|
||||||
|
{
|
||||||
|
if (isset($_SERVER['REQUEST_URI'])) {
|
||||||
|
self::$logger->log('REQUESTED URI: ' . $_SERVER['REQUEST_URI'], Zend_Log::INFO);
|
||||||
|
} else {
|
||||||
|
self::$logger->log('REQUESTED THROUGH CLI: ' . $GLOBALS['argv'][0], Zend_Log::INFO);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($_POST) && $_POST) {
|
||||||
|
self::$logger->log('POST payload: ' . print_r($_POST, 1), Zend_Log::INFO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function setDatabase()
|
||||||
|
{
|
||||||
|
self::$config->database->params->driver_options = array(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true);
|
||||||
|
$db = Zend_Db::factory(self::$config->database);
|
||||||
|
if (self::$config->logging->level == Zend_Log::DEBUG) {
|
||||||
|
$profiler = new Monkeys_Db_Profiler();
|
||||||
|
$db->setProfiler($profiler);
|
||||||
|
}
|
||||||
|
Zend_Db_Table_Abstract::setDefaultAdapter($db);
|
||||||
|
// unknown PHP bug (tested on PHP 2.8 and PHP 2.10) corrupts the $db reference, so I gotta retrieve it again:
|
||||||
|
$db = Zend_Db_Table_Abstract::getDefaultAdapter();
|
||||||
|
Zend_Registry::set('db', $db);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$db->getConnection();
|
||||||
|
return true;
|
||||||
|
} catch (Zend_Db_Adapter_Exception $e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function setSession()
|
||||||
|
{
|
||||||
|
// The framework doesn't provide yet a clean way of doing this
|
||||||
|
if (isset($_POST['rememberme'])) {
|
||||||
|
Zend_Session::rememberMe();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZF still doesn't have facilities for session_name().
|
||||||
|
session_name(self::$config->environment->session_name);
|
||||||
|
|
||||||
|
$appSession = new Zend_Session_Namespace('Default');
|
||||||
|
if (is_null($appSession->messages)) {
|
||||||
|
$appSession->messages = array();
|
||||||
|
}
|
||||||
|
Zend_Registry::set('appSession', $appSession);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function setAcl()
|
||||||
|
{
|
||||||
|
self::$acl = new Zend_Acl();
|
||||||
|
require 'Acl.php';
|
||||||
|
|
||||||
|
foreach ($privileges as $module => $moduleConfig) {
|
||||||
|
foreach ($moduleConfig as $controller => $controllerConfig) {
|
||||||
|
self::$acl->add(new Zend_Acl_Resource($module . '_' . $controller));
|
||||||
|
foreach ($controllerConfig as $action => $role) {
|
||||||
|
self::$acl->allow($role, $module . '_' . $controller, $action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Zend_Registry::set('acl', self::$acl);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function setI18N()
|
||||||
|
{
|
||||||
|
if (self::$config->environment->locale == 'auto') {
|
||||||
|
try {
|
||||||
|
$locale = new Zend_Locale(Zend_Locale::BROWSER);
|
||||||
|
} catch (Zend_Locale_Exception $e) {
|
||||||
|
// happens when no browser around, e.g. when calling the rest api by other means
|
||||||
|
$locale = new Zend_Locale('en_US');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$locale = new Zend_Locale(self::$config->environment->locale);
|
||||||
|
}
|
||||||
|
Zend_Registry::set('Zend_Locale', $locale);
|
||||||
|
$translate = new Zend_Translate('gettext',
|
||||||
|
APP_DIR . '/languages',
|
||||||
|
$locale->toString(),
|
||||||
|
array(
|
||||||
|
'scan' => Zend_Translate::LOCALE_DIRECTORY,
|
||||||
|
'disableNotices' => true));
|
||||||
|
Zend_Registry::set('Zend_Translate', $translate);
|
||||||
|
|
||||||
|
return $translate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function setLayout()
|
||||||
|
{
|
||||||
|
$template = self::$config->environment->template;
|
||||||
|
|
||||||
|
// Hack: Explicitly add the ViewRenderer, so that when an exception is thrown,
|
||||||
|
// the layout is not shown (should be better handled in ZF 1.6)
|
||||||
|
// @see http://framework.zend.com/issues/browse/ZF-2993?focusedCommentId=23121#action_23121
|
||||||
|
Zend_Controller_Action_HelperBroker::addHelper(new Zend_Controller_Action_Helper_ViewRenderer());
|
||||||
|
|
||||||
|
Zend_Layout::startMvc(array(
|
||||||
|
'layoutPath' => $template == 'default'? APP_DIR.'/views/layouts' : APP_DIR."/views/layouts_$template",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function setFrontController()
|
||||||
|
{
|
||||||
|
self::$front = Zend_Controller_Front::getInstance();
|
||||||
|
self::$front->registerPlugin(new Monkeys_Controller_Plugin_Auth(self::$acl));
|
||||||
|
self::$front->addModuleDirectory(APP_DIR.'/modules');
|
||||||
|
|
||||||
|
$router = self::$front->getRouter();
|
||||||
|
|
||||||
|
if (self::$config->subdomain->enabled) {
|
||||||
|
if (self::$config->subdomain->use_www) {
|
||||||
|
$reqs = array('username' => '([^w]|w[^w][^w]|ww[^w]|www.+).*');
|
||||||
|
} else {
|
||||||
|
$reqs = array();
|
||||||
|
}
|
||||||
|
$hostNameRoute = new Zend_Controller_Router_Route_Hostname(
|
||||||
|
':username.' . self::$config->subdomain->hostname,
|
||||||
|
array(
|
||||||
|
'module' => 'default',
|
||||||
|
'controller' => 'identity',
|
||||||
|
'action' => 'id',
|
||||||
|
),
|
||||||
|
$reqs
|
||||||
|
);
|
||||||
|
$router->addRoute('hostNameRoute', $hostNameRoute);
|
||||||
|
}
|
||||||
|
|
||||||
|
$route = new Zend_Controller_Router_Route(
|
||||||
|
'identity/:userid',
|
||||||
|
array(
|
||||||
|
'module' => 'default',
|
||||||
|
'controller' => 'identity',
|
||||||
|
'action' => 'id',
|
||||||
|
),
|
||||||
|
array('userid' => '[\w-]*')
|
||||||
|
);
|
||||||
|
$router->addRoute('identityRoute', $route);
|
||||||
|
|
||||||
|
$route = new Zend_Controller_Router_Route(
|
||||||
|
'news/:id',
|
||||||
|
array(
|
||||||
|
'module' => 'news',
|
||||||
|
'controller' => 'view',
|
||||||
|
'action' => 'index',
|
||||||
|
),
|
||||||
|
array('id' => '\d+')
|
||||||
|
);
|
||||||
|
$router->addRoute('articleView', $route);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function dispatch()
|
||||||
|
{
|
||||||
|
self::$front->dispatch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* this is just a global function used to mark translations
|
||||||
|
*/
|
||||||
|
function translate() {}
|
55
CHANGELOG
55
CHANGELOG
@ -1,6 +1,56 @@
|
|||||||
|
2009-08-21 Reiner Jung <reiner@kb-m.com>
|
||||||
|
|
||||||
|
NEW FEATURES:
|
||||||
|
|
||||||
|
- Community-ID news feed has been moved to a new About section, visible
|
||||||
|
only by admins.
|
||||||
|
- News in the home page are now manageable by the admin.
|
||||||
|
- Brute-force login attempts are now mitigated through the appearance of
|
||||||
|
a captcha after the third failed attempt, in both the main page login
|
||||||
|
section, and when trying to log-in while during an OpenID authentication.
|
||||||
|
- Removed requirement of having short_open_tag php.ini directive to be On.
|
||||||
|
- The user's OpenID URL is now visible in all pages when he's logged in.
|
||||||
|
- The Manage Users section now has a search field.
|
||||||
|
- You're able to delete unconfirmed users that have not confirmed their
|
||||||
|
account for a given number of days.
|
||||||
|
- You're able to send a reminder to unconfirmed users that have not
|
||||||
|
confirmed their account for a given number of days.
|
||||||
|
- Added sorting ability for the History Log table. Have it sort from
|
||||||
|
latest to oldest by default.
|
||||||
|
- Replaced rich-text editor in the Message Users section with the more
|
||||||
|
capable FCK Editor.
|
||||||
|
- Rich-text editor messages are filtered through the HTMLPurifier lib,
|
||||||
|
that filters out XSS and other malignous content.
|
||||||
|
- Upgraded Zend Framework to version 1.8.4PL1
|
||||||
|
|
||||||
|
|
||||||
|
FIXED BUGS:
|
||||||
|
|
||||||
|
- Fixed compatibility with OpenID relays that send their info through
|
||||||
|
POST instead of GET.
|
||||||
|
- Fixed support for relays not sending the OpenID identifier. This fixes
|
||||||
|
Facebook compatibility.
|
||||||
|
- Fixed clashes with other Zend Frameworks located in PHP's include path.
|
||||||
|
- Now only ascii characters will be allowed in the usernames, to avoid
|
||||||
|
problems in the OpenID URL.
|
||||||
|
- Fixed pagination issues in the Manage Users section.
|
||||||
|
- Fixed pagination issues in the History Log section.
|
||||||
|
- Fixed problems in the Feedback and Message Users forms.
|
||||||
|
- Mass-mailing to users will have the recipients in BCC instead of TO,
|
||||||
|
to avoid revealing E-mails to all recipients.
|
||||||
|
- Fixed layout issue of the login checkbox "Remember me", under IE and
|
||||||
|
Opera.
|
||||||
|
- Fixed some javascript error messages under IE.
|
||||||
|
|
||||||
|
|
||||||
|
NEW REQUIREMENTS:
|
||||||
|
|
||||||
|
- Minimal supported PHP version is 5.2.4
|
||||||
|
|
||||||
2009-04-21 Reiner Jung <reiner@kb-m.com>
|
2009-04-21 Reiner Jung <reiner@kb-m.com>
|
||||||
|
|
||||||
New features:
|
NEW FEATURES:
|
||||||
|
|
||||||
- Added configuration directives to support OpenID URLs using subdomains.
|
- Added configuration directives to support OpenID URLs using subdomains.
|
||||||
- Add a configuration directives to set the number of news items to show.
|
- Add a configuration directives to set the number of news items to show.
|
||||||
- When in maintenance mode, have a warning message explaining, and disable the login section.
|
- When in maintenance mode, have a warning message explaining, and disable the login section.
|
||||||
@ -11,6 +61,7 @@ New features:
|
|||||||
- Check if set_include_path() is supported by the current PHP configuration.
|
- Check if set_include_path() is supported by the current PHP configuration.
|
||||||
- Moved from PDO Mysql to MySQLi database back-end, to avoid problems under Windows servers.
|
- Moved from PDO Mysql to MySQLi database back-end, to avoid problems under Windows servers.
|
||||||
|
|
||||||
Bug fixes:
|
FIXED BUGS:
|
||||||
|
|
||||||
- Was throwing an exception when logging in during an openid authentication.
|
- Was throwing an exception when logging in during an openid authentication.
|
||||||
- Wasn't showing 'denied' or 'authorized' in the history list
|
- Wasn't showing 'denied' or 'authorized' in the history list
|
||||||
|
@ -16,4 +16,3 @@ Translations
|
|||||||
Testing
|
Testing
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
11
INSTALL
11
INSTALL
@ -1,4 +1,13 @@
|
|||||||
This is the initial Install file for Community-ID. We will work on this file soon.
|
This is the initial Install file for Community-ID.
|
||||||
|
|
||||||
|
UPGRADE PROCEDURE:
|
||||||
|
|
||||||
|
- Replace all files with the new release, only conserving the config.php file.
|
||||||
|
- When going to the site, the upgrade will be detected automatically,
|
||||||
|
and you'll be asked to enter the admin credentials to proceed with the
|
||||||
|
upgrade.
|
||||||
|
|
||||||
|
INSTALL PROCEDURE:
|
||||||
|
|
||||||
For more information how to install Community-ID please have a look at the projekt wiki:
|
For more information how to install Community-ID please have a look at the projekt wiki:
|
||||||
|
|
||||||
|
6
README
6
README
@ -1 +1,5 @@
|
|||||||
import things form https://sourceforge.net/projects/communityid/files/
|
009-08-21 Reiner Jung <reiner@kb-m.com>
|
||||||
|
|
||||||
|
NEW REQUIREMENTS:
|
||||||
|
|
||||||
|
- Minimal supported PHP version is 5.2.4
|
||||||
|
@ -9,18 +9,18 @@
|
|||||||
* @packager Keyboard Monkeys
|
* @packager Keyboard Monkeys
|
||||||
*/
|
*/
|
||||||
|
|
||||||
require 'Setup.php';
|
require 'Application.php';
|
||||||
|
|
||||||
Setup::setIncludePath();
|
Application::setIncludePath();
|
||||||
Setup::setAutoLoader();
|
Application::setAutoLoader();
|
||||||
Setup::setConfig();
|
Application::setConfig();
|
||||||
Setup::setErrorReporting();
|
Application::setErrorReporting();
|
||||||
Setup::setLogger();
|
Application::setLogger();
|
||||||
Setup::logRequest();
|
Application::logRequest();
|
||||||
Setup::setDatabase();
|
Application::setDatabase();
|
||||||
Setup::setSession();
|
Application::setSession();
|
||||||
Setup::setAcl();
|
Application::setAcl();
|
||||||
Setup::setI18N();
|
Application::setI18N();
|
||||||
Setup::setLayout();
|
Application::setLayout();
|
||||||
Setup::setFrontController();
|
Application::setFrontController();
|
||||||
Setup::dispatch();
|
Application::dispatch();
|
||||||
|
@ -18,14 +18,6 @@ $config['environment']['locale'] = 'auto';
|
|||||||
|
|
||||||
$config['environment']['template'] = 'default';
|
$config['environment']['template'] = 'default';
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# ------- HOME NEWS FEED ------------
|
|
||||||
#
|
|
||||||
$config['news_feed']['url'] = 'http://source.keyboard-monkeys.org/projects/communityid/news?format=atom';
|
|
||||||
$config['news_feed']['num_items'] = 3;
|
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# ------- LOGGING ------------
|
# ------- LOGGING ------------
|
||||||
#
|
#
|
||||||
|
@ -20,13 +20,6 @@ $config['environment']['template'] = '{environment.template}';
|
|||||||
$config['environment']['news_feed'] = '{environment.news_feed}';
|
$config['environment']['news_feed'] = '{environment.news_feed}';
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# ------- HOME NEWS FEED ------------
|
|
||||||
#
|
|
||||||
$config['news_feed']['url'] = '{news_feed.url}';
|
|
||||||
$config['news_feed']['num_items'] = {news_feed.num_items};
|
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# ------- LOGGING ------------
|
# ------- LOGGING ------------
|
||||||
#
|
#
|
||||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
552
libs/Auth/OpenID.php
Normal file
552
libs/Auth/OpenID.php
Normal file
@ -0,0 +1,552 @@
|
|||||||
|
<?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-2008 Janrain, Inc.
|
||||||
|
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The library version string
|
||||||
|
*/
|
||||||
|
define('Auth_OpenID_VERSION', '2.1.2');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Require the fetcher code.
|
||||||
|
*/
|
||||||
|
require_once "Auth/Yadis/PlainHTTPFetcher.php";
|
||||||
|
require_once "Auth/Yadis/ParanoidHTTPFetcher.php";
|
||||||
|
require_once "Auth/OpenID/BigMath.php";
|
||||||
|
require_once "Auth/OpenID/URINorm.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) {
|
||||||
|
Auth_OpenID_setNoMathSupport();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The OpenID utility function class.
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
class Auth_OpenID {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if $thing is an Auth_OpenID_FailureResponse object;
|
||||||
|
* false if not.
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
function isFailure($thing)
|
||||||
|
{
|
||||||
|
return is_a($thing, 'Auth_OpenID_FailureResponse');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the query data from the server environment based on the
|
||||||
|
* request method used. If GET was used, this looks at
|
||||||
|
* $_SERVER['QUERY_STRING'] directly. If POST was used, this
|
||||||
|
* fetches data from the special php://input file stream.
|
||||||
|
*
|
||||||
|
* Returns an associative array of the query arguments.
|
||||||
|
*
|
||||||
|
* Skips invalid key/value pairs (i.e. keys with no '=value'
|
||||||
|
* portion).
|
||||||
|
*
|
||||||
|
* Returns an empty array if neither GET nor POST was used, or if
|
||||||
|
* POST was used but php://input cannot be opened.
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
function getQuery($query_str=null)
|
||||||
|
{
|
||||||
|
$data = array();
|
||||||
|
|
||||||
|
if ($query_str !== null) {
|
||||||
|
$data = Auth_OpenID::params_from_string($query_str);
|
||||||
|
} else if (!array_key_exists('REQUEST_METHOD', $_SERVER)) {
|
||||||
|
// Do nothing.
|
||||||
|
} else {
|
||||||
|
// XXX HACK FIXME HORRIBLE.
|
||||||
|
//
|
||||||
|
// POSTing to a URL with query parameters is acceptable, but
|
||||||
|
// we don't have a clean way to distinguish those parameters
|
||||||
|
// when we need to do things like return_to verification
|
||||||
|
// which only want to look at one kind of parameter. We're
|
||||||
|
// going to emulate the behavior of some other environments
|
||||||
|
// by defaulting to GET and overwriting with POST if POST
|
||||||
|
// data is available.
|
||||||
|
$data = Auth_OpenID::params_from_string($_SERVER['QUERY_STRING']);
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||||
|
$str = file_get_contents('php://input');
|
||||||
|
|
||||||
|
if ($str === false) {
|
||||||
|
$post = array();
|
||||||
|
} else {
|
||||||
|
$post = Auth_OpenID::params_from_string($str);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = array_merge($data, $post);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
function params_from_string($str)
|
||||||
|
{
|
||||||
|
$chunks = explode("&", $str);
|
||||||
|
|
||||||
|
$data = array();
|
||||||
|
foreach ($chunks as $chunk) {
|
||||||
|
$parts = explode("=", $chunk, 2);
|
||||||
|
|
||||||
|
if (count($parts) != 2) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
list($k, $v) = $parts;
|
||||||
|
$data[$k] = urldecode($v);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 {
|
||||||
|
$parent_dir = dirname($dir_name);
|
||||||
|
|
||||||
|
// Terminal case; there is no parent directory to create.
|
||||||
|
if ($parent_dir == $dir_name) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (Auth_OpenID::ensureDir($parent_dir) && @mkdir($dir_name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a string prefix to all values of an array. Returns a new
|
||||||
|
* array containing the prefixed values.
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
function addPrefix($values, $prefix)
|
||||||
|
{
|
||||||
|
$new_values = array();
|
||||||
|
foreach ($values as $s) {
|
||||||
|
$new_values[] = $prefix . $s;
|
||||||
|
}
|
||||||
|
return $new_values;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience function for getting array values. Given an array
|
||||||
|
* $arr and a key $key, get the corresponding value from the array
|
||||||
|
* or return $default if the key is absent.
|
||||||
|
*
|
||||||
|
* @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 (key = ".$key.") expected " .
|
||||||
|
"array as first parameter, got " .
|
||||||
|
gettype($arr), E_USER_WARNING);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replacement for PHP's broken parse_str.
|
||||||
|
*/
|
||||||
|
function parse_str($query)
|
||||||
|
{
|
||||||
|
if ($query === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$parts = explode('&', $query);
|
||||||
|
|
||||||
|
$new_parts = array();
|
||||||
|
for ($i = 0; $i < count($parts); $i++) {
|
||||||
|
$pair = explode('=', $parts[$i]);
|
||||||
|
|
||||||
|
if (count($pair) != 2) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
list($key, $value) = $pair;
|
||||||
|
$new_parts[$key] = urldecode($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $new_parts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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).
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
@$parsed = parse_url($url);
|
||||||
|
|
||||||
|
if (!$parsed) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($parsed['scheme']) &&
|
||||||
|
isset($parsed['host'])) {
|
||||||
|
$scheme = strtolower($parsed['scheme']);
|
||||||
|
if (!in_array($scheme, array('http', 'https'))) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$url = 'http://' . $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
$normalized = Auth_OpenID_urinorm($url);
|
||||||
|
if ($normalized === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
list($defragged, $frag) = Auth_OpenID::urldefrag($normalized);
|
||||||
|
return $defragged;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replacement (wrapper) for PHP's intval() because it's broken.
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
function intval($value)
|
||||||
|
{
|
||||||
|
$re = "/^\\d+$/";
|
||||||
|
|
||||||
|
if (!preg_match($re, $value)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return intval($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count the number of bytes in a string independently of
|
||||||
|
* multibyte support conditions.
|
||||||
|
*
|
||||||
|
* @param string $str The string of bytes to count.
|
||||||
|
* @return int The number of bytes in $str.
|
||||||
|
*/
|
||||||
|
function bytes($str)
|
||||||
|
{
|
||||||
|
return strlen(bin2hex($str)) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the bytes in a string independently of multibyte support
|
||||||
|
* conditions.
|
||||||
|
*/
|
||||||
|
function toBytes($str)
|
||||||
|
{
|
||||||
|
$hex = bin2hex($str);
|
||||||
|
|
||||||
|
if (!$hex) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$b = array();
|
||||||
|
for ($i = 0; $i < strlen($hex); $i += 2) {
|
||||||
|
$b[] = chr(base_convert(substr($hex, $i, 2), 16, 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $b;
|
||||||
|
}
|
||||||
|
|
||||||
|
function urldefrag($url)
|
||||||
|
{
|
||||||
|
$parts = explode("#", $url, 2);
|
||||||
|
|
||||||
|
if (count($parts) == 1) {
|
||||||
|
return array($parts[0], "");
|
||||||
|
} else {
|
||||||
|
return $parts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function filter($callback, &$sequence)
|
||||||
|
{
|
||||||
|
$result = array();
|
||||||
|
|
||||||
|
foreach ($sequence as $item) {
|
||||||
|
if (call_user_func_array($callback, array($item))) {
|
||||||
|
$result[] = $item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function update(&$dest, &$src)
|
||||||
|
{
|
||||||
|
foreach ($src as $k => $v) {
|
||||||
|
$dest[$k] = $v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrap PHP's standard error_log functionality. Use this to
|
||||||
|
* perform all logging. It will interpolate any additional
|
||||||
|
* arguments into the format string before logging.
|
||||||
|
*
|
||||||
|
* @param string $format_string The sprintf format for the message
|
||||||
|
*/
|
||||||
|
function log($format_string)
|
||||||
|
{
|
||||||
|
$args = func_get_args();
|
||||||
|
$message = call_user_func_array('sprintf', $args);
|
||||||
|
error_log($message);
|
||||||
|
}
|
||||||
|
|
||||||
|
function autoSubmitHTML($form, $title="OpenId transaction in progress")
|
||||||
|
{
|
||||||
|
return("<html>".
|
||||||
|
"<head><title>".
|
||||||
|
$title .
|
||||||
|
"</title></head>".
|
||||||
|
"<body onload='document.forms[0].submit();'>".
|
||||||
|
$form .
|
||||||
|
"<script>".
|
||||||
|
"var elements = document.forms[0].elements;".
|
||||||
|
"for (var i = 0; i < elements.length; i++) {".
|
||||||
|
" elements[i].style.display = \"none\";".
|
||||||
|
"}".
|
||||||
|
"</script>".
|
||||||
|
"</body>".
|
||||||
|
"</html>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
1023
libs/Auth/OpenID/AX.php
Normal file
1023
libs/Auth/OpenID/AX.php
Normal file
File diff suppressed because it is too large
Load Diff
613
libs/Auth/OpenID/Association.php
Normal file
613
libs/Auth/OpenID/Association.php
Normal file
@ -0,0 +1,613 @@
|
|||||||
|
<?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-2008 Janrain, Inc.
|
||||||
|
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
require_once 'Auth/OpenID/CryptUtil.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
require_once 'Auth/OpenID/KVForm.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
require_once 'Auth/OpenID/HMAC.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'
|
||||||
|
);
|
||||||
|
|
||||||
|
var $_macs = array(
|
||||||
|
'HMAC-SHA1' => 'Auth_OpenID_HMACSHA1',
|
||||||
|
'HMAC-SHA256' => 'Auth_OpenID_HMACSHA256'
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 values of this field at
|
||||||
|
* this time is 'HMAC-SHA1' and 'HMAC-SHA256', 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 values of this field at
|
||||||
|
* this time is 'HMAC-SHA1' and 'HMAC-SHA256', but new types may
|
||||||
|
* be defined in the future.
|
||||||
|
*/
|
||||||
|
function Auth_OpenID_Association(
|
||||||
|
$handle, $secret, $issued, $lifetime, $assoc_type)
|
||||||
|
{
|
||||||
|
if (!in_array($assoc_type,
|
||||||
|
Auth_OpenID_getSupportedAssociationTypes())) {
|
||||||
|
$fmt = 'Unsupported association type (%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: ' . var_export($keys, true),
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* Invalid association types should be caught at constructor */
|
||||||
|
$callback = $this->_macs[$this->assoc_type];
|
||||||
|
|
||||||
|
return call_user_func_array($callback, array($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 signMessage($message)
|
||||||
|
{
|
||||||
|
if ($message->hasKey(Auth_OpenID_OPENID_NS, 'sig') ||
|
||||||
|
$message->hasKey(Auth_OpenID_OPENID_NS, 'signed')) {
|
||||||
|
// Already has a sig
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$extant_handle = $message->getArg(Auth_OpenID_OPENID_NS,
|
||||||
|
'assoc_handle');
|
||||||
|
|
||||||
|
if ($extant_handle && ($extant_handle != $this->handle)) {
|
||||||
|
// raise ValueError("Message has a different association handle")
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$signed_message = $message;
|
||||||
|
$signed_message->setArg(Auth_OpenID_OPENID_NS, 'assoc_handle',
|
||||||
|
$this->handle);
|
||||||
|
|
||||||
|
$message_keys = array_keys($signed_message->toPostArgs());
|
||||||
|
$signed_list = array();
|
||||||
|
$signed_prefix = 'openid.';
|
||||||
|
|
||||||
|
foreach ($message_keys as $k) {
|
||||||
|
if (strpos($k, $signed_prefix) === 0) {
|
||||||
|
$signed_list[] = substr($k, strlen($signed_prefix));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$signed_list[] = 'signed';
|
||||||
|
sort($signed_list);
|
||||||
|
|
||||||
|
$signed_message->setArg(Auth_OpenID_OPENID_NS, 'signed',
|
||||||
|
implode(',', $signed_list));
|
||||||
|
$sig = $this->getMessageSignature($signed_message);
|
||||||
|
$signed_message->setArg(Auth_OpenID_OPENID_NS, 'sig', $sig);
|
||||||
|
return $signed_message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a {@link Auth_OpenID_Message}, return the key/value pairs
|
||||||
|
* to be signed according to the signed list in the message. If
|
||||||
|
* the message lacks a signed list, return null.
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
function _makePairs(&$message)
|
||||||
|
{
|
||||||
|
$signed = $message->getArg(Auth_OpenID_OPENID_NS, 'signed');
|
||||||
|
if (!$signed || Auth_OpenID::isFailure($signed)) {
|
||||||
|
// raise ValueError('Message has no signed list: %s' % (message,))
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$signed_list = explode(',', $signed);
|
||||||
|
$pairs = array();
|
||||||
|
$data = $message->toPostArgs();
|
||||||
|
foreach ($signed_list as $field) {
|
||||||
|
$pairs[] = array($field, Auth_OpenID::arrayGet($data,
|
||||||
|
'openid.' .
|
||||||
|
$field, ''));
|
||||||
|
}
|
||||||
|
return $pairs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given an {@link Auth_OpenID_Message}, return the signature for
|
||||||
|
* the signed list in the message.
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
function getMessageSignature(&$message)
|
||||||
|
{
|
||||||
|
$pairs = $this->_makePairs($message);
|
||||||
|
return base64_encode($this->sign($pairs));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Confirm that the signature of these fields matches the
|
||||||
|
* signature contained in the data.
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
function checkMessageSignature(&$message)
|
||||||
|
{
|
||||||
|
$sig = $message->getArg(Auth_OpenID_OPENID_NS,
|
||||||
|
'sig');
|
||||||
|
|
||||||
|
if (!$sig || Auth_OpenID::isFailure($sig)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$calculated_sig = $this->getMessageSignature($message);
|
||||||
|
return $calculated_sig == $sig;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Auth_OpenID_getSecretSize($assoc_type)
|
||||||
|
{
|
||||||
|
if ($assoc_type == 'HMAC-SHA1') {
|
||||||
|
return 20;
|
||||||
|
} else if ($assoc_type == 'HMAC-SHA256') {
|
||||||
|
return 32;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Auth_OpenID_getAllAssociationTypes()
|
||||||
|
{
|
||||||
|
return array('HMAC-SHA1', 'HMAC-SHA256');
|
||||||
|
}
|
||||||
|
|
||||||
|
function Auth_OpenID_getSupportedAssociationTypes()
|
||||||
|
{
|
||||||
|
$a = array('HMAC-SHA1');
|
||||||
|
|
||||||
|
if (Auth_OpenID_HMACSHA256_SUPPORTED) {
|
||||||
|
$a[] = 'HMAC-SHA256';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $a;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Auth_OpenID_getSessionTypes($assoc_type)
|
||||||
|
{
|
||||||
|
$assoc_to_session = array(
|
||||||
|
'HMAC-SHA1' => array('DH-SHA1', 'no-encryption'));
|
||||||
|
|
||||||
|
if (Auth_OpenID_HMACSHA256_SUPPORTED) {
|
||||||
|
$assoc_to_session['HMAC-SHA256'] =
|
||||||
|
array('DH-SHA256', 'no-encryption');
|
||||||
|
}
|
||||||
|
|
||||||
|
return Auth_OpenID::arrayGet($assoc_to_session, $assoc_type, array());
|
||||||
|
}
|
||||||
|
|
||||||
|
function Auth_OpenID_checkSessionType($assoc_type, $session_type)
|
||||||
|
{
|
||||||
|
if (!in_array($session_type,
|
||||||
|
Auth_OpenID_getSessionTypes($assoc_type))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Auth_OpenID_getDefaultAssociationOrder()
|
||||||
|
{
|
||||||
|
$order = array();
|
||||||
|
|
||||||
|
if (!Auth_OpenID_noMathSupport()) {
|
||||||
|
$order[] = array('HMAC-SHA1', 'DH-SHA1');
|
||||||
|
|
||||||
|
if (Auth_OpenID_HMACSHA256_SUPPORTED) {
|
||||||
|
$order[] = array('HMAC-SHA256', 'DH-SHA256');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$order[] = array('HMAC-SHA1', 'no-encryption');
|
||||||
|
|
||||||
|
if (Auth_OpenID_HMACSHA256_SUPPORTED) {
|
||||||
|
$order[] = array('HMAC-SHA256', 'no-encryption');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $order;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Auth_OpenID_getOnlyEncryptedOrder()
|
||||||
|
{
|
||||||
|
$result = array();
|
||||||
|
|
||||||
|
foreach (Auth_OpenID_getDefaultAssociationOrder() as $pair) {
|
||||||
|
list($assoc, $session) = $pair;
|
||||||
|
|
||||||
|
if ($session != 'no-encryption') {
|
||||||
|
if (Auth_OpenID_HMACSHA256_SUPPORTED &&
|
||||||
|
($assoc == 'HMAC-SHA256')) {
|
||||||
|
$result[] = $pair;
|
||||||
|
} else if ($assoc != 'HMAC-SHA256') {
|
||||||
|
$result[] = $pair;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function &Auth_OpenID_getDefaultNegotiator()
|
||||||
|
{
|
||||||
|
$x = new Auth_OpenID_SessionNegotiator(
|
||||||
|
Auth_OpenID_getDefaultAssociationOrder());
|
||||||
|
return $x;
|
||||||
|
}
|
||||||
|
|
||||||
|
function &Auth_OpenID_getEncryptedNegotiator()
|
||||||
|
{
|
||||||
|
$x = new Auth_OpenID_SessionNegotiator(
|
||||||
|
Auth_OpenID_getOnlyEncryptedOrder());
|
||||||
|
return $x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A session negotiator controls the allowed and preferred association
|
||||||
|
* types and association session types. Both the {@link
|
||||||
|
* Auth_OpenID_Consumer} and {@link Auth_OpenID_Server} use
|
||||||
|
* negotiators when creating associations.
|
||||||
|
*
|
||||||
|
* You can create and use negotiators if you:
|
||||||
|
|
||||||
|
* - Do not want to do Diffie-Hellman key exchange because you use
|
||||||
|
* transport-layer encryption (e.g. SSL)
|
||||||
|
*
|
||||||
|
* - Want to use only SHA-256 associations
|
||||||
|
*
|
||||||
|
* - Do not want to support plain-text associations over a non-secure
|
||||||
|
* channel
|
||||||
|
*
|
||||||
|
* It is up to you to set a policy for what kinds of associations to
|
||||||
|
* accept. By default, the library will make any kind of association
|
||||||
|
* that is allowed in the OpenID 2.0 specification.
|
||||||
|
*
|
||||||
|
* Use of negotiators in the library
|
||||||
|
* =================================
|
||||||
|
*
|
||||||
|
* When a consumer makes an association request, it calls {@link
|
||||||
|
* getAllowedType} to get the preferred association type and
|
||||||
|
* association session type.
|
||||||
|
*
|
||||||
|
* The server gets a request for a particular association/session type
|
||||||
|
* and calls {@link isAllowed} to determine if it should create an
|
||||||
|
* association. If it is supported, negotiation is complete. If it is
|
||||||
|
* not, the server calls {@link getAllowedType} to get an allowed
|
||||||
|
* association type to return to the consumer.
|
||||||
|
*
|
||||||
|
* If the consumer gets an error response indicating that the
|
||||||
|
* requested association/session type is not supported by the server
|
||||||
|
* that contains an assocation/session type to try, it calls {@link
|
||||||
|
* isAllowed} to determine if it should try again with the given
|
||||||
|
* combination of association/session type.
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
*/
|
||||||
|
class Auth_OpenID_SessionNegotiator {
|
||||||
|
function Auth_OpenID_SessionNegotiator($allowed_types)
|
||||||
|
{
|
||||||
|
$this->allowed_types = array();
|
||||||
|
$this->setAllowedTypes($allowed_types);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the allowed association types, checking to make sure each
|
||||||
|
* combination is valid.
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
function setAllowedTypes($allowed_types)
|
||||||
|
{
|
||||||
|
foreach ($allowed_types as $pair) {
|
||||||
|
list($assoc_type, $session_type) = $pair;
|
||||||
|
if (!Auth_OpenID_checkSessionType($assoc_type, $session_type)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->allowed_types = $allowed_types;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an association type and session type to the allowed types
|
||||||
|
* list. The assocation/session pairs are tried in the order that
|
||||||
|
* they are added.
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
function addAllowedType($assoc_type, $session_type = null)
|
||||||
|
{
|
||||||
|
if ($this->allowed_types === null) {
|
||||||
|
$this->allowed_types = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($session_type === null) {
|
||||||
|
$available = Auth_OpenID_getSessionTypes($assoc_type);
|
||||||
|
|
||||||
|
if (!$available) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($available as $session_type) {
|
||||||
|
$this->addAllowedType($assoc_type, $session_type);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (Auth_OpenID_checkSessionType($assoc_type, $session_type)) {
|
||||||
|
$this->allowed_types[] = array($assoc_type, $session_type);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is this combination of association type and session type allowed?
|
||||||
|
function isAllowed($assoc_type, $session_type)
|
||||||
|
{
|
||||||
|
$assoc_good = in_array(array($assoc_type, $session_type),
|
||||||
|
$this->allowed_types);
|
||||||
|
|
||||||
|
$matches = in_array($session_type,
|
||||||
|
Auth_OpenID_getSessionTypes($assoc_type));
|
||||||
|
|
||||||
|
return ($assoc_good && $matches);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a pair of assocation type and session type that are
|
||||||
|
* supported.
|
||||||
|
*/
|
||||||
|
function getAllowedType()
|
||||||
|
{
|
||||||
|
if (!$this->allowed_types) {
|
||||||
|
return array(null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->allowed_types[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
471
libs/Auth/OpenID/BigMath.php
Normal file
471
libs/Auth/OpenID/BigMath.php
Normal file
@ -0,0 +1,471 @@
|
|||||||
|
<?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-2008 Janrain, Inc.
|
||||||
|
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Needed for random number generation
|
||||||
|
*/
|
||||||
|
require_once 'Auth/OpenID/CryptUtil.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Need Auth_OpenID::bytes().
|
||||||
|
*/
|
||||||
|
require_once 'Auth/OpenID.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 = Auth_OpenID::bytes($rbytes) - 1;
|
||||||
|
} else {
|
||||||
|
$nbytes = Auth_OpenID::bytes($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.
|
||||||
|
*/
|
||||||
|
function Auth_OpenID_math_extensions()
|
||||||
|
{
|
||||||
|
$result = array();
|
||||||
|
|
||||||
|
if (!defined('Auth_OpenID_BUGGY_GMP')) {
|
||||||
|
$result[] =
|
||||||
|
array('modules' => array('gmp', 'php_gmp'),
|
||||||
|
'extension' => 'gmp',
|
||||||
|
'class' => 'Auth_OpenID_GmpMathWrapper');
|
||||||
|
}
|
||||||
|
|
||||||
|
$result[] = array(
|
||||||
|
'modules' => array('bcmath', 'php_bcmath'),
|
||||||
|
'extension' => 'bcmath',
|
||||||
|
'class' => 'Auth_OpenID_BcMathWrapper');
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* result of {@link Auth_OpenID_math_extensions()} 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 (Auth_OpenID_noMathSupport()) {
|
||||||
|
$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.
|
||||||
|
$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);
|
||||||
|
|
||||||
|
Auth_OpenID_setNoMathSupport();
|
||||||
|
|
||||||
|
$result = null;
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instantiate a new wrapper
|
||||||
|
$class = $ext['class'];
|
||||||
|
$lib = new $class();
|
||||||
|
|
||||||
|
return $lib;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Auth_OpenID_setNoMathSupport()
|
||||||
|
{
|
||||||
|
if (!defined('Auth_OpenID_NO_MATH_SUPPORT')) {
|
||||||
|
define('Auth_OpenID_NO_MATH_SUPPORT', true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Auth_OpenID_noMathSupport()
|
||||||
|
{
|
||||||
|
return defined('Auth_OpenID_NO_MATH_SUPPORT');
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
2230
libs/Auth/OpenID/Consumer.php
Normal file
2230
libs/Auth/OpenID/Consumer.php
Normal file
File diff suppressed because it is too large
Load Diff
109
libs/Auth/OpenID/CryptUtil.php
Normal file
109
libs/Auth/OpenID/CryptUtil.php
Normal 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-2008 Janrain, Inc.
|
||||||
|
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
|
||||||
|
*/
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
131
libs/Auth/OpenID/DatabaseConnection.php
Normal file
131
libs/Auth/OpenID/DatabaseConnection.php
Normal 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-2008 Janrain, Inc.
|
||||||
|
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
113
libs/Auth/OpenID/DiffieHellman.php
Normal file
113
libs/Auth/OpenID/DiffieHellman.php
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
<?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-2008 Janrain, Inc.
|
||||||
|
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once 'Auth/OpenID.php';
|
||||||
|
require_once 'Auth/OpenID/BigMath.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
function usingDefaultValues()
|
||||||
|
{
|
||||||
|
return ($this->mod == Auth_OpenID_getDefaultMod() &&
|
||||||
|
$this->gen == Auth_OpenID_getDefaultGen());
|
||||||
|
}
|
||||||
|
|
||||||
|
function xorSecret($composite, $secret, $hash_func)
|
||||||
|
{
|
||||||
|
$dh_shared = $this->getSharedSecret($composite);
|
||||||
|
$dh_shared_str = $this->lib->longToBinary($dh_shared);
|
||||||
|
$hash_dh_shared = $hash_func($dh_shared_str);
|
||||||
|
|
||||||
|
$xsecret = "";
|
||||||
|
for ($i = 0; $i < Auth_OpenID::bytes($secret); $i++) {
|
||||||
|
$xsecret .= chr(ord($secret[$i]) ^ ord($hash_dh_shared[$i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $xsecret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
548
libs/Auth/OpenID/Discover.php
Normal file
548
libs/Auth/OpenID/Discover.php
Normal file
@ -0,0 +1,548 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The OpenID and Yadis discovery implementation for OpenID 1.2.
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once "Auth/OpenID.php";
|
||||||
|
require_once "Auth/OpenID/Parse.php";
|
||||||
|
require_once "Auth/OpenID/Message.php";
|
||||||
|
require_once "Auth/Yadis/XRIRes.php";
|
||||||
|
require_once "Auth/Yadis/Yadis.php";
|
||||||
|
|
||||||
|
// XML namespace value
|
||||||
|
define('Auth_OpenID_XMLNS_1_0', 'http://openid.net/xmlns/1.0');
|
||||||
|
|
||||||
|
// Yadis service types
|
||||||
|
define('Auth_OpenID_TYPE_1_2', 'http://openid.net/signon/1.2');
|
||||||
|
define('Auth_OpenID_TYPE_1_1', 'http://openid.net/signon/1.1');
|
||||||
|
define('Auth_OpenID_TYPE_1_0', 'http://openid.net/signon/1.0');
|
||||||
|
define('Auth_OpenID_TYPE_2_0_IDP', 'http://specs.openid.net/auth/2.0/server');
|
||||||
|
define('Auth_OpenID_TYPE_2_0', 'http://specs.openid.net/auth/2.0/signon');
|
||||||
|
define('Auth_OpenID_RP_RETURN_TO_URL_TYPE',
|
||||||
|
'http://specs.openid.net/auth/2.0/return_to');
|
||||||
|
|
||||||
|
function Auth_OpenID_getOpenIDTypeURIs()
|
||||||
|
{
|
||||||
|
return array(Auth_OpenID_TYPE_2_0_IDP,
|
||||||
|
Auth_OpenID_TYPE_2_0,
|
||||||
|
Auth_OpenID_TYPE_1_2,
|
||||||
|
Auth_OpenID_TYPE_1_1,
|
||||||
|
Auth_OpenID_TYPE_1_0,
|
||||||
|
Auth_OpenID_RP_RETURN_TO_URL_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Object representing an OpenID service endpoint.
|
||||||
|
*/
|
||||||
|
class Auth_OpenID_ServiceEndpoint {
|
||||||
|
function Auth_OpenID_ServiceEndpoint()
|
||||||
|
{
|
||||||
|
$this->claimed_id = null;
|
||||||
|
$this->server_url = null;
|
||||||
|
$this->type_uris = array();
|
||||||
|
$this->local_id = null;
|
||||||
|
$this->canonicalID = null;
|
||||||
|
$this->used_yadis = false; // whether this came from an XRDS
|
||||||
|
$this->display_identifier = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDisplayIdentifier()
|
||||||
|
{
|
||||||
|
if ($this->display_identifier) {
|
||||||
|
return $this->display_identifier;
|
||||||
|
}
|
||||||
|
if (! $this->claimed_id) {
|
||||||
|
return $this->claimed_id;
|
||||||
|
}
|
||||||
|
$parsed = parse_url($this->claimed_id);
|
||||||
|
$scheme = $parsed['scheme'];
|
||||||
|
$host = $parsed['host'];
|
||||||
|
$path = $parsed['path'];
|
||||||
|
if (array_key_exists('query', $parsed)) {
|
||||||
|
$query = $parsed['query'];
|
||||||
|
$no_frag = "$scheme://$host$path?$query";
|
||||||
|
} else {
|
||||||
|
$no_frag = "$scheme://$host$path";
|
||||||
|
}
|
||||||
|
return $no_frag;
|
||||||
|
}
|
||||||
|
|
||||||
|
function usesExtension($extension_uri)
|
||||||
|
{
|
||||||
|
return in_array($extension_uri, $this->type_uris);
|
||||||
|
}
|
||||||
|
|
||||||
|
function preferredNamespace()
|
||||||
|
{
|
||||||
|
if (in_array(Auth_OpenID_TYPE_2_0_IDP, $this->type_uris) ||
|
||||||
|
in_array(Auth_OpenID_TYPE_2_0, $this->type_uris)) {
|
||||||
|
return Auth_OpenID_OPENID2_NS;
|
||||||
|
} else {
|
||||||
|
return Auth_OpenID_OPENID1_NS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Query this endpoint to see if it has any of the given type
|
||||||
|
* URIs. This is useful for implementing other endpoint classes
|
||||||
|
* that e.g. need to check for the presence of multiple versions
|
||||||
|
* of a single protocol.
|
||||||
|
*
|
||||||
|
* @param $type_uris The URIs that you wish to check
|
||||||
|
*
|
||||||
|
* @return all types that are in both in type_uris and
|
||||||
|
* $this->type_uris
|
||||||
|
*/
|
||||||
|
function matchTypes($type_uris)
|
||||||
|
{
|
||||||
|
$result = array();
|
||||||
|
foreach ($type_uris as $test_uri) {
|
||||||
|
if ($this->supportsType($test_uri)) {
|
||||||
|
$result[] = $test_uri;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function supportsType($type_uri)
|
||||||
|
{
|
||||||
|
// Does this endpoint support this type?
|
||||||
|
return ((in_array($type_uri, $this->type_uris)) ||
|
||||||
|
(($type_uri == Auth_OpenID_TYPE_2_0) &&
|
||||||
|
$this->isOPIdentifier()));
|
||||||
|
}
|
||||||
|
|
||||||
|
function compatibilityMode()
|
||||||
|
{
|
||||||
|
return $this->preferredNamespace() != Auth_OpenID_OPENID2_NS;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isOPIdentifier()
|
||||||
|
{
|
||||||
|
return in_array(Auth_OpenID_TYPE_2_0_IDP, $this->type_uris);
|
||||||
|
}
|
||||||
|
|
||||||
|
function fromOPEndpointURL($op_endpoint_url)
|
||||||
|
{
|
||||||
|
// Construct an OP-Identifier OpenIDServiceEndpoint object for
|
||||||
|
// a given OP Endpoint URL
|
||||||
|
$obj = new Auth_OpenID_ServiceEndpoint();
|
||||||
|
$obj->server_url = $op_endpoint_url;
|
||||||
|
$obj->type_uris = array(Auth_OpenID_TYPE_2_0_IDP);
|
||||||
|
return $obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseService($yadis_url, $uri, $type_uris, $service_element)
|
||||||
|
{
|
||||||
|
// Set the state of this object based on the contents of the
|
||||||
|
// service element. Return true if successful, false if not
|
||||||
|
// (if findOPLocalIdentifier returns false).
|
||||||
|
$this->type_uris = $type_uris;
|
||||||
|
$this->server_url = $uri;
|
||||||
|
$this->used_yadis = true;
|
||||||
|
|
||||||
|
if (!$this->isOPIdentifier()) {
|
||||||
|
$this->claimed_id = $yadis_url;
|
||||||
|
$this->local_id = Auth_OpenID_findOPLocalIdentifier(
|
||||||
|
$service_element,
|
||||||
|
$this->type_uris);
|
||||||
|
if ($this->local_id === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLocalID()
|
||||||
|
{
|
||||||
|
// Return the identifier that should be sent as the
|
||||||
|
// openid.identity_url parameter to the server.
|
||||||
|
if ($this->local_id === null && $this->canonicalID === null) {
|
||||||
|
return $this->claimed_id;
|
||||||
|
} else {
|
||||||
|
if ($this->local_id) {
|
||||||
|
return $this->local_id;
|
||||||
|
} else {
|
||||||
|
return $this->canonicalID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse the given document as XRDS looking for OpenID services.
|
||||||
|
*
|
||||||
|
* @return array of Auth_OpenID_ServiceEndpoint or null if the
|
||||||
|
* document cannot be parsed.
|
||||||
|
*/
|
||||||
|
function fromXRDS($uri, $xrds_text)
|
||||||
|
{
|
||||||
|
$xrds =& Auth_Yadis_XRDS::parseXRDS($xrds_text);
|
||||||
|
|
||||||
|
if ($xrds) {
|
||||||
|
$yadis_services =
|
||||||
|
$xrds->services(array('filter_MatchesAnyOpenIDType'));
|
||||||
|
return Auth_OpenID_makeOpenIDEndpoints($uri, $yadis_services);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create endpoints from a DiscoveryResult.
|
||||||
|
*
|
||||||
|
* @param discoveryResult Auth_Yadis_DiscoveryResult
|
||||||
|
* @return array of Auth_OpenID_ServiceEndpoint or null if
|
||||||
|
* endpoints cannot be created.
|
||||||
|
*/
|
||||||
|
function fromDiscoveryResult($discoveryResult)
|
||||||
|
{
|
||||||
|
if ($discoveryResult->isXRDS()) {
|
||||||
|
return Auth_OpenID_ServiceEndpoint::fromXRDS(
|
||||||
|
$discoveryResult->normalized_uri,
|
||||||
|
$discoveryResult->response_text);
|
||||||
|
} else {
|
||||||
|
return Auth_OpenID_ServiceEndpoint::fromHTML(
|
||||||
|
$discoveryResult->normalized_uri,
|
||||||
|
$discoveryResult->response_text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function fromHTML($uri, $html)
|
||||||
|
{
|
||||||
|
$discovery_types = array(
|
||||||
|
array(Auth_OpenID_TYPE_2_0,
|
||||||
|
'openid2.provider', 'openid2.local_id'),
|
||||||
|
array(Auth_OpenID_TYPE_1_1,
|
||||||
|
'openid.server', 'openid.delegate')
|
||||||
|
);
|
||||||
|
|
||||||
|
$services = array();
|
||||||
|
|
||||||
|
foreach ($discovery_types as $triple) {
|
||||||
|
list($type_uri, $server_rel, $delegate_rel) = $triple;
|
||||||
|
|
||||||
|
$urls = Auth_OpenID_legacy_discover($html, $server_rel,
|
||||||
|
$delegate_rel);
|
||||||
|
|
||||||
|
if ($urls === false) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
list($delegate_url, $server_url) = $urls;
|
||||||
|
|
||||||
|
$service = new Auth_OpenID_ServiceEndpoint();
|
||||||
|
$service->claimed_id = $uri;
|
||||||
|
$service->local_id = $delegate_url;
|
||||||
|
$service->server_url = $server_url;
|
||||||
|
$service->type_uris = array($type_uri);
|
||||||
|
|
||||||
|
$services[] = $service;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $services;
|
||||||
|
}
|
||||||
|
|
||||||
|
function copy()
|
||||||
|
{
|
||||||
|
$x = new Auth_OpenID_ServiceEndpoint();
|
||||||
|
|
||||||
|
$x->claimed_id = $this->claimed_id;
|
||||||
|
$x->server_url = $this->server_url;
|
||||||
|
$x->type_uris = $this->type_uris;
|
||||||
|
$x->local_id = $this->local_id;
|
||||||
|
$x->canonicalID = $this->canonicalID;
|
||||||
|
$x->used_yadis = $this->used_yadis;
|
||||||
|
|
||||||
|
return $x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Auth_OpenID_findOPLocalIdentifier($service, $type_uris)
|
||||||
|
{
|
||||||
|
// Extract a openid:Delegate value from a Yadis Service element.
|
||||||
|
// If no delegate is found, returns null. Returns false on
|
||||||
|
// discovery failure (when multiple delegate/localID tags have
|
||||||
|
// different values).
|
||||||
|
|
||||||
|
$service->parser->registerNamespace('openid',
|
||||||
|
Auth_OpenID_XMLNS_1_0);
|
||||||
|
|
||||||
|
$service->parser->registerNamespace('xrd',
|
||||||
|
Auth_Yadis_XMLNS_XRD_2_0);
|
||||||
|
|
||||||
|
$parser =& $service->parser;
|
||||||
|
|
||||||
|
$permitted_tags = array();
|
||||||
|
|
||||||
|
if (in_array(Auth_OpenID_TYPE_1_1, $type_uris) ||
|
||||||
|
in_array(Auth_OpenID_TYPE_1_0, $type_uris)) {
|
||||||
|
$permitted_tags[] = 'openid:Delegate';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_array(Auth_OpenID_TYPE_2_0, $type_uris)) {
|
||||||
|
$permitted_tags[] = 'xrd:LocalID';
|
||||||
|
}
|
||||||
|
|
||||||
|
$local_id = null;
|
||||||
|
|
||||||
|
foreach ($permitted_tags as $tag_name) {
|
||||||
|
$tags = $service->getElements($tag_name);
|
||||||
|
|
||||||
|
foreach ($tags as $tag) {
|
||||||
|
$content = $parser->content($tag);
|
||||||
|
|
||||||
|
if ($local_id === null) {
|
||||||
|
$local_id = $content;
|
||||||
|
} else if ($local_id != $content) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $local_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
function filter_MatchesAnyOpenIDType(&$service)
|
||||||
|
{
|
||||||
|
$uris = $service->getTypes();
|
||||||
|
|
||||||
|
foreach ($uris as $uri) {
|
||||||
|
if (in_array($uri, Auth_OpenID_getOpenIDTypeURIs())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Auth_OpenID_bestMatchingService($service, $preferred_types)
|
||||||
|
{
|
||||||
|
// Return the index of the first matching type, or something
|
||||||
|
// higher if no type matches.
|
||||||
|
//
|
||||||
|
// This provides an ordering in which service elements that
|
||||||
|
// contain a type that comes earlier in the preferred types list
|
||||||
|
// come before service elements that come later. If a service
|
||||||
|
// element has more than one type, the most preferred one wins.
|
||||||
|
|
||||||
|
foreach ($preferred_types as $index => $typ) {
|
||||||
|
if (in_array($typ, $service->type_uris)) {
|
||||||
|
return $index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count($preferred_types);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Auth_OpenID_arrangeByType($service_list, $preferred_types)
|
||||||
|
{
|
||||||
|
// Rearrange service_list in a new list so services are ordered by
|
||||||
|
// types listed in preferred_types. Return the new list.
|
||||||
|
|
||||||
|
// Build a list with the service elements in tuples whose
|
||||||
|
// comparison will prefer the one with the best matching service
|
||||||
|
$prio_services = array();
|
||||||
|
foreach ($service_list as $index => $service) {
|
||||||
|
$prio_services[] = array(Auth_OpenID_bestMatchingService($service,
|
||||||
|
$preferred_types),
|
||||||
|
$index, $service);
|
||||||
|
}
|
||||||
|
|
||||||
|
sort($prio_services);
|
||||||
|
|
||||||
|
// Now that the services are sorted by priority, remove the sort
|
||||||
|
// keys from the list.
|
||||||
|
foreach ($prio_services as $index => $s) {
|
||||||
|
$prio_services[$index] = $prio_services[$index][2];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $prio_services;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract OP Identifier services. If none found, return the rest,
|
||||||
|
// sorted with most preferred first according to
|
||||||
|
// OpenIDServiceEndpoint.openid_type_uris.
|
||||||
|
//
|
||||||
|
// openid_services is a list of OpenIDServiceEndpoint objects.
|
||||||
|
//
|
||||||
|
// Returns a list of OpenIDServiceEndpoint objects."""
|
||||||
|
function Auth_OpenID_getOPOrUserServices($openid_services)
|
||||||
|
{
|
||||||
|
$op_services = Auth_OpenID_arrangeByType($openid_services,
|
||||||
|
array(Auth_OpenID_TYPE_2_0_IDP));
|
||||||
|
|
||||||
|
$openid_services = Auth_OpenID_arrangeByType($openid_services,
|
||||||
|
Auth_OpenID_getOpenIDTypeURIs());
|
||||||
|
|
||||||
|
if ($op_services) {
|
||||||
|
return $op_services;
|
||||||
|
} else {
|
||||||
|
return $openid_services;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Auth_OpenID_makeOpenIDEndpoints($uri, $yadis_services)
|
||||||
|
{
|
||||||
|
$s = array();
|
||||||
|
|
||||||
|
if (!$yadis_services) {
|
||||||
|
return $s;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($yadis_services as $service) {
|
||||||
|
$type_uris = $service->getTypes();
|
||||||
|
$uris = $service->getURIs();
|
||||||
|
|
||||||
|
// If any Type URIs match and there is an endpoint URI
|
||||||
|
// specified, then this is an OpenID endpoint
|
||||||
|
if ($type_uris &&
|
||||||
|
$uris) {
|
||||||
|
foreach ($uris as $service_uri) {
|
||||||
|
$openid_endpoint = new Auth_OpenID_ServiceEndpoint();
|
||||||
|
if ($openid_endpoint->parseService($uri,
|
||||||
|
$service_uri,
|
||||||
|
$type_uris,
|
||||||
|
$service)) {
|
||||||
|
$s[] = $openid_endpoint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $s;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Auth_OpenID_discoverWithYadis($uri, &$fetcher,
|
||||||
|
$endpoint_filter='Auth_OpenID_getOPOrUserServices',
|
||||||
|
$discover_function=null)
|
||||||
|
{
|
||||||
|
// Discover OpenID services for a URI. Tries Yadis and falls back
|
||||||
|
// on old-style <link rel='...'> discovery if Yadis fails.
|
||||||
|
|
||||||
|
// Might raise a yadis.discover.DiscoveryFailure if no document
|
||||||
|
// came back for that URI at all. I don't think falling back to
|
||||||
|
// OpenID 1.0 discovery on the same URL will help, so don't bother
|
||||||
|
// to catch it.
|
||||||
|
if ($discover_function === null) {
|
||||||
|
$discover_function = array('Auth_Yadis_Yadis', 'discover');
|
||||||
|
}
|
||||||
|
|
||||||
|
$openid_services = array();
|
||||||
|
|
||||||
|
$response = call_user_func_array($discover_function,
|
||||||
|
array($uri, &$fetcher));
|
||||||
|
|
||||||
|
$yadis_url = $response->normalized_uri;
|
||||||
|
$yadis_services = array();
|
||||||
|
|
||||||
|
if ($response->isFailure()) {
|
||||||
|
return array($uri, array());
|
||||||
|
}
|
||||||
|
|
||||||
|
$openid_services = Auth_OpenID_ServiceEndpoint::fromXRDS(
|
||||||
|
$yadis_url,
|
||||||
|
$response->response_text);
|
||||||
|
|
||||||
|
if (!$openid_services) {
|
||||||
|
if ($response->isXRDS()) {
|
||||||
|
return Auth_OpenID_discoverWithoutYadis($uri,
|
||||||
|
$fetcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to parse the response as HTML to get OpenID 1.0/1.1
|
||||||
|
// <link rel="...">
|
||||||
|
$openid_services = Auth_OpenID_ServiceEndpoint::fromHTML(
|
||||||
|
$yadis_url,
|
||||||
|
$response->response_text);
|
||||||
|
}
|
||||||
|
|
||||||
|
$openid_services = call_user_func_array($endpoint_filter,
|
||||||
|
array(&$openid_services));
|
||||||
|
|
||||||
|
return array($yadis_url, $openid_services);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Auth_OpenID_discoverURI($uri, &$fetcher)
|
||||||
|
{
|
||||||
|
$uri = Auth_OpenID::normalizeUrl($uri);
|
||||||
|
return Auth_OpenID_discoverWithYadis($uri, $fetcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Auth_OpenID_discoverWithoutYadis($uri, &$fetcher)
|
||||||
|
{
|
||||||
|
$http_resp = @$fetcher->get($uri);
|
||||||
|
|
||||||
|
if ($http_resp->status != 200 and $http_resp->status != 206) {
|
||||||
|
return array($uri, array());
|
||||||
|
}
|
||||||
|
|
||||||
|
$identity_url = $http_resp->final_url;
|
||||||
|
|
||||||
|
// Try to parse the response as HTML to get OpenID 1.0/1.1 <link
|
||||||
|
// rel="...">
|
||||||
|
$openid_services = Auth_OpenID_ServiceEndpoint::fromHTML(
|
||||||
|
$identity_url,
|
||||||
|
$http_resp->body);
|
||||||
|
|
||||||
|
return array($identity_url, $openid_services);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Auth_OpenID_discoverXRI($iname, &$fetcher)
|
||||||
|
{
|
||||||
|
$resolver = new Auth_Yadis_ProxyResolver($fetcher);
|
||||||
|
list($canonicalID, $yadis_services) =
|
||||||
|
$resolver->query($iname,
|
||||||
|
Auth_OpenID_getOpenIDTypeURIs(),
|
||||||
|
array('filter_MatchesAnyOpenIDType'));
|
||||||
|
|
||||||
|
$openid_services = Auth_OpenID_makeOpenIDEndpoints($iname,
|
||||||
|
$yadis_services);
|
||||||
|
|
||||||
|
$openid_services = Auth_OpenID_getOPOrUserServices($openid_services);
|
||||||
|
|
||||||
|
for ($i = 0; $i < count($openid_services); $i++) {
|
||||||
|
$openid_services[$i]->canonicalID = $canonicalID;
|
||||||
|
$openid_services[$i]->claimed_id = $canonicalID;
|
||||||
|
$openid_services[$i]->display_identifier = $iname;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: returned xri should probably be in some normal form
|
||||||
|
return array($iname, $openid_services);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Auth_OpenID_discover($uri, &$fetcher)
|
||||||
|
{
|
||||||
|
// If the fetcher (i.e., PHP) doesn't support SSL, we can't do
|
||||||
|
// discovery on an HTTPS URL.
|
||||||
|
if ($fetcher->isHTTPS($uri) && !$fetcher->supportsSSL()) {
|
||||||
|
return array($uri, array());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Auth_Yadis_identifierScheme($uri) == 'XRI') {
|
||||||
|
$result = Auth_OpenID_discoverXRI($uri, $fetcher);
|
||||||
|
} else {
|
||||||
|
$result = Auth_OpenID_discoverURI($uri, $fetcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the fetcher doesn't support SSL, we can't interact with
|
||||||
|
// HTTPS server URLs; remove those endpoints from the list.
|
||||||
|
if (!$fetcher->supportsSSL()) {
|
||||||
|
$http_endpoints = array();
|
||||||
|
list($new_uri, $endpoints) = $result;
|
||||||
|
|
||||||
|
foreach ($endpoints as $e) {
|
||||||
|
if (!$fetcher->isHTTPS($e->server_url)) {
|
||||||
|
$http_endpoints[] = $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = array($new_uri, $http_endpoints);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
100
libs/Auth/OpenID/DumbStore.php
Normal file
100
libs/Auth/OpenID/DumbStore.php
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file supplies a dumb store backend for OpenID servers and
|
||||||
|
* consumers.
|
||||||
|
*
|
||||||
|
* PHP versions 4 and 5
|
||||||
|
*
|
||||||
|
* LICENSE: See the COPYING file included in this distribution.
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
* @author JanRain, Inc. <openid@janrain.com>
|
||||||
|
* @copyright 2005-2008 Janrain, Inc.
|
||||||
|
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import the interface for creating a new store class.
|
||||||
|
*/
|
||||||
|
require_once 'Auth/OpenID/Interface.php';
|
||||||
|
require_once 'Auth/OpenID/HMAC.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a store for use in the worst case, when you have no way of
|
||||||
|
* saving state on the consumer site. Using this store makes the
|
||||||
|
* consumer vulnerable to replay attacks, as it's unable to use
|
||||||
|
* nonces. Avoid using this store if it is at all possible.
|
||||||
|
*
|
||||||
|
* Most of the methods of this class are implementation details.
|
||||||
|
* Users of this class need to worry only about the constructor.
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
*/
|
||||||
|
class Auth_OpenID_DumbStore extends Auth_OpenID_OpenIDStore {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link Auth_OpenID_DumbStore} instance. For the security
|
||||||
|
* of the tokens generated by the library, this class attempts to
|
||||||
|
* at least have a secure implementation of getAuthKey.
|
||||||
|
*
|
||||||
|
* When you create an instance of this class, pass in a secret
|
||||||
|
* phrase. The phrase is hashed with sha1 to make it the correct
|
||||||
|
* length and form for an auth key. That allows you to use a long
|
||||||
|
* string as the secret phrase, which means you can make it very
|
||||||
|
* difficult to guess.
|
||||||
|
*
|
||||||
|
* Each {@link Auth_OpenID_DumbStore} instance that is created for use by
|
||||||
|
* your consumer site needs to use the same $secret_phrase.
|
||||||
|
*
|
||||||
|
* @param string secret_phrase The phrase used to create the auth
|
||||||
|
* key returned by getAuthKey
|
||||||
|
*/
|
||||||
|
function Auth_OpenID_DumbStore($secret_phrase)
|
||||||
|
{
|
||||||
|
$this->auth_key = Auth_OpenID_SHA1($secret_phrase);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This implementation does nothing.
|
||||||
|
*/
|
||||||
|
function storeAssociation($server_url, $association)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This implementation always returns null.
|
||||||
|
*/
|
||||||
|
function getAssociation($server_url, $handle = null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This implementation always returns false.
|
||||||
|
*/
|
||||||
|
function removeAssociation($server_url, $handle)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In a system truly limited to dumb mode, nonces must all be
|
||||||
|
* accepted. This therefore always returns true, which makes
|
||||||
|
* replay attacks feasible.
|
||||||
|
*/
|
||||||
|
function useNonce($server_url, $timestamp, $salt)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the auth key generated by the constructor.
|
||||||
|
*/
|
||||||
|
function getAuthKey()
|
||||||
|
{
|
||||||
|
return $this->auth_key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
62
libs/Auth/OpenID/Extension.php
Normal file
62
libs/Auth/OpenID/Extension.php
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface for OpenID extensions.
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Require the Message implementation.
|
||||||
|
*/
|
||||||
|
require_once 'Auth/OpenID/Message.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A base class for accessing extension request and response data for
|
||||||
|
* the OpenID 2 protocol.
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
*/
|
||||||
|
class Auth_OpenID_Extension {
|
||||||
|
/**
|
||||||
|
* ns_uri: The namespace to which to add the arguments for this
|
||||||
|
* extension
|
||||||
|
*/
|
||||||
|
var $ns_uri = null;
|
||||||
|
var $ns_alias = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the string arguments that should be added to an OpenID
|
||||||
|
* message for this extension.
|
||||||
|
*/
|
||||||
|
function getExtensionArgs()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the arguments from this extension to the provided message.
|
||||||
|
*
|
||||||
|
* Returns the message with the extension arguments added.
|
||||||
|
*/
|
||||||
|
function toMessage(&$message)
|
||||||
|
{
|
||||||
|
$implicit = $message->isOpenID1();
|
||||||
|
$added = $message->namespaces->addAlias($this->ns_uri,
|
||||||
|
$this->ns_alias,
|
||||||
|
$implicit);
|
||||||
|
|
||||||
|
if ($added === null) {
|
||||||
|
if ($message->namespaces->getAlias($this->ns_uri) !=
|
||||||
|
$this->ns_alias) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$message->updateArgs($this->ns_uri,
|
||||||
|
$this->getExtensionArgs());
|
||||||
|
return $message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
618
libs/Auth/OpenID/FileStore.php
Normal file
618
libs/Auth/OpenID/FileStore.php
Normal file
@ -0,0 +1,618 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file supplies a Memcached store backend for OpenID servers and
|
||||||
|
* consumers.
|
||||||
|
*
|
||||||
|
* PHP versions 4 and 5
|
||||||
|
*
|
||||||
|
* LICENSE: See the COPYING file included in this distribution.
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
* @author JanRain, Inc. <openid@janrain.com>
|
||||||
|
* @copyright 2005-2008 Janrain, Inc.
|
||||||
|
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Require base class for creating a new interface.
|
||||||
|
*/
|
||||||
|
require_once 'Auth/OpenID.php';
|
||||||
|
require_once 'Auth/OpenID/Interface.php';
|
||||||
|
require_once 'Auth/OpenID/HMAC.php';
|
||||||
|
require_once 'Auth/OpenID/Nonce.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a filesystem-based store for OpenID associations and
|
||||||
|
* nonces. This store should be safe for use in concurrent systems on
|
||||||
|
* both windows and unix (excluding NFS filesystems). There are a
|
||||||
|
* couple race conditions in the system, but those failure cases have
|
||||||
|
* been set up in such a way that the worst-case behavior is someone
|
||||||
|
* having to try to log in a second time.
|
||||||
|
*
|
||||||
|
* Most of the methods of this class are implementation details.
|
||||||
|
* People wishing to just use this store need only pay attention to
|
||||||
|
* the constructor.
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
*/
|
||||||
|
class Auth_OpenID_FileStore extends Auth_OpenID_OpenIDStore {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a new {@link Auth_OpenID_FileStore}. This
|
||||||
|
* initializes the nonce and association directories, which are
|
||||||
|
* subdirectories of the directory passed in.
|
||||||
|
*
|
||||||
|
* @param string $directory This is the directory to put the store
|
||||||
|
* directories in.
|
||||||
|
*/
|
||||||
|
function Auth_OpenID_FileStore($directory)
|
||||||
|
{
|
||||||
|
if (!Auth_OpenID::ensureDir($directory)) {
|
||||||
|
trigger_error('Not a directory and failed to create: '
|
||||||
|
. $directory, E_USER_ERROR);
|
||||||
|
}
|
||||||
|
$directory = realpath($directory);
|
||||||
|
|
||||||
|
$this->directory = $directory;
|
||||||
|
$this->active = true;
|
||||||
|
|
||||||
|
$this->nonce_dir = $directory . DIRECTORY_SEPARATOR . 'nonces';
|
||||||
|
|
||||||
|
$this->association_dir = $directory . DIRECTORY_SEPARATOR .
|
||||||
|
'associations';
|
||||||
|
|
||||||
|
// Temp dir must be on the same filesystem as the assciations
|
||||||
|
// $directory.
|
||||||
|
$this->temp_dir = $directory . DIRECTORY_SEPARATOR . 'temp';
|
||||||
|
|
||||||
|
$this->max_nonce_age = 6 * 60 * 60; // Six hours, in seconds
|
||||||
|
|
||||||
|
if (!$this->_setup()) {
|
||||||
|
trigger_error('Failed to initialize OpenID file store in ' .
|
||||||
|
$directory, E_USER_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function destroy()
|
||||||
|
{
|
||||||
|
Auth_OpenID_FileStore::_rmtree($this->directory);
|
||||||
|
$this->active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make sure that the directories in which we store our data
|
||||||
|
* exist.
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
function _setup()
|
||||||
|
{
|
||||||
|
return (Auth_OpenID::ensureDir($this->nonce_dir) &&
|
||||||
|
Auth_OpenID::ensureDir($this->association_dir) &&
|
||||||
|
Auth_OpenID::ensureDir($this->temp_dir));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a temporary file on the same filesystem as
|
||||||
|
* $this->association_dir.
|
||||||
|
*
|
||||||
|
* The temporary directory should not be cleaned if there are any
|
||||||
|
* processes using the store. If there is no active process using
|
||||||
|
* the store, it is safe to remove all of the files in the
|
||||||
|
* temporary directory.
|
||||||
|
*
|
||||||
|
* @return array ($fd, $filename)
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
function _mktemp()
|
||||||
|
{
|
||||||
|
$name = Auth_OpenID_FileStore::_mkstemp($dir = $this->temp_dir);
|
||||||
|
$file_obj = @fopen($name, 'wb');
|
||||||
|
if ($file_obj !== false) {
|
||||||
|
return array($file_obj, $name);
|
||||||
|
} else {
|
||||||
|
Auth_OpenID_FileStore::_removeIfPresent($name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanupNonces()
|
||||||
|
{
|
||||||
|
global $Auth_OpenID_SKEW;
|
||||||
|
|
||||||
|
$nonces = Auth_OpenID_FileStore::_listdir($this->nonce_dir);
|
||||||
|
$now = time();
|
||||||
|
|
||||||
|
$removed = 0;
|
||||||
|
// Check all nonces for expiry
|
||||||
|
foreach ($nonces as $nonce_fname) {
|
||||||
|
$base = basename($nonce_fname);
|
||||||
|
$parts = explode('-', $base, 2);
|
||||||
|
$timestamp = $parts[0];
|
||||||
|
$timestamp = intval($timestamp, 16);
|
||||||
|
if (abs($timestamp - $now) > $Auth_OpenID_SKEW) {
|
||||||
|
Auth_OpenID_FileStore::_removeIfPresent($nonce_fname);
|
||||||
|
$removed += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $removed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a unique filename for a given server url and
|
||||||
|
* handle. This implementation does not assume anything about the
|
||||||
|
* format of the handle. The filename that is returned will
|
||||||
|
* contain the domain name from the server URL for ease of human
|
||||||
|
* inspection of the data directory.
|
||||||
|
*
|
||||||
|
* @return string $filename
|
||||||
|
*/
|
||||||
|
function getAssociationFilename($server_url, $handle)
|
||||||
|
{
|
||||||
|
if (!$this->active) {
|
||||||
|
trigger_error("FileStore no longer active", E_USER_ERROR);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strpos($server_url, '://') === false) {
|
||||||
|
trigger_error(sprintf("Bad server URL: %s", $server_url),
|
||||||
|
E_USER_WARNING);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
list($proto, $rest) = explode('://', $server_url, 2);
|
||||||
|
$parts = explode('/', $rest);
|
||||||
|
$domain = Auth_OpenID_FileStore::_filenameEscape($parts[0]);
|
||||||
|
$url_hash = Auth_OpenID_FileStore::_safe64($server_url);
|
||||||
|
if ($handle) {
|
||||||
|
$handle_hash = Auth_OpenID_FileStore::_safe64($handle);
|
||||||
|
} else {
|
||||||
|
$handle_hash = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$filename = sprintf('%s-%s-%s-%s', $proto, $domain, $url_hash,
|
||||||
|
$handle_hash);
|
||||||
|
|
||||||
|
return $this->association_dir. DIRECTORY_SEPARATOR . $filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store an association in the association directory.
|
||||||
|
*/
|
||||||
|
function storeAssociation($server_url, $association)
|
||||||
|
{
|
||||||
|
if (!$this->active) {
|
||||||
|
trigger_error("FileStore no longer active", E_USER_ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$association_s = $association->serialize();
|
||||||
|
$filename = $this->getAssociationFilename($server_url,
|
||||||
|
$association->handle);
|
||||||
|
list($tmp_file, $tmp) = $this->_mktemp();
|
||||||
|
|
||||||
|
if (!$tmp_file) {
|
||||||
|
trigger_error("_mktemp didn't return a valid file descriptor",
|
||||||
|
E_USER_WARNING);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fwrite($tmp_file, $association_s);
|
||||||
|
|
||||||
|
fflush($tmp_file);
|
||||||
|
|
||||||
|
fclose($tmp_file);
|
||||||
|
|
||||||
|
if (@rename($tmp, $filename)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// In case we are running on Windows, try unlinking the
|
||||||
|
// file in case it exists.
|
||||||
|
@unlink($filename);
|
||||||
|
|
||||||
|
// Now the target should not exist. Try renaming again,
|
||||||
|
// giving up if it fails.
|
||||||
|
if (@rename($tmp, $filename)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there was an error, don't leave the temporary file
|
||||||
|
// around.
|
||||||
|
Auth_OpenID_FileStore::_removeIfPresent($tmp);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve an association. If no handle is specified, return the
|
||||||
|
* association with the most recent issue time.
|
||||||
|
*
|
||||||
|
* @return mixed $association
|
||||||
|
*/
|
||||||
|
function getAssociation($server_url, $handle = null)
|
||||||
|
{
|
||||||
|
if (!$this->active) {
|
||||||
|
trigger_error("FileStore no longer active", E_USER_ERROR);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($handle === null) {
|
||||||
|
$handle = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// The filename with the empty handle is a prefix of all other
|
||||||
|
// associations for the given server URL.
|
||||||
|
$filename = $this->getAssociationFilename($server_url, $handle);
|
||||||
|
|
||||||
|
if ($handle) {
|
||||||
|
return $this->_getAssociation($filename);
|
||||||
|
} else {
|
||||||
|
$association_files =
|
||||||
|
Auth_OpenID_FileStore::_listdir($this->association_dir);
|
||||||
|
$matching_files = array();
|
||||||
|
|
||||||
|
// strip off the path to do the comparison
|
||||||
|
$name = basename($filename);
|
||||||
|
foreach ($association_files as $association_file) {
|
||||||
|
$base = basename($association_file);
|
||||||
|
if (strpos($base, $name) === 0) {
|
||||||
|
$matching_files[] = $association_file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$matching_associations = array();
|
||||||
|
// read the matching files and sort by time issued
|
||||||
|
foreach ($matching_files as $full_name) {
|
||||||
|
$association = $this->_getAssociation($full_name);
|
||||||
|
if ($association !== null) {
|
||||||
|
$matching_associations[] = array($association->issued,
|
||||||
|
$association);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$issued = array();
|
||||||
|
$assocs = array();
|
||||||
|
foreach ($matching_associations as $key => $assoc) {
|
||||||
|
$issued[$key] = $assoc[0];
|
||||||
|
$assocs[$key] = $assoc[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
array_multisort($issued, SORT_DESC, $assocs, SORT_DESC,
|
||||||
|
$matching_associations);
|
||||||
|
|
||||||
|
// return the most recently issued one.
|
||||||
|
if ($matching_associations) {
|
||||||
|
list($issued, $assoc) = $matching_associations[0];
|
||||||
|
return $assoc;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
function _getAssociation($filename)
|
||||||
|
{
|
||||||
|
if (!$this->active) {
|
||||||
|
trigger_error("FileStore no longer active", E_USER_ERROR);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether this nonce is present. As a side effect, mark it
|
||||||
|
* as no longer present.
|
||||||
|
*
|
||||||
|
* @return bool $present
|
||||||
|
*/
|
||||||
|
function useNonce($server_url, $timestamp, $salt)
|
||||||
|
{
|
||||||
|
global $Auth_OpenID_SKEW;
|
||||||
|
|
||||||
|
if (!$this->active) {
|
||||||
|
trigger_error("FileStore no longer active", E_USER_ERROR);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( abs($timestamp - time()) > $Auth_OpenID_SKEW ) {
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($server_url) {
|
||||||
|
list($proto, $rest) = explode('://', $server_url, 2);
|
||||||
|
} else {
|
||||||
|
$proto = '';
|
||||||
|
$rest = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$parts = explode('/', $rest, 2);
|
||||||
|
$domain = $this->_filenameEscape($parts[0]);
|
||||||
|
$url_hash = $this->_safe64($server_url);
|
||||||
|
$salt_hash = $this->_safe64($salt);
|
||||||
|
|
||||||
|
$filename = sprintf('%08x-%s-%s-%s-%s', $timestamp, $proto,
|
||||||
|
$domain, $url_hash, $salt_hash);
|
||||||
|
$filename = $this->nonce_dir . DIRECTORY_SEPARATOR . $filename;
|
||||||
|
|
||||||
|
$result = @fopen($filename, 'x');
|
||||||
|
|
||||||
|
if ($result === false) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
fclose($result);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove expired entries from the database. This is potentially
|
||||||
|
* expensive, so only run when it is acceptable to take time.
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
function _allAssocs()
|
||||||
|
{
|
||||||
|
$all_associations = array();
|
||||||
|
|
||||||
|
$association_filenames =
|
||||||
|
Auth_OpenID_FileStore::_listdir($this->association_dir);
|
||||||
|
|
||||||
|
foreach ($association_filenames as $association_filename) {
|
||||||
|
$association_file = fopen($association_filename, 'rb');
|
||||||
|
|
||||||
|
if ($association_file !== false) {
|
||||||
|
$assoc_s = fread($association_file,
|
||||||
|
filesize($association_filename));
|
||||||
|
fclose($association_file);
|
||||||
|
|
||||||
|
// Remove expired or corrupted associations
|
||||||
|
$association =
|
||||||
|
Auth_OpenID_Association::deserialize(
|
||||||
|
'Auth_OpenID_Association', $assoc_s);
|
||||||
|
|
||||||
|
if ($association === null) {
|
||||||
|
Auth_OpenID_FileStore::_removeIfPresent(
|
||||||
|
$association_filename);
|
||||||
|
} else {
|
||||||
|
if ($association->getExpiresIn() == 0) {
|
||||||
|
$all_associations[] = array($association_filename,
|
||||||
|
$association);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $all_associations;
|
||||||
|
}
|
||||||
|
|
||||||
|
function clean()
|
||||||
|
{
|
||||||
|
if (!$this->active) {
|
||||||
|
trigger_error("FileStore no longer active", E_USER_ERROR);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$nonces = Auth_OpenID_FileStore::_listdir($this->nonce_dir);
|
||||||
|
$now = time();
|
||||||
|
|
||||||
|
// Check all nonces for expiry
|
||||||
|
foreach ($nonces as $nonce) {
|
||||||
|
if (!Auth_OpenID_checkTimestamp($nonce, $now)) {
|
||||||
|
$filename = $this->nonce_dir . DIRECTORY_SEPARATOR . $nonce;
|
||||||
|
Auth_OpenID_FileStore::_removeIfPresent($filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->_allAssocs() as $pair) {
|
||||||
|
list($assoc_filename, $assoc) = $pair;
|
||||||
|
if ($assoc->getExpiresIn() == 0) {
|
||||||
|
Auth_OpenID_FileStore::_removeIfPresent($assoc_filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
function _rmtree($dir)
|
||||||
|
{
|
||||||
|
if ($dir[strlen($dir) - 1] != DIRECTORY_SEPARATOR) {
|
||||||
|
$dir .= DIRECTORY_SEPARATOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($handle = opendir($dir)) {
|
||||||
|
while ($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))) {
|
||||||
|
if (!in_array($filename, array('.', '..'))) {
|
||||||
|
$files[] = $dir . DIRECTORY_SEPARATOR . $filename;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $files;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
function _isFilenameSafe($char)
|
||||||
|
{
|
||||||
|
$_Auth_OpenID_filename_allowed = Auth_OpenID_letters .
|
||||||
|
Auth_OpenID_digits . ".";
|
||||||
|
return (strpos($_Auth_OpenID_filename_allowed, $char) !== false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
function _safe64($str)
|
||||||
|
{
|
||||||
|
$h64 = base64_encode(Auth_OpenID_SHA1($str));
|
||||||
|
$h64 = str_replace('+', '_', $h64);
|
||||||
|
$h64 = str_replace('/', '.', $h64);
|
||||||
|
$h64 = str_replace('=', '', $h64);
|
||||||
|
return $h64;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
function _filenameEscape($str)
|
||||||
|
{
|
||||||
|
$filename = "";
|
||||||
|
$b = Auth_OpenID::toBytes($str);
|
||||||
|
|
||||||
|
for ($i = 0; $i < count($b); $i++) {
|
||||||
|
$c = $b[$i];
|
||||||
|
if (Auth_OpenID_FileStore::_isFilenameSafe($c)) {
|
||||||
|
$filename .= $c;
|
||||||
|
} else {
|
||||||
|
$filename .= sprintf("_%02X", ord($c));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to remove a file, returning whether the file existed at
|
||||||
|
* the time of the call.
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @return bool $result True if the file was present, false if not.
|
||||||
|
*/
|
||||||
|
function _removeIfPresent($filename)
|
||||||
|
{
|
||||||
|
return @unlink($filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanupAssociations()
|
||||||
|
{
|
||||||
|
$removed = 0;
|
||||||
|
foreach ($this->_allAssocs() as $pair) {
|
||||||
|
list($assoc_filename, $assoc) = $pair;
|
||||||
|
if ($assoc->getExpiresIn() == 0) {
|
||||||
|
$this->_removeIfPresent($assoc_filename);
|
||||||
|
$removed += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $removed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
99
libs/Auth/OpenID/HMAC.php
Normal file
99
libs/Auth/OpenID/HMAC.php
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the HMACSHA1 implementation for the OpenID library.
|
||||||
|
*
|
||||||
|
* PHP versions 4 and 5
|
||||||
|
*
|
||||||
|
* LICENSE: See the COPYING file included in this distribution.
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @package OpenID
|
||||||
|
* @author JanRain, Inc. <openid@janrain.com>
|
||||||
|
* @copyright 2005-2008 Janrain, Inc.
|
||||||
|
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once 'Auth/OpenID.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SHA1_BLOCKSIZE is this module's SHA1 blocksize used by the fallback
|
||||||
|
* implementation.
|
||||||
|
*/
|
||||||
|
define('Auth_OpenID_SHA1_BLOCKSIZE', 64);
|
||||||
|
|
||||||
|
function Auth_OpenID_SHA1($text)
|
||||||
|
{
|
||||||
|
if (function_exists('hash') &&
|
||||||
|
function_exists('hash_algos') &&
|
||||||
|
(in_array('sha1', hash_algos()))) {
|
||||||
|
// PHP 5 case (sometimes): 'hash' available and 'sha1' algo
|
||||||
|
// supported.
|
||||||
|
return hash('sha1', $text, true);
|
||||||
|
} else if (function_exists('sha1')) {
|
||||||
|
// PHP 4 case: 'sha1' available.
|
||||||
|
$hex = sha1($text);
|
||||||
|
$raw = '';
|
||||||
|
for ($i = 0; $i < 40; $i += 2) {
|
||||||
|
$hexcode = substr($hex, $i, 2);
|
||||||
|
$charcode = (int)base_convert($hexcode, 16, 10);
|
||||||
|
$raw .= chr($charcode);
|
||||||
|
}
|
||||||
|
return $raw;
|
||||||
|
} else {
|
||||||
|
// Explode.
|
||||||
|
trigger_error('No SHA1 function found', E_USER_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute an HMAC/SHA1 hash.
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @param string $key The HMAC key
|
||||||
|
* @param string $text The message text to hash
|
||||||
|
* @return string $mac The MAC
|
||||||
|
*/
|
||||||
|
function Auth_OpenID_HMACSHA1($key, $text)
|
||||||
|
{
|
||||||
|
if (Auth_OpenID::bytes($key) > Auth_OpenID_SHA1_BLOCKSIZE) {
|
||||||
|
$key = Auth_OpenID_SHA1($key, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$key = str_pad($key, Auth_OpenID_SHA1_BLOCKSIZE, chr(0x00));
|
||||||
|
$ipad = str_repeat(chr(0x36), Auth_OpenID_SHA1_BLOCKSIZE);
|
||||||
|
$opad = str_repeat(chr(0x5c), Auth_OpenID_SHA1_BLOCKSIZE);
|
||||||
|
$hash1 = Auth_OpenID_SHA1(($key ^ $ipad) . $text, true);
|
||||||
|
$hmac = Auth_OpenID_SHA1(($key ^ $opad) . $hash1, true);
|
||||||
|
return $hmac;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (function_exists('hash') &&
|
||||||
|
function_exists('hash_algos') &&
|
||||||
|
(in_array('sha256', hash_algos()))) {
|
||||||
|
function Auth_OpenID_SHA256($text)
|
||||||
|
{
|
||||||
|
// PHP 5 case: 'hash' available and 'sha256' algo supported.
|
||||||
|
return hash('sha256', $text, true);
|
||||||
|
}
|
||||||
|
define('Auth_OpenID_SHA256_SUPPORTED', true);
|
||||||
|
} else {
|
||||||
|
define('Auth_OpenID_SHA256_SUPPORTED', false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (function_exists('hash_hmac') &&
|
||||||
|
function_exists('hash_algos') &&
|
||||||
|
(in_array('sha256', hash_algos()))) {
|
||||||
|
|
||||||
|
function Auth_OpenID_HMACSHA256($key, $text)
|
||||||
|
{
|
||||||
|
// Return raw MAC (not hex string).
|
||||||
|
return hash_hmac('sha256', $text, $key, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
define('Auth_OpenID_HMACSHA256_SUPPORTED', true);
|
||||||
|
} else {
|
||||||
|
define('Auth_OpenID_HMACSHA256_SUPPORTED', false);
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
197
libs/Auth/OpenID/Interface.php
Normal file
197
libs/Auth/OpenID/Interface.php
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file specifies the interface for PHP OpenID store implementations.
|
||||||
|
*
|
||||||
|
* PHP versions 4 and 5
|
||||||
|
*
|
||||||
|
* LICENSE: See the COPYING file included in this distribution.
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
* @author JanRain, Inc. <openid@janrain.com>
|
||||||
|
* @copyright 2005-2008 Janrain, Inc.
|
||||||
|
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the interface for the store objects the OpenID library
|
||||||
|
* uses. It is a single class that provides all of the persistence
|
||||||
|
* mechanisms that the OpenID library needs, for both servers and
|
||||||
|
* consumers. If you want to create an SQL-driven store, please see
|
||||||
|
* then {@link Auth_OpenID_SQLStore} class.
|
||||||
|
*
|
||||||
|
* Change: Version 2.0 removed the storeNonce, getAuthKey, and isDumb
|
||||||
|
* methods, and changed the behavior of the useNonce method to support
|
||||||
|
* one-way nonces.
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
* @author JanRain, Inc. <openid@janrain.com>
|
||||||
|
*/
|
||||||
|
class Auth_OpenID_OpenIDStore {
|
||||||
|
/**
|
||||||
|
* This method puts an Association object into storage,
|
||||||
|
* retrievable by server URL and handle.
|
||||||
|
*
|
||||||
|
* @param string $server_url The URL of the identity server that
|
||||||
|
* this association is with. Because of the way the server portion
|
||||||
|
* of the library uses this interface, don't assume there are any
|
||||||
|
* limitations on the character set of the input string. In
|
||||||
|
* particular, expect to see unescaped non-url-safe characters in
|
||||||
|
* the server_url field.
|
||||||
|
*
|
||||||
|
* @param Association $association The Association to store.
|
||||||
|
*/
|
||||||
|
function storeAssociation($server_url, $association)
|
||||||
|
{
|
||||||
|
trigger_error("Auth_OpenID_OpenIDStore::storeAssociation ".
|
||||||
|
"not implemented", E_USER_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove expired nonces from the store.
|
||||||
|
*
|
||||||
|
* Discards any nonce from storage that is old enough that its
|
||||||
|
* timestamp would not pass useNonce().
|
||||||
|
*
|
||||||
|
* This method is not called in the normal operation of the
|
||||||
|
* library. It provides a way for store admins to keep their
|
||||||
|
* storage from filling up with expired data.
|
||||||
|
*
|
||||||
|
* @return the number of nonces expired
|
||||||
|
*/
|
||||||
|
function cleanupNonces()
|
||||||
|
{
|
||||||
|
trigger_error("Auth_OpenID_OpenIDStore::cleanupNonces ".
|
||||||
|
"not implemented", E_USER_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove expired associations from the store.
|
||||||
|
*
|
||||||
|
* This method is not called in the normal operation of the
|
||||||
|
* library. It provides a way for store admins to keep their
|
||||||
|
* storage from filling up with expired data.
|
||||||
|
*
|
||||||
|
* @return the number of associations expired.
|
||||||
|
*/
|
||||||
|
function cleanupAssociations()
|
||||||
|
{
|
||||||
|
trigger_error("Auth_OpenID_OpenIDStore::cleanupAssociations ".
|
||||||
|
"not implemented", E_USER_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Shortcut for cleanupNonces(), cleanupAssociations().
|
||||||
|
*
|
||||||
|
* This method is not called in the normal operation of the
|
||||||
|
* library. It provides a way for store admins to keep their
|
||||||
|
* storage from filling up with expired data.
|
||||||
|
*/
|
||||||
|
function cleanup()
|
||||||
|
{
|
||||||
|
return array($this->cleanupNonces(),
|
||||||
|
$this->cleanupAssociations());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Report whether this storage supports cleanup
|
||||||
|
*/
|
||||||
|
function supportsCleanup()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns an Association object from storage that
|
||||||
|
* matches the server URL and, if specified, handle. It returns
|
||||||
|
* null if no such association is found or if the matching
|
||||||
|
* association is expired.
|
||||||
|
*
|
||||||
|
* If no handle is specified, the store may return any association
|
||||||
|
* which matches the server URL. If multiple associations are
|
||||||
|
* valid, the recommended return value for this method is the one
|
||||||
|
* most recently issued.
|
||||||
|
*
|
||||||
|
* This method is allowed (and encouraged) to garbage collect
|
||||||
|
* expired associations when found. This method must not return
|
||||||
|
* expired associations.
|
||||||
|
*
|
||||||
|
* @param string $server_url The URL of the identity server to get
|
||||||
|
* the association for. Because of the way the server portion of
|
||||||
|
* the library uses this interface, don't assume there are any
|
||||||
|
* limitations on the character set of the input string. In
|
||||||
|
* particular, expect to see unescaped non-url-safe characters in
|
||||||
|
* the server_url field.
|
||||||
|
*
|
||||||
|
* @param mixed $handle This optional parameter is the handle of
|
||||||
|
* the specific association to get. If no specific handle is
|
||||||
|
* provided, any valid association matching the server URL is
|
||||||
|
* returned.
|
||||||
|
*
|
||||||
|
* @return Association The Association for the given identity
|
||||||
|
* server.
|
||||||
|
*/
|
||||||
|
function getAssociation($server_url, $handle = null)
|
||||||
|
{
|
||||||
|
trigger_error("Auth_OpenID_OpenIDStore::getAssociation ".
|
||||||
|
"not implemented", E_USER_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method removes the matching association if it's found, and
|
||||||
|
* returns whether the association was removed or not.
|
||||||
|
*
|
||||||
|
* @param string $server_url The URL of the identity server the
|
||||||
|
* association to remove belongs to. Because of the way the server
|
||||||
|
* portion of the library uses this interface, don't assume there
|
||||||
|
* are any limitations on the character set of the input
|
||||||
|
* string. In particular, expect to see unescaped non-url-safe
|
||||||
|
* characters in the server_url field.
|
||||||
|
*
|
||||||
|
* @param string $handle This is the handle of the association to
|
||||||
|
* remove. If there isn't an association found that matches both
|
||||||
|
* the given URL and handle, then there was no matching handle
|
||||||
|
* found.
|
||||||
|
*
|
||||||
|
* @return mixed Returns whether or not the given association existed.
|
||||||
|
*/
|
||||||
|
function removeAssociation($server_url, $handle)
|
||||||
|
{
|
||||||
|
trigger_error("Auth_OpenID_OpenIDStore::removeAssociation ".
|
||||||
|
"not implemented", E_USER_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when using a nonce.
|
||||||
|
*
|
||||||
|
* This method should return C{True} if the nonce has not been
|
||||||
|
* used before, and store it for a while to make sure nobody
|
||||||
|
* tries to use the same value again. If the nonce has already
|
||||||
|
* been used, return C{False}.
|
||||||
|
*
|
||||||
|
* Change: In earlier versions, round-trip nonces were used and a
|
||||||
|
* nonce was only valid if it had been previously stored with
|
||||||
|
* storeNonce. Version 2.0 uses one-way nonces, requiring a
|
||||||
|
* different implementation here that does not depend on a
|
||||||
|
* storeNonce call. (storeNonce is no longer part of the
|
||||||
|
* interface.
|
||||||
|
*
|
||||||
|
* @param string $nonce The nonce to use.
|
||||||
|
*
|
||||||
|
* @return bool Whether or not the nonce was valid.
|
||||||
|
*/
|
||||||
|
function useNonce($server_url, $timestamp, $salt)
|
||||||
|
{
|
||||||
|
trigger_error("Auth_OpenID_OpenIDStore::useNonce ".
|
||||||
|
"not implemented", E_USER_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all entries from the store; implementation is optional.
|
||||||
|
*/
|
||||||
|
function reset()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
?>
|
112
libs/Auth/OpenID/KVForm.php
Normal file
112
libs/Auth/OpenID/KVForm.php
Normal 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-2008 Janrain, Inc.
|
||||||
|
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Container for key-value/comma-newline OpenID format and parsing
|
||||||
|
*/
|
||||||
|
class Auth_OpenID_KVForm {
|
||||||
|
/**
|
||||||
|
* Convert an OpenID colon/newline separated string into an
|
||||||
|
* associative array
|
||||||
|
*
|
||||||
|
* @static
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
208
libs/Auth/OpenID/MemcachedStore.php
Normal file
208
libs/Auth/OpenID/MemcachedStore.php
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file supplies a memcached store backend for OpenID servers and
|
||||||
|
* consumers.
|
||||||
|
*
|
||||||
|
* PHP versions 4 and 5
|
||||||
|
*
|
||||||
|
* LICENSE: See the COPYING file included in this distribution.
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
* @author Artemy Tregubenko <me@arty.name>
|
||||||
|
* @copyright 2008 JanRain, Inc.
|
||||||
|
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
|
||||||
|
* Contributed by Open Web Technologies <http://openwebtech.ru/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import the interface for creating a new store class.
|
||||||
|
*/
|
||||||
|
require_once 'Auth/OpenID/Interface.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a memcached-based store for OpenID associations and
|
||||||
|
* nonces.
|
||||||
|
*
|
||||||
|
* As memcache has limit of 250 chars for key length,
|
||||||
|
* server_url, handle and salt are hashed with sha1().
|
||||||
|
*
|
||||||
|
* Most of the methods of this class are implementation details.
|
||||||
|
* People wishing to just use this store need only pay attention to
|
||||||
|
* the constructor.
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
*/
|
||||||
|
class Auth_OpenID_MemcachedStore extends Auth_OpenID_OpenIDStore {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a new {@link Auth_OpenID_MemcachedStore} instance.
|
||||||
|
* Just saves memcached object as property.
|
||||||
|
*
|
||||||
|
* @param resource connection Memcache connection resourse
|
||||||
|
*/
|
||||||
|
function Auth_OpenID_MemcachedStore($connection, $compress = false)
|
||||||
|
{
|
||||||
|
$this->connection = $connection;
|
||||||
|
$this->compress = $compress ? MEMCACHE_COMPRESSED : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store association until its expiration time in memcached.
|
||||||
|
* Overwrites any existing association with same server_url and
|
||||||
|
* handle. Handles list of associations for every server.
|
||||||
|
*/
|
||||||
|
function storeAssociation($server_url, $association)
|
||||||
|
{
|
||||||
|
// create memcached keys for association itself
|
||||||
|
// and list of associations for this server
|
||||||
|
$associationKey = $this->associationKey($server_url,
|
||||||
|
$association->handle);
|
||||||
|
$serverKey = $this->associationServerKey($server_url);
|
||||||
|
|
||||||
|
// get list of associations
|
||||||
|
$serverAssociations = $this->connection->get($serverKey);
|
||||||
|
|
||||||
|
// if no such list, initialize it with empty array
|
||||||
|
if (!$serverAssociations) {
|
||||||
|
$serverAssociations = array();
|
||||||
|
}
|
||||||
|
// and store given association key in it
|
||||||
|
$serverAssociations[$association->issued] = $associationKey;
|
||||||
|
|
||||||
|
// save associations' keys list
|
||||||
|
$this->connection->set(
|
||||||
|
$serverKey,
|
||||||
|
$serverAssociations,
|
||||||
|
$this->compress
|
||||||
|
);
|
||||||
|
// save association itself
|
||||||
|
$this->connection->set(
|
||||||
|
$associationKey,
|
||||||
|
$association,
|
||||||
|
$this->compress,
|
||||||
|
$association->issued + $association->lifetime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read association from memcached. If no handle given
|
||||||
|
* and multiple associations found, returns latest issued
|
||||||
|
*/
|
||||||
|
function getAssociation($server_url, $handle = null)
|
||||||
|
{
|
||||||
|
// simple case: handle given
|
||||||
|
if ($handle !== null) {
|
||||||
|
// get association, return null if failed
|
||||||
|
$association = $this->connection->get(
|
||||||
|
$this->associationKey($server_url, $handle));
|
||||||
|
return $association ? $association : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// no handle given, working with list
|
||||||
|
// create key for list of associations
|
||||||
|
$serverKey = $this->associationServerKey($server_url);
|
||||||
|
|
||||||
|
// get list of associations
|
||||||
|
$serverAssociations = $this->connection->get($serverKey);
|
||||||
|
// return null if failed or got empty list
|
||||||
|
if (!$serverAssociations) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get key of most recently issued association
|
||||||
|
$keys = array_keys($serverAssociations);
|
||||||
|
sort($keys);
|
||||||
|
$lastKey = $serverAssociations[array_pop($keys)];
|
||||||
|
|
||||||
|
// get association, return null if failed
|
||||||
|
$association = $this->connection->get($lastKey);
|
||||||
|
return $association ? $association : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Immediately delete association from memcache.
|
||||||
|
*/
|
||||||
|
function removeAssociation($server_url, $handle)
|
||||||
|
{
|
||||||
|
// create memcached keys for association itself
|
||||||
|
// and list of associations for this server
|
||||||
|
$serverKey = $this->associationServerKey($server_url);
|
||||||
|
$associationKey = $this->associationKey($server_url,
|
||||||
|
$handle);
|
||||||
|
|
||||||
|
// get list of associations
|
||||||
|
$serverAssociations = $this->connection->get($serverKey);
|
||||||
|
// return null if failed or got empty list
|
||||||
|
if (!$serverAssociations) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure that given association key exists in list
|
||||||
|
$serverAssociations = array_flip($serverAssociations);
|
||||||
|
if (!array_key_exists($associationKey, $serverAssociations)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove given association key from list
|
||||||
|
unset($serverAssociations[$associationKey]);
|
||||||
|
$serverAssociations = array_flip($serverAssociations);
|
||||||
|
|
||||||
|
// save updated list
|
||||||
|
$this->connection->set(
|
||||||
|
$serverKey,
|
||||||
|
$serverAssociations,
|
||||||
|
$this->compress
|
||||||
|
);
|
||||||
|
|
||||||
|
// delete association
|
||||||
|
return $this->connection->delete($associationKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create nonce for server and salt, expiring after
|
||||||
|
* $Auth_OpenID_SKEW seconds.
|
||||||
|
*/
|
||||||
|
function useNonce($server_url, $timestamp, $salt)
|
||||||
|
{
|
||||||
|
global $Auth_OpenID_SKEW;
|
||||||
|
|
||||||
|
// save one request to memcache when nonce obviously expired
|
||||||
|
if (abs($timestamp - time()) > $Auth_OpenID_SKEW) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns false when nonce already exists
|
||||||
|
// otherwise adds nonce
|
||||||
|
return $this->connection->add(
|
||||||
|
'openid_nonce_' . sha1($server_url) . '_' . sha1($salt),
|
||||||
|
1, // any value here
|
||||||
|
$this->compress,
|
||||||
|
$Auth_OpenID_SKEW);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Memcache key is prefixed with 'openid_association_' string.
|
||||||
|
*/
|
||||||
|
function associationKey($server_url, $handle = null)
|
||||||
|
{
|
||||||
|
return 'openid_association_' . sha1($server_url) . '_' . sha1($handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Memcache key is prefixed with 'openid_association_' string.
|
||||||
|
*/
|
||||||
|
function associationServerKey($server_url)
|
||||||
|
{
|
||||||
|
return 'openid_association_server_' . sha1($server_url);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Report that this storage doesn't support cleanup
|
||||||
|
*/
|
||||||
|
function supportsCleanup()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
920
libs/Auth/OpenID/Message.php
Normal file
920
libs/Auth/OpenID/Message.php
Normal file
@ -0,0 +1,920 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extension argument processing code
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import tools needed to deal with messages.
|
||||||
|
*/
|
||||||
|
require_once 'Auth/OpenID.php';
|
||||||
|
require_once 'Auth/OpenID/KVForm.php';
|
||||||
|
require_once 'Auth/Yadis/XML.php';
|
||||||
|
require_once 'Auth/OpenID/Consumer.php'; // For Auth_OpenID_FailureResponse
|
||||||
|
|
||||||
|
// This doesn't REALLY belong here, but where is better?
|
||||||
|
define('Auth_OpenID_IDENTIFIER_SELECT',
|
||||||
|
"http://specs.openid.net/auth/2.0/identifier_select");
|
||||||
|
|
||||||
|
// URI for Simple Registration extension, the only commonly deployed
|
||||||
|
// OpenID 1.x extension, and so a special case
|
||||||
|
define('Auth_OpenID_SREG_URI', 'http://openid.net/sreg/1.0');
|
||||||
|
|
||||||
|
// The OpenID 1.X namespace URI
|
||||||
|
define('Auth_OpenID_OPENID1_NS', 'http://openid.net/signon/1.0');
|
||||||
|
define('Auth_OpenID_THE_OTHER_OPENID1_NS', 'http://openid.net/signon/1.1');
|
||||||
|
|
||||||
|
function Auth_OpenID_isOpenID1($ns)
|
||||||
|
{
|
||||||
|
return ($ns == Auth_OpenID_THE_OTHER_OPENID1_NS) ||
|
||||||
|
($ns == Auth_OpenID_OPENID1_NS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The OpenID 2.0 namespace URI
|
||||||
|
define('Auth_OpenID_OPENID2_NS', 'http://specs.openid.net/auth/2.0');
|
||||||
|
|
||||||
|
// The namespace consisting of pairs with keys that are prefixed with
|
||||||
|
// "openid." but not in another namespace.
|
||||||
|
define('Auth_OpenID_NULL_NAMESPACE', 'Null namespace');
|
||||||
|
|
||||||
|
// The null namespace, when it is an allowed OpenID namespace
|
||||||
|
define('Auth_OpenID_OPENID_NS', 'OpenID namespace');
|
||||||
|
|
||||||
|
// The top-level namespace, excluding all pairs with keys that start
|
||||||
|
// with "openid."
|
||||||
|
define('Auth_OpenID_BARE_NS', 'Bare namespace');
|
||||||
|
|
||||||
|
// Sentinel for Message implementation to indicate that getArg should
|
||||||
|
// return null instead of returning a default.
|
||||||
|
define('Auth_OpenID_NO_DEFAULT', 'NO DEFAULT ALLOWED');
|
||||||
|
|
||||||
|
// Limit, in bytes, of identity provider and return_to URLs, including
|
||||||
|
// response payload. See OpenID 1.1 specification, Appendix D.
|
||||||
|
define('Auth_OpenID_OPENID1_URL_LIMIT', 2047);
|
||||||
|
|
||||||
|
// All OpenID protocol fields. Used to check namespace aliases.
|
||||||
|
global $Auth_OpenID_OPENID_PROTOCOL_FIELDS;
|
||||||
|
$Auth_OpenID_OPENID_PROTOCOL_FIELDS = array(
|
||||||
|
'ns', 'mode', 'error', 'return_to', 'contact', 'reference',
|
||||||
|
'signed', 'assoc_type', 'session_type', 'dh_modulus', 'dh_gen',
|
||||||
|
'dh_consumer_public', 'claimed_id', 'identity', 'realm',
|
||||||
|
'invalidate_handle', 'op_endpoint', 'response_nonce', 'sig',
|
||||||
|
'assoc_handle', 'trust_root', 'openid');
|
||||||
|
|
||||||
|
// Global namespace / alias registration map. See
|
||||||
|
// Auth_OpenID_registerNamespaceAlias.
|
||||||
|
global $Auth_OpenID_registered_aliases;
|
||||||
|
$Auth_OpenID_registered_aliases = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a (namespace URI, alias) mapping in a global namespace
|
||||||
|
* alias map. Raises NamespaceAliasRegistrationError if either the
|
||||||
|
* namespace URI or alias has already been registered with a different
|
||||||
|
* value. This function is required if you want to use a namespace
|
||||||
|
* with an OpenID 1 message.
|
||||||
|
*/
|
||||||
|
function Auth_OpenID_registerNamespaceAlias($namespace_uri, $alias)
|
||||||
|
{
|
||||||
|
global $Auth_OpenID_registered_aliases;
|
||||||
|
|
||||||
|
if (Auth_OpenID::arrayGet($Auth_OpenID_registered_aliases,
|
||||||
|
$alias) == $namespace_uri) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_array($namespace_uri,
|
||||||
|
array_values($Auth_OpenID_registered_aliases))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_array($alias, array_keys($Auth_OpenID_registered_aliases))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$Auth_OpenID_registered_aliases[$alias] = $namespace_uri;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a (namespace_uri, alias) registration from the global
|
||||||
|
* namespace alias map. Returns true if the removal succeeded; false
|
||||||
|
* if not (if the mapping did not exist).
|
||||||
|
*/
|
||||||
|
function Auth_OpenID_removeNamespaceAlias($namespace_uri, $alias)
|
||||||
|
{
|
||||||
|
global $Auth_OpenID_registered_aliases;
|
||||||
|
|
||||||
|
if (Auth_OpenID::arrayGet($Auth_OpenID_registered_aliases,
|
||||||
|
$alias) === $namespace_uri) {
|
||||||
|
unset($Auth_OpenID_registered_aliases[$alias]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An Auth_OpenID_Mapping maintains a mapping from arbitrary keys to
|
||||||
|
* arbitrary values. (This is unlike an ordinary PHP array, whose
|
||||||
|
* keys may be only simple scalars.)
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
*/
|
||||||
|
class Auth_OpenID_Mapping {
|
||||||
|
/**
|
||||||
|
* Initialize a mapping. If $classic_array is specified, its keys
|
||||||
|
* and values are used to populate the mapping.
|
||||||
|
*/
|
||||||
|
function Auth_OpenID_Mapping($classic_array = null)
|
||||||
|
{
|
||||||
|
$this->keys = array();
|
||||||
|
$this->values = array();
|
||||||
|
|
||||||
|
if (is_array($classic_array)) {
|
||||||
|
foreach ($classic_array as $key => $value) {
|
||||||
|
$this->set($key, $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if $thing is an Auth_OpenID_Mapping object; false
|
||||||
|
* if not.
|
||||||
|
*/
|
||||||
|
function isA($thing)
|
||||||
|
{
|
||||||
|
return (is_object($thing) &&
|
||||||
|
strtolower(get_class($thing)) == 'auth_openid_mapping');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of the keys in the mapping.
|
||||||
|
*/
|
||||||
|
function keys()
|
||||||
|
{
|
||||||
|
return $this->keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of values in the mapping.
|
||||||
|
*/
|
||||||
|
function values()
|
||||||
|
{
|
||||||
|
return $this->values;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of (key, value) pairs in the mapping.
|
||||||
|
*/
|
||||||
|
function items()
|
||||||
|
{
|
||||||
|
$temp = array();
|
||||||
|
|
||||||
|
for ($i = 0; $i < count($this->keys); $i++) {
|
||||||
|
$temp[] = array($this->keys[$i],
|
||||||
|
$this->values[$i]);
|
||||||
|
}
|
||||||
|
return $temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the "length" of the mapping, or the number of keys.
|
||||||
|
*/
|
||||||
|
function len()
|
||||||
|
{
|
||||||
|
return count($this->keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a key-value pair in the mapping. If the key already
|
||||||
|
* exists, its value is replaced with the new value.
|
||||||
|
*/
|
||||||
|
function set($key, $value)
|
||||||
|
{
|
||||||
|
$index = array_search($key, $this->keys);
|
||||||
|
|
||||||
|
if ($index !== false) {
|
||||||
|
$this->values[$index] = $value;
|
||||||
|
} else {
|
||||||
|
$this->keys[] = $key;
|
||||||
|
$this->values[] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a specified value from the mapping, associated with the
|
||||||
|
* specified key. If the key does not exist in the mapping,
|
||||||
|
* $default is returned instead.
|
||||||
|
*/
|
||||||
|
function get($key, $default = null)
|
||||||
|
{
|
||||||
|
$index = array_search($key, $this->keys);
|
||||||
|
|
||||||
|
if ($index !== false) {
|
||||||
|
return $this->values[$index];
|
||||||
|
} else {
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
function _reflow()
|
||||||
|
{
|
||||||
|
// PHP is broken yet again. Sort the arrays to remove the
|
||||||
|
// hole in the numeric indexes that make up the array.
|
||||||
|
$old_keys = $this->keys;
|
||||||
|
$old_values = $this->values;
|
||||||
|
|
||||||
|
$this->keys = array();
|
||||||
|
$this->values = array();
|
||||||
|
|
||||||
|
foreach ($old_keys as $k) {
|
||||||
|
$this->keys[] = $k;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($old_values as $v) {
|
||||||
|
$this->values[] = $v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a key-value pair from the mapping with the specified
|
||||||
|
* key.
|
||||||
|
*/
|
||||||
|
function del($key)
|
||||||
|
{
|
||||||
|
$index = array_search($key, $this->keys);
|
||||||
|
|
||||||
|
if ($index !== false) {
|
||||||
|
unset($this->keys[$index]);
|
||||||
|
unset($this->values[$index]);
|
||||||
|
$this->_reflow();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the specified value has a key in the mapping;
|
||||||
|
* false if not.
|
||||||
|
*/
|
||||||
|
function contains($value)
|
||||||
|
{
|
||||||
|
return (array_search($value, $this->keys) !== false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maintains a bijective map between namespace uris and aliases.
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
*/
|
||||||
|
class Auth_OpenID_NamespaceMap {
|
||||||
|
function Auth_OpenID_NamespaceMap()
|
||||||
|
{
|
||||||
|
$this->alias_to_namespace = new Auth_OpenID_Mapping();
|
||||||
|
$this->namespace_to_alias = new Auth_OpenID_Mapping();
|
||||||
|
$this->implicit_namespaces = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAlias($namespace_uri)
|
||||||
|
{
|
||||||
|
return $this->namespace_to_alias->get($namespace_uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNamespaceURI($alias)
|
||||||
|
{
|
||||||
|
return $this->alias_to_namespace->get($alias);
|
||||||
|
}
|
||||||
|
|
||||||
|
function iterNamespaceURIs()
|
||||||
|
{
|
||||||
|
// Return an iterator over the namespace URIs
|
||||||
|
return $this->namespace_to_alias->keys();
|
||||||
|
}
|
||||||
|
|
||||||
|
function iterAliases()
|
||||||
|
{
|
||||||
|
// Return an iterator over the aliases"""
|
||||||
|
return $this->alias_to_namespace->keys();
|
||||||
|
}
|
||||||
|
|
||||||
|
function iteritems()
|
||||||
|
{
|
||||||
|
return $this->namespace_to_alias->items();
|
||||||
|
}
|
||||||
|
|
||||||
|
function isImplicit($namespace_uri)
|
||||||
|
{
|
||||||
|
return in_array($namespace_uri, $this->implicit_namespaces);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addAlias($namespace_uri, $desired_alias, $implicit=false)
|
||||||
|
{
|
||||||
|
// Add an alias from this namespace URI to the desired alias
|
||||||
|
global $Auth_OpenID_OPENID_PROTOCOL_FIELDS;
|
||||||
|
|
||||||
|
// Check that desired_alias is not an openid protocol field as
|
||||||
|
// per the spec.
|
||||||
|
if (in_array($desired_alias, $Auth_OpenID_OPENID_PROTOCOL_FIELDS)) {
|
||||||
|
Auth_OpenID::log("\"%s\" is not an allowed namespace alias",
|
||||||
|
$desired_alias);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that desired_alias does not contain a period as per
|
||||||
|
// the spec.
|
||||||
|
if (strpos($desired_alias, '.') !== false) {
|
||||||
|
Auth_OpenID::log('"%s" must not contain a dot', $desired_alias);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that there is not a namespace already defined for the
|
||||||
|
// desired alias
|
||||||
|
$current_namespace_uri =
|
||||||
|
$this->alias_to_namespace->get($desired_alias);
|
||||||
|
|
||||||
|
if (($current_namespace_uri !== null) &&
|
||||||
|
($current_namespace_uri != $namespace_uri)) {
|
||||||
|
Auth_OpenID::log('Cannot map "%s" because previous mapping exists',
|
||||||
|
$namespace_uri);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that there is not already a (different) alias for
|
||||||
|
// this namespace URI
|
||||||
|
$alias = $this->namespace_to_alias->get($namespace_uri);
|
||||||
|
|
||||||
|
if (($alias !== null) && ($alias != $desired_alias)) {
|
||||||
|
Auth_OpenID::log('Cannot map %s to alias %s. ' .
|
||||||
|
'It is already mapped to alias %s',
|
||||||
|
$namespace_uri, $desired_alias, $alias);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert((Auth_OpenID_NULL_NAMESPACE === $desired_alias) ||
|
||||||
|
is_string($desired_alias));
|
||||||
|
|
||||||
|
$this->alias_to_namespace->set($desired_alias, $namespace_uri);
|
||||||
|
$this->namespace_to_alias->set($namespace_uri, $desired_alias);
|
||||||
|
if ($implicit) {
|
||||||
|
array_push($this->implicit_namespaces, $namespace_uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $desired_alias;
|
||||||
|
}
|
||||||
|
|
||||||
|
function add($namespace_uri)
|
||||||
|
{
|
||||||
|
// Add this namespace URI to the mapping, without caring what
|
||||||
|
// alias it ends up with
|
||||||
|
|
||||||
|
// See if this namespace is already mapped to an alias
|
||||||
|
$alias = $this->namespace_to_alias->get($namespace_uri);
|
||||||
|
|
||||||
|
if ($alias !== null) {
|
||||||
|
return $alias;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall back to generating a numerical alias
|
||||||
|
$i = 0;
|
||||||
|
while (1) {
|
||||||
|
$alias = 'ext' . strval($i);
|
||||||
|
if ($this->addAlias($namespace_uri, $alias) === null) {
|
||||||
|
$i += 1;
|
||||||
|
} else {
|
||||||
|
return $alias;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should NEVER be reached!
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function contains($namespace_uri)
|
||||||
|
{
|
||||||
|
return $this->isDefined($namespace_uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isDefined($namespace_uri)
|
||||||
|
{
|
||||||
|
return $this->namespace_to_alias->contains($namespace_uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In the implementation of this object, null represents the global
|
||||||
|
* namespace as well as a namespace with no key.
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
*/
|
||||||
|
class Auth_OpenID_Message {
|
||||||
|
|
||||||
|
function Auth_OpenID_Message($openid_namespace = null)
|
||||||
|
{
|
||||||
|
// Create an empty Message
|
||||||
|
$this->allowed_openid_namespaces = array(
|
||||||
|
Auth_OpenID_OPENID1_NS,
|
||||||
|
Auth_OpenID_THE_OTHER_OPENID1_NS,
|
||||||
|
Auth_OpenID_OPENID2_NS);
|
||||||
|
|
||||||
|
$this->args = new Auth_OpenID_Mapping();
|
||||||
|
$this->namespaces = new Auth_OpenID_NamespaceMap();
|
||||||
|
if ($openid_namespace === null) {
|
||||||
|
$this->_openid_ns_uri = null;
|
||||||
|
} else {
|
||||||
|
$implicit = Auth_OpenID_isOpenID1($openid_namespace);
|
||||||
|
$this->setOpenIDNamespace($openid_namespace, $implicit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isOpenID1()
|
||||||
|
{
|
||||||
|
return Auth_OpenID_isOpenID1($this->getOpenIDNamespace());
|
||||||
|
}
|
||||||
|
|
||||||
|
function isOpenID2()
|
||||||
|
{
|
||||||
|
return $this->getOpenIDNamespace() == Auth_OpenID_OPENID2_NS;
|
||||||
|
}
|
||||||
|
|
||||||
|
function fromPostArgs($args)
|
||||||
|
{
|
||||||
|
// Construct a Message containing a set of POST arguments
|
||||||
|
$obj = new Auth_OpenID_Message();
|
||||||
|
|
||||||
|
// Partition into "openid." args and bare args
|
||||||
|
$openid_args = array();
|
||||||
|
foreach ($args as $key => $value) {
|
||||||
|
|
||||||
|
if (is_array($value)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$parts = explode('.', $key, 2);
|
||||||
|
|
||||||
|
if (count($parts) == 2) {
|
||||||
|
list($prefix, $rest) = $parts;
|
||||||
|
} else {
|
||||||
|
$prefix = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($prefix != 'openid') {
|
||||||
|
$obj->args->set(array(Auth_OpenID_BARE_NS, $key), $value);
|
||||||
|
} else {
|
||||||
|
$openid_args[$rest] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($obj->_fromOpenIDArgs($openid_args)) {
|
||||||
|
return $obj;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function fromOpenIDArgs($openid_args)
|
||||||
|
{
|
||||||
|
// Takes an array.
|
||||||
|
|
||||||
|
// Construct a Message from a parsed KVForm message
|
||||||
|
$obj = new Auth_OpenID_Message();
|
||||||
|
if ($obj->_fromOpenIDArgs($openid_args)) {
|
||||||
|
return $obj;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
function _fromOpenIDArgs($openid_args)
|
||||||
|
{
|
||||||
|
global $Auth_OpenID_registered_aliases;
|
||||||
|
|
||||||
|
// Takes an Auth_OpenID_Mapping instance OR an array.
|
||||||
|
|
||||||
|
if (!Auth_OpenID_Mapping::isA($openid_args)) {
|
||||||
|
$openid_args = new Auth_OpenID_Mapping($openid_args);
|
||||||
|
}
|
||||||
|
|
||||||
|
$ns_args = array();
|
||||||
|
|
||||||
|
// Resolve namespaces
|
||||||
|
foreach ($openid_args->items() as $pair) {
|
||||||
|
list($rest, $value) = $pair;
|
||||||
|
|
||||||
|
$parts = explode('.', $rest, 2);
|
||||||
|
|
||||||
|
if (count($parts) == 2) {
|
||||||
|
list($ns_alias, $ns_key) = $parts;
|
||||||
|
} else {
|
||||||
|
$ns_alias = Auth_OpenID_NULL_NAMESPACE;
|
||||||
|
$ns_key = $rest;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($ns_alias == 'ns') {
|
||||||
|
if ($this->namespaces->addAlias($value, $ns_key) === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (($ns_alias == Auth_OpenID_NULL_NAMESPACE) &&
|
||||||
|
($ns_key == 'ns')) {
|
||||||
|
// null namespace
|
||||||
|
if ($this->setOpenIDNamespace($value, false) === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$ns_args[] = array($ns_alias, $ns_key, $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->getOpenIDNamespace()) {
|
||||||
|
if ($this->setOpenIDNamespace(Auth_OpenID_OPENID1_NS, true) ===
|
||||||
|
false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actually put the pairs into the appropriate namespaces
|
||||||
|
foreach ($ns_args as $triple) {
|
||||||
|
list($ns_alias, $ns_key, $value) = $triple;
|
||||||
|
$ns_uri = $this->namespaces->getNamespaceURI($ns_alias);
|
||||||
|
if ($ns_uri === null) {
|
||||||
|
$ns_uri = $this->_getDefaultNamespace($ns_alias);
|
||||||
|
if ($ns_uri === null) {
|
||||||
|
|
||||||
|
$ns_uri = Auth_OpenID_OPENID_NS;
|
||||||
|
$ns_key = sprintf('%s.%s', $ns_alias, $ns_key);
|
||||||
|
} else {
|
||||||
|
$this->namespaces->addAlias($ns_uri, $ns_alias, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->setArg($ns_uri, $ns_key, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _getDefaultNamespace($mystery_alias)
|
||||||
|
{
|
||||||
|
global $Auth_OpenID_registered_aliases;
|
||||||
|
if ($this->isOpenID1()) {
|
||||||
|
return @$Auth_OpenID_registered_aliases[$mystery_alias];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setOpenIDNamespace($openid_ns_uri, $implicit)
|
||||||
|
{
|
||||||
|
if (!in_array($openid_ns_uri, $this->allowed_openid_namespaces)) {
|
||||||
|
Auth_OpenID::log('Invalid null namespace: "%s"', $openid_ns_uri);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$succeeded = $this->namespaces->addAlias($openid_ns_uri,
|
||||||
|
Auth_OpenID_NULL_NAMESPACE,
|
||||||
|
$implicit);
|
||||||
|
if ($succeeded === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->_openid_ns_uri = $openid_ns_uri;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getOpenIDNamespace()
|
||||||
|
{
|
||||||
|
return $this->_openid_ns_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
function fromKVForm($kvform_string)
|
||||||
|
{
|
||||||
|
// Create a Message from a KVForm string
|
||||||
|
return Auth_OpenID_Message::fromOpenIDArgs(
|
||||||
|
Auth_OpenID_KVForm::toArray($kvform_string));
|
||||||
|
}
|
||||||
|
|
||||||
|
function copy()
|
||||||
|
{
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toPostArgs()
|
||||||
|
{
|
||||||
|
// Return all arguments with openid. in front of namespaced
|
||||||
|
// arguments.
|
||||||
|
|
||||||
|
$args = array();
|
||||||
|
|
||||||
|
// Add namespace definitions to the output
|
||||||
|
foreach ($this->namespaces->iteritems() as $pair) {
|
||||||
|
list($ns_uri, $alias) = $pair;
|
||||||
|
if ($this->namespaces->isImplicit($ns_uri)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ($alias == Auth_OpenID_NULL_NAMESPACE) {
|
||||||
|
$ns_key = 'openid.ns';
|
||||||
|
} else {
|
||||||
|
$ns_key = 'openid.ns.' . $alias;
|
||||||
|
}
|
||||||
|
$args[$ns_key] = $ns_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->args->items() as $pair) {
|
||||||
|
list($ns_parts, $value) = $pair;
|
||||||
|
list($ns_uri, $ns_key) = $ns_parts;
|
||||||
|
$key = $this->getKey($ns_uri, $ns_key);
|
||||||
|
$args[$key] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $args;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toArgs()
|
||||||
|
{
|
||||||
|
// Return all namespaced arguments, failing if any
|
||||||
|
// non-namespaced arguments exist.
|
||||||
|
$post_args = $this->toPostArgs();
|
||||||
|
$kvargs = array();
|
||||||
|
foreach ($post_args as $k => $v) {
|
||||||
|
if (strpos($k, 'openid.') !== 0) {
|
||||||
|
// raise ValueError(
|
||||||
|
// 'This message can only be encoded as a POST, because it '
|
||||||
|
// 'contains arguments that are not prefixed with "openid."')
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
$kvargs[substr($k, 7)] = $v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $kvargs;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toFormMarkup($action_url, $form_tag_attrs = null,
|
||||||
|
$submit_text = "Continue")
|
||||||
|
{
|
||||||
|
$form = "<form accept-charset=\"UTF-8\" ".
|
||||||
|
"enctype=\"application/x-www-form-urlencoded\"";
|
||||||
|
|
||||||
|
if (!$form_tag_attrs) {
|
||||||
|
$form_tag_attrs = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$form_tag_attrs['action'] = $action_url;
|
||||||
|
$form_tag_attrs['method'] = 'post';
|
||||||
|
|
||||||
|
unset($form_tag_attrs['enctype']);
|
||||||
|
unset($form_tag_attrs['accept-charset']);
|
||||||
|
|
||||||
|
if ($form_tag_attrs) {
|
||||||
|
foreach ($form_tag_attrs as $name => $attr) {
|
||||||
|
$form .= sprintf(" %s=\"%s\"", $name, $attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$form .= ">\n";
|
||||||
|
|
||||||
|
foreach ($this->toPostArgs() as $name => $value) {
|
||||||
|
$form .= sprintf(
|
||||||
|
"<input type=\"hidden\" name=\"%s\" value=\"%s\" />\n",
|
||||||
|
$name, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
$form .= sprintf("<input type=\"submit\" value=\"%s\" />\n",
|
||||||
|
$submit_text);
|
||||||
|
|
||||||
|
$form .= "</form>\n";
|
||||||
|
|
||||||
|
return $form;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toURL($base_url)
|
||||||
|
{
|
||||||
|
// Generate a GET URL with the parameters in this message
|
||||||
|
// attached as query parameters.
|
||||||
|
return Auth_OpenID::appendArgs($base_url, $this->toPostArgs());
|
||||||
|
}
|
||||||
|
|
||||||
|
function toKVForm()
|
||||||
|
{
|
||||||
|
// Generate a KVForm string that contains the parameters in
|
||||||
|
// this message. This will fail if the message contains
|
||||||
|
// arguments outside of the 'openid.' prefix.
|
||||||
|
return Auth_OpenID_KVForm::fromArray($this->toArgs());
|
||||||
|
}
|
||||||
|
|
||||||
|
function toURLEncoded()
|
||||||
|
{
|
||||||
|
// Generate an x-www-urlencoded string
|
||||||
|
$args = array();
|
||||||
|
|
||||||
|
foreach ($this->toPostArgs() as $k => $v) {
|
||||||
|
$args[] = array($k, $v);
|
||||||
|
}
|
||||||
|
|
||||||
|
sort($args);
|
||||||
|
return Auth_OpenID::httpBuildQuery($args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
function _fixNS($namespace)
|
||||||
|
{
|
||||||
|
// Convert an input value into the internally used values of
|
||||||
|
// this object
|
||||||
|
|
||||||
|
if ($namespace == Auth_OpenID_OPENID_NS) {
|
||||||
|
if ($this->_openid_ns_uri === null) {
|
||||||
|
return new Auth_OpenID_FailureResponse(null,
|
||||||
|
'OpenID namespace not set');
|
||||||
|
} else {
|
||||||
|
$namespace = $this->_openid_ns_uri;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (($namespace != Auth_OpenID_BARE_NS) &&
|
||||||
|
(!is_string($namespace))) {
|
||||||
|
//TypeError
|
||||||
|
$err_msg = sprintf("Namespace must be Auth_OpenID_BARE_NS, ".
|
||||||
|
"Auth_OpenID_OPENID_NS or a string. got %s",
|
||||||
|
print_r($namespace, true));
|
||||||
|
return new Auth_OpenID_FailureResponse(null, $err_msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (($namespace != Auth_OpenID_BARE_NS) &&
|
||||||
|
(strpos($namespace, ':') === false)) {
|
||||||
|
// fmt = 'OpenID 2.0 namespace identifiers SHOULD be URIs. Got %r'
|
||||||
|
// warnings.warn(fmt % (namespace,), DeprecationWarning)
|
||||||
|
|
||||||
|
if ($namespace == 'sreg') {
|
||||||
|
// fmt = 'Using %r instead of "sreg" as namespace'
|
||||||
|
// warnings.warn(fmt % (SREG_URI,), DeprecationWarning,)
|
||||||
|
return Auth_OpenID_SREG_URI;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $namespace;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasKey($namespace, $ns_key)
|
||||||
|
{
|
||||||
|
$namespace = $this->_fixNS($namespace);
|
||||||
|
if (Auth_OpenID::isFailure($namespace)) {
|
||||||
|
// XXX log me
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return $this->args->contains(array($namespace, $ns_key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getKey($namespace, $ns_key)
|
||||||
|
{
|
||||||
|
// Get the key for a particular namespaced argument
|
||||||
|
$namespace = $this->_fixNS($namespace);
|
||||||
|
if (Auth_OpenID::isFailure($namespace)) {
|
||||||
|
return $namespace;
|
||||||
|
}
|
||||||
|
if ($namespace == Auth_OpenID_BARE_NS) {
|
||||||
|
return $ns_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ns_alias = $this->namespaces->getAlias($namespace);
|
||||||
|
|
||||||
|
// No alias is defined, so no key can exist
|
||||||
|
if ($ns_alias === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($ns_alias == Auth_OpenID_NULL_NAMESPACE) {
|
||||||
|
$tail = $ns_key;
|
||||||
|
} else {
|
||||||
|
$tail = sprintf('%s.%s', $ns_alias, $ns_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'openid.' . $tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getArg($namespace, $key, $default = null)
|
||||||
|
{
|
||||||
|
// Get a value for a namespaced key.
|
||||||
|
$namespace = $this->_fixNS($namespace);
|
||||||
|
|
||||||
|
if (Auth_OpenID::isFailure($namespace)) {
|
||||||
|
return $namespace;
|
||||||
|
} else {
|
||||||
|
if ((!$this->args->contains(array($namespace, $key))) &&
|
||||||
|
($default == Auth_OpenID_NO_DEFAULT)) {
|
||||||
|
$err_msg = sprintf("Namespace %s missing required field %s",
|
||||||
|
$namespace, $key);
|
||||||
|
return new Auth_OpenID_FailureResponse(null, $err_msg);
|
||||||
|
} else {
|
||||||
|
return $this->args->get(array($namespace, $key), $default);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getArgs($namespace)
|
||||||
|
{
|
||||||
|
// Get the arguments that are defined for this namespace URI
|
||||||
|
|
||||||
|
$namespace = $this->_fixNS($namespace);
|
||||||
|
if (Auth_OpenID::isFailure($namespace)) {
|
||||||
|
return $namespace;
|
||||||
|
} else {
|
||||||
|
$stuff = array();
|
||||||
|
foreach ($this->args->items() as $pair) {
|
||||||
|
list($key, $value) = $pair;
|
||||||
|
list($pair_ns, $ns_key) = $key;
|
||||||
|
if ($pair_ns == $namespace) {
|
||||||
|
$stuff[$ns_key] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $stuff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateArgs($namespace, $updates)
|
||||||
|
{
|
||||||
|
// Set multiple key/value pairs in one call
|
||||||
|
|
||||||
|
$namespace = $this->_fixNS($namespace);
|
||||||
|
|
||||||
|
if (Auth_OpenID::isFailure($namespace)) {
|
||||||
|
return $namespace;
|
||||||
|
} else {
|
||||||
|
foreach ($updates as $k => $v) {
|
||||||
|
$this->setArg($namespace, $k, $v);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setArg($namespace, $key, $value)
|
||||||
|
{
|
||||||
|
// Set a single argument in this namespace
|
||||||
|
$namespace = $this->_fixNS($namespace);
|
||||||
|
|
||||||
|
if (Auth_OpenID::isFailure($namespace)) {
|
||||||
|
return $namespace;
|
||||||
|
} else {
|
||||||
|
$this->args->set(array($namespace, $key), $value);
|
||||||
|
if ($namespace !== Auth_OpenID_BARE_NS) {
|
||||||
|
$this->namespaces->add($namespace);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function delArg($namespace, $key)
|
||||||
|
{
|
||||||
|
$namespace = $this->_fixNS($namespace);
|
||||||
|
|
||||||
|
if (Auth_OpenID::isFailure($namespace)) {
|
||||||
|
return $namespace;
|
||||||
|
} else {
|
||||||
|
return $this->args->del(array($namespace, $key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAliasedArg($aliased_key, $default = null)
|
||||||
|
{
|
||||||
|
if ($aliased_key == 'ns') {
|
||||||
|
// Return the namespace URI for the OpenID namespace
|
||||||
|
return $this->getOpenIDNamespace();
|
||||||
|
}
|
||||||
|
|
||||||
|
$parts = explode('.', $aliased_key, 2);
|
||||||
|
|
||||||
|
if (count($parts) != 2) {
|
||||||
|
$ns = null;
|
||||||
|
} else {
|
||||||
|
list($alias, $key) = $parts;
|
||||||
|
|
||||||
|
if ($alias == 'ns') {
|
||||||
|
// Return the namespace URI for a namespace alias
|
||||||
|
// parameter.
|
||||||
|
return $this->namespaces->getNamespaceURI($key);
|
||||||
|
} else {
|
||||||
|
$ns = $this->namespaces->getNamespaceURI($alias);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($ns === null) {
|
||||||
|
$key = $aliased_key;
|
||||||
|
$ns = $this->getOpenIDNamespace();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->getArg($ns, $key, $default);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
91
libs/Auth/OpenID/MySQLStore.php
Normal file
91
libs/Auth/OpenID/MySQLStore.php
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
<?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 (\n".
|
||||||
|
" server_url VARCHAR(2047) NOT NULL,\n".
|
||||||
|
" timestamp INTEGER NOT NULL,\n".
|
||||||
|
" salt CHAR(40) NOT NULL,\n".
|
||||||
|
" UNIQUE (server_url(255), timestamp, salt)\n".
|
||||||
|
") ENGINE=InnoDB";
|
||||||
|
|
||||||
|
$this->sql['assoc_table'] =
|
||||||
|
"CREATE TABLE %s (\n".
|
||||||
|
" server_url BLOB NOT NULL,\n".
|
||||||
|
" handle VARCHAR(255) NOT NULL,\n".
|
||||||
|
" secret BLOB NOT NULL,\n".
|
||||||
|
" issued INTEGER NOT NULL,\n".
|
||||||
|
" lifetime INTEGER NOT NULL,\n".
|
||||||
|
" assoc_type VARCHAR(64) NOT NULL,\n".
|
||||||
|
" PRIMARY KEY (server_url(255), handle)\n".
|
||||||
|
") ENGINE=InnoDB";
|
||||||
|
|
||||||
|
$this->sql['set_assoc'] =
|
||||||
|
"REPLACE INTO %s (server_url, handle, secret, issued,\n".
|
||||||
|
" lifetime, assoc_type) 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 INTO %s (server_url, timestamp, salt) VALUES (?, ?, ?)";
|
||||||
|
|
||||||
|
$this->sql['clean_nonce'] =
|
||||||
|
"DELETE FROM %s WHERE timestamp < ?";
|
||||||
|
|
||||||
|
$this->sql['clean_assoc'] =
|
||||||
|
"DELETE FROM %s WHERE issued + lifetime < ?";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
function blobEncode($blob)
|
||||||
|
{
|
||||||
|
return "0x" . bin2hex($blob);
|
||||||
|
}
|
||||||
|
|
||||||
|
function blobDecode($blob)
|
||||||
|
{
|
||||||
|
$blob = substr($blob, 2);
|
||||||
|
$bin = '';
|
||||||
|
$i = 0;
|
||||||
|
do {
|
||||||
|
$bin .= chr(hexdec($blob{$i}.$blob{($i + 1)}));
|
||||||
|
$i += 2;
|
||||||
|
} while ($i < strlen($blob));
|
||||||
|
|
||||||
|
return $bin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
109
libs/Auth/OpenID/Nonce.php
Normal file
109
libs/Auth/OpenID/Nonce.php
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nonce-related functionality.
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Need CryptUtil to generate random strings.
|
||||||
|
*/
|
||||||
|
require_once 'Auth/OpenID/CryptUtil.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the characters that the nonces are made from.
|
||||||
|
*/
|
||||||
|
define('Auth_OpenID_Nonce_CHRS',"abcdefghijklmnopqrstuvwxyz" .
|
||||||
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
|
||||||
|
|
||||||
|
// Keep nonces for five hours (allow five hours for the combination of
|
||||||
|
// request time and clock skew). This is probably way more than is
|
||||||
|
// necessary, but there is not much overhead in storing nonces.
|
||||||
|
global $Auth_OpenID_SKEW;
|
||||||
|
$Auth_OpenID_SKEW = 60 * 60 * 5;
|
||||||
|
|
||||||
|
define('Auth_OpenID_Nonce_REGEX',
|
||||||
|
'/(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)Z(.*)/');
|
||||||
|
|
||||||
|
define('Auth_OpenID_Nonce_TIME_FMT',
|
||||||
|
'%Y-%m-%dT%H:%M:%SZ');
|
||||||
|
|
||||||
|
function Auth_OpenID_splitNonce($nonce_string)
|
||||||
|
{
|
||||||
|
// Extract a timestamp from the given nonce string
|
||||||
|
$result = preg_match(Auth_OpenID_Nonce_REGEX, $nonce_string, $matches);
|
||||||
|
if ($result != 1 || count($matches) != 8) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
list($unused,
|
||||||
|
$tm_year,
|
||||||
|
$tm_mon,
|
||||||
|
$tm_mday,
|
||||||
|
$tm_hour,
|
||||||
|
$tm_min,
|
||||||
|
$tm_sec,
|
||||||
|
$uniquifier) = $matches;
|
||||||
|
|
||||||
|
$timestamp =
|
||||||
|
@gmmktime($tm_hour, $tm_min, $tm_sec, $tm_mon, $tm_mday, $tm_year);
|
||||||
|
|
||||||
|
if ($timestamp === false || $timestamp < 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array($timestamp, $uniquifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Auth_OpenID_checkTimestamp($nonce_string,
|
||||||
|
$allowed_skew = null,
|
||||||
|
$now = null)
|
||||||
|
{
|
||||||
|
// Is the timestamp that is part of the specified nonce string
|
||||||
|
// within the allowed clock-skew of the current time?
|
||||||
|
global $Auth_OpenID_SKEW;
|
||||||
|
|
||||||
|
if ($allowed_skew === null) {
|
||||||
|
$allowed_skew = $Auth_OpenID_SKEW;
|
||||||
|
}
|
||||||
|
|
||||||
|
$parts = Auth_OpenID_splitNonce($nonce_string);
|
||||||
|
if ($parts == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($now === null) {
|
||||||
|
$now = time();
|
||||||
|
}
|
||||||
|
|
||||||
|
$stamp = $parts[0];
|
||||||
|
|
||||||
|
// Time after which we should not use the nonce
|
||||||
|
$past = $now - $allowed_skew;
|
||||||
|
|
||||||
|
// Time that is too far in the future for us to allow
|
||||||
|
$future = $now + $allowed_skew;
|
||||||
|
|
||||||
|
// the stamp is not too far in the future and is not too far
|
||||||
|
// in the past
|
||||||
|
return (($past <= $stamp) && ($stamp <= $future));
|
||||||
|
}
|
||||||
|
|
||||||
|
function Auth_OpenID_mkNonce($when = null)
|
||||||
|
{
|
||||||
|
// Generate a nonce with the current timestamp
|
||||||
|
$salt = Auth_OpenID_CryptUtil::randomString(
|
||||||
|
6, Auth_OpenID_Nonce_CHRS);
|
||||||
|
if ($when === null) {
|
||||||
|
// It's safe to call time() with no arguments; it returns a
|
||||||
|
// GMT unix timestamp on PHP 4 and PHP 5. gmmktime() with no
|
||||||
|
// args returns a local unix timestamp on PHP 4, so don't use
|
||||||
|
// that.
|
||||||
|
$when = time();
|
||||||
|
}
|
||||||
|
$time_str = gmstrftime(Auth_OpenID_Nonce_TIME_FMT, $when);
|
||||||
|
return $time_str . $salt;
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
301
libs/Auth/OpenID/PAPE.php
Normal file
301
libs/Auth/OpenID/PAPE.php
Normal file
@ -0,0 +1,301 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An implementation of the OpenID Provider Authentication Policy
|
||||||
|
* Extension 1.0
|
||||||
|
*
|
||||||
|
* See:
|
||||||
|
* http://openid.net/developers/specs/
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once "Auth/OpenID/Extension.php";
|
||||||
|
|
||||||
|
define('Auth_OpenID_PAPE_NS_URI',
|
||||||
|
"http://specs.openid.net/extensions/pape/1.0");
|
||||||
|
|
||||||
|
define('PAPE_AUTH_MULTI_FACTOR_PHYSICAL',
|
||||||
|
'http://schemas.openid.net/pape/policies/2007/06/multi-factor-physical');
|
||||||
|
define('PAPE_AUTH_MULTI_FACTOR',
|
||||||
|
'http://schemas.openid.net/pape/policies/2007/06/multi-factor');
|
||||||
|
define('PAPE_AUTH_PHISHING_RESISTANT',
|
||||||
|
'http://schemas.openid.net/pape/policies/2007/06/phishing-resistant');
|
||||||
|
|
||||||
|
define('PAPE_TIME_VALIDATOR',
|
||||||
|
'^[0-9]{4,4}-[0-9][0-9]-[0-9][0-9]T[0-9][0-9]:[0-9][0-9]:[0-9][0-9]Z$');
|
||||||
|
/**
|
||||||
|
* A Provider Authentication Policy request, sent from a relying party
|
||||||
|
* to a provider
|
||||||
|
*
|
||||||
|
* preferred_auth_policies: The authentication policies that
|
||||||
|
* the relying party prefers
|
||||||
|
*
|
||||||
|
* max_auth_age: The maximum time, in seconds, that the relying party
|
||||||
|
* wants to allow to have elapsed before the user must re-authenticate
|
||||||
|
*/
|
||||||
|
class Auth_OpenID_PAPE_Request extends Auth_OpenID_Extension {
|
||||||
|
|
||||||
|
var $ns_alias = 'pape';
|
||||||
|
var $ns_uri = Auth_OpenID_PAPE_NS_URI;
|
||||||
|
|
||||||
|
function Auth_OpenID_PAPE_Request($preferred_auth_policies=null,
|
||||||
|
$max_auth_age=null)
|
||||||
|
{
|
||||||
|
if ($preferred_auth_policies === null) {
|
||||||
|
$preferred_auth_policies = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->preferred_auth_policies = $preferred_auth_policies;
|
||||||
|
$this->max_auth_age = $max_auth_age;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an acceptable authentication policy URI to this request
|
||||||
|
*
|
||||||
|
* This method is intended to be used by the relying party to add
|
||||||
|
* acceptable authentication types to the request.
|
||||||
|
*
|
||||||
|
* policy_uri: The identifier for the preferred type of
|
||||||
|
* authentication.
|
||||||
|
*/
|
||||||
|
function addPolicyURI($policy_uri)
|
||||||
|
{
|
||||||
|
if (!in_array($policy_uri, $this->preferred_auth_policies)) {
|
||||||
|
$this->preferred_auth_policies[] = $policy_uri;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getExtensionArgs()
|
||||||
|
{
|
||||||
|
$ns_args = array(
|
||||||
|
'preferred_auth_policies' =>
|
||||||
|
implode(' ', $this->preferred_auth_policies)
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($this->max_auth_age !== null) {
|
||||||
|
$ns_args['max_auth_age'] = strval($this->max_auth_age);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ns_args;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiate a Request object from the arguments in a checkid_*
|
||||||
|
* OpenID message
|
||||||
|
*/
|
||||||
|
function fromOpenIDRequest($request)
|
||||||
|
{
|
||||||
|
$obj = new Auth_OpenID_PAPE_Request();
|
||||||
|
$args = $request->message->getArgs(Auth_OpenID_PAPE_NS_URI);
|
||||||
|
|
||||||
|
if ($args === null || $args === array()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$obj->parseExtensionArgs($args);
|
||||||
|
return $obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the state of this request to be that expressed in these
|
||||||
|
* PAPE arguments
|
||||||
|
*
|
||||||
|
* @param args: The PAPE arguments without a namespace
|
||||||
|
*/
|
||||||
|
function parseExtensionArgs($args)
|
||||||
|
{
|
||||||
|
// preferred_auth_policies is a space-separated list of policy
|
||||||
|
// URIs
|
||||||
|
$this->preferred_auth_policies = array();
|
||||||
|
|
||||||
|
$policies_str = Auth_OpenID::arrayGet($args, 'preferred_auth_policies');
|
||||||
|
if ($policies_str) {
|
||||||
|
foreach (explode(' ', $policies_str) as $uri) {
|
||||||
|
if (!in_array($uri, $this->preferred_auth_policies)) {
|
||||||
|
$this->preferred_auth_policies[] = $uri;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// max_auth_age is base-10 integer number of seconds
|
||||||
|
$max_auth_age_str = Auth_OpenID::arrayGet($args, 'max_auth_age');
|
||||||
|
if ($max_auth_age_str) {
|
||||||
|
$this->max_auth_age = Auth_OpenID::intval($max_auth_age_str);
|
||||||
|
} else {
|
||||||
|
$this->max_auth_age = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a list of authentication policy URIs that a provider
|
||||||
|
* supports, this method returns the subsequence of those types
|
||||||
|
* that are preferred by the relying party.
|
||||||
|
*
|
||||||
|
* @param supported_types: A sequence of authentication policy
|
||||||
|
* type URIs that are supported by a provider
|
||||||
|
*
|
||||||
|
* @return array The sub-sequence of the supported types that are
|
||||||
|
* preferred by the relying party. This list will be ordered in
|
||||||
|
* the order that the types appear in the supported_types
|
||||||
|
* sequence, and may be empty if the provider does not prefer any
|
||||||
|
* of the supported authentication types.
|
||||||
|
*/
|
||||||
|
function preferredTypes($supported_types)
|
||||||
|
{
|
||||||
|
$result = array();
|
||||||
|
|
||||||
|
foreach ($supported_types as $st) {
|
||||||
|
if (in_array($st, $this->preferred_auth_policies)) {
|
||||||
|
$result[] = $st;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Provider Authentication Policy response, sent from a provider to
|
||||||
|
* a relying party
|
||||||
|
*/
|
||||||
|
class Auth_OpenID_PAPE_Response extends Auth_OpenID_Extension {
|
||||||
|
|
||||||
|
var $ns_alias = 'pape';
|
||||||
|
var $ns_uri = Auth_OpenID_PAPE_NS_URI;
|
||||||
|
|
||||||
|
function Auth_OpenID_PAPE_Response($auth_policies=null, $auth_time=null,
|
||||||
|
$nist_auth_level=null)
|
||||||
|
{
|
||||||
|
if ($auth_policies) {
|
||||||
|
$this->auth_policies = $auth_policies;
|
||||||
|
} else {
|
||||||
|
$this->auth_policies = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->auth_time = $auth_time;
|
||||||
|
$this->nist_auth_level = $nist_auth_level;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a authentication policy to this response
|
||||||
|
*
|
||||||
|
* This method is intended to be used by the provider to add a
|
||||||
|
* policy that the provider conformed to when authenticating the
|
||||||
|
* user.
|
||||||
|
*
|
||||||
|
* @param policy_uri: The identifier for the preferred type of
|
||||||
|
* authentication.
|
||||||
|
*/
|
||||||
|
function addPolicyURI($policy_uri)
|
||||||
|
{
|
||||||
|
if (!in_array($policy_uri, $this->auth_policies)) {
|
||||||
|
$this->auth_policies[] = $policy_uri;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an Auth_OpenID_PAPE_Response object from a successful
|
||||||
|
* OpenID library response.
|
||||||
|
*
|
||||||
|
* @param success_response $success_response A SuccessResponse
|
||||||
|
* from Auth_OpenID_Consumer::complete()
|
||||||
|
*
|
||||||
|
* @returns: A provider authentication policy response from the
|
||||||
|
* data that was supplied with the id_res response.
|
||||||
|
*/
|
||||||
|
function fromSuccessResponse($success_response)
|
||||||
|
{
|
||||||
|
$obj = new Auth_OpenID_PAPE_Response();
|
||||||
|
|
||||||
|
// PAPE requires that the args be signed.
|
||||||
|
$args = $success_response->getSignedNS(Auth_OpenID_PAPE_NS_URI);
|
||||||
|
|
||||||
|
if ($args === null || $args === array()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $obj->parseExtensionArgs($args);
|
||||||
|
|
||||||
|
if ($result === false) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return $obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the provider authentication policy arguments into the
|
||||||
|
* internal state of this object
|
||||||
|
*
|
||||||
|
* @param args: unqualified provider authentication policy
|
||||||
|
* arguments
|
||||||
|
*
|
||||||
|
* @param strict: Whether to return false when bad data is
|
||||||
|
* encountered
|
||||||
|
*
|
||||||
|
* @return null The data is parsed into the internal fields of
|
||||||
|
* this object.
|
||||||
|
*/
|
||||||
|
function parseExtensionArgs($args, $strict=false)
|
||||||
|
{
|
||||||
|
$policies_str = Auth_OpenID::arrayGet($args, 'auth_policies');
|
||||||
|
if ($policies_str && $policies_str != "none") {
|
||||||
|
$this->auth_policies = explode(" ", $policies_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
$nist_level_str = Auth_OpenID::arrayGet($args, 'nist_auth_level');
|
||||||
|
if ($nist_level_str !== null) {
|
||||||
|
$nist_level = Auth_OpenID::intval($nist_level_str);
|
||||||
|
|
||||||
|
if ($nist_level === false) {
|
||||||
|
if ($strict) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
$nist_level = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 <= $nist_level && $nist_level < 5) {
|
||||||
|
$this->nist_auth_level = $nist_level;
|
||||||
|
} else if ($strict) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$auth_time = Auth_OpenID::arrayGet($args, 'auth_time');
|
||||||
|
if ($auth_time !== null) {
|
||||||
|
if (ereg(PAPE_TIME_VALIDATOR, $auth_time)) {
|
||||||
|
$this->auth_time = $auth_time;
|
||||||
|
} else if ($strict) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getExtensionArgs()
|
||||||
|
{
|
||||||
|
$ns_args = array();
|
||||||
|
if (count($this->auth_policies) > 0) {
|
||||||
|
$ns_args['auth_policies'] = implode(' ', $this->auth_policies);
|
||||||
|
} else {
|
||||||
|
$ns_args['auth_policies'] = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->nist_auth_level !== null) {
|
||||||
|
if (!in_array($this->nist_auth_level, range(0, 4), true)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$ns_args['nist_auth_level'] = strval($this->nist_auth_level);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->auth_time !== null) {
|
||||||
|
if (!ereg(PAPE_TIME_VALIDATOR, $this->auth_time)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ns_args['auth_time'] = $this->auth_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ns_args;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
352
libs/Auth/OpenID/Parse.php
Normal file
352
libs/Auth/OpenID/Parse.php
Normal file
@ -0,0 +1,352 @@
|
|||||||
|
<?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 &,
|
||||||
|
* <, >, and ".
|
||||||
|
*
|
||||||
|
* 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-2008 Janrain, Inc.
|
||||||
|
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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\/<>]+)';
|
||||||
|
|
||||||
|
var $_open_tag_expr = "<%s\b";
|
||||||
|
var $_close_tag_expr = "<((\/%s\b)|(%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)
|
||||||
|
{
|
||||||
|
$expr = $this->_tag_expr;
|
||||||
|
|
||||||
|
if ($close_tags) {
|
||||||
|
$options = implode("|", array_merge(array($tag_name), $close_tags));
|
||||||
|
$closer = sprintf("(?:%s)", $options);
|
||||||
|
} else {
|
||||||
|
$closer = $tag_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
$expr = sprintf($expr, $tag_name, $closer);
|
||||||
|
return sprintf("/%s/%s", $expr, $this->_re_flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
function openTag($tag_name)
|
||||||
|
{
|
||||||
|
$expr = sprintf($this->_open_tag_expr, $tag_name);
|
||||||
|
return sprintf("/%s/%s", $expr, $this->_re_flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeTag($tag_name)
|
||||||
|
{
|
||||||
|
$expr = sprintf($this->_close_tag_expr, $tag_name, $tag_name);
|
||||||
|
return sprintf("/%s/%s", $expr, $this->_re_flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
function htmlBegin($s)
|
||||||
|
{
|
||||||
|
$matches = array();
|
||||||
|
$result = preg_match($this->openTag('html'), $s,
|
||||||
|
$matches, PREG_OFFSET_CAPTURE);
|
||||||
|
if ($result === false || !$matches) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Return the offset of the first match.
|
||||||
|
return $matches[0][1];
|
||||||
|
}
|
||||||
|
|
||||||
|
function htmlEnd($s)
|
||||||
|
{
|
||||||
|
$matches = array();
|
||||||
|
$result = preg_match($this->closeTag('html'), $s,
|
||||||
|
$matches, PREG_OFFSET_CAPTURE);
|
||||||
|
if ($result === false || !$matches) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Return the offset of the first match.
|
||||||
|
return $matches[count($matches) - 1][1];
|
||||||
|
}
|
||||||
|
|
||||||
|
function headFind()
|
||||||
|
{
|
||||||
|
return $this->tagMatcher('head', array('body', 'html'));
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
$html_begin = $this->htmlBegin($stripped);
|
||||||
|
$html_end = $this->htmlEnd($stripped);
|
||||||
|
|
||||||
|
if ($html_begin === false) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($html_end === false) {
|
||||||
|
$html_end = strlen($stripped);
|
||||||
|
}
|
||||||
|
|
||||||
|
$stripped = substr($stripped, $html_begin,
|
||||||
|
$html_end - $html_begin);
|
||||||
|
|
||||||
|
// Try to find the <HEAD> tag.
|
||||||
|
$head_re = $this->headFind();
|
||||||
|
$head_matches = array();
|
||||||
|
if (!preg_match($head_re, $stripped, $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, $server_rel,
|
||||||
|
$delegate_rel)
|
||||||
|
{
|
||||||
|
$p = new Auth_OpenID_Parse();
|
||||||
|
|
||||||
|
$link_attrs = $p->parseLinkAttrs($html_text);
|
||||||
|
|
||||||
|
$server_url = $p->findFirstHref($link_attrs,
|
||||||
|
$server_rel);
|
||||||
|
|
||||||
|
if ($server_url === null) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
$delegate_url = $p->findFirstHref($link_attrs,
|
||||||
|
$delegate_rel);
|
||||||
|
return array($delegate_url, $server_url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
113
libs/Auth/OpenID/PostgreSQLStore.php
Normal file
113
libs/Auth/OpenID/PostgreSQLStore.php
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
<?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 (server_url VARCHAR(2047) NOT NULL, ".
|
||||||
|
"timestamp INTEGER NOT NULL, ".
|
||||||
|
"salt CHAR(40) NOT NULL, ".
|
||||||
|
"UNIQUE (server_url, timestamp, salt))";
|
||||||
|
|
||||||
|
$this->sql['assoc_table'] =
|
||||||
|
"CREATE TABLE %s (server_url VARCHAR(2047) NOT NULL, ".
|
||||||
|
"handle VARCHAR(255) NOT NULL, ".
|
||||||
|
"secret BYTEA NOT NULL, ".
|
||||||
|
"issued INTEGER NOT NULL, ".
|
||||||
|
"lifetime INTEGER NOT NULL, ".
|
||||||
|
"assoc_type VARCHAR(64) NOT NULL, ".
|
||||||
|
"PRIMARY KEY (server_url, handle), ".
|
||||||
|
"CONSTRAINT secret_length_constraint CHECK ".
|
||||||
|
"(LENGTH(secret) <= 128))";
|
||||||
|
|
||||||
|
$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'] =
|
||||||
|
"INSERT INTO %s (server_url, timestamp, salt) VALUES ".
|
||||||
|
"(?, ?, ?)"
|
||||||
|
;
|
||||||
|
|
||||||
|
$this->sql['clean_nonce'] =
|
||||||
|
"DELETE FROM %s WHERE timestamp < ?";
|
||||||
|
|
||||||
|
$this->sql['clean_assoc'] =
|
||||||
|
"DELETE FROM %s WHERE issued + lifetime < ?";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 blobEncode($blob)
|
||||||
|
{
|
||||||
|
return $this->_octify($blob);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
function blobDecode($blob)
|
||||||
|
{
|
||||||
|
return $this->_unoctify($blob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
569
libs/Auth/OpenID/SQLStore.php
Normal file
569
libs/Auth/OpenID/SQLStore.php
Normal file
@ -0,0 +1,569 @@
|
|||||||
|
<?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-2008 Janrain, Inc.
|
||||||
|
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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';
|
||||||
|
require_once 'Auth/OpenID/Nonce.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
require_once 'Auth/OpenID.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
require_once 'Auth/OpenID/Nonce.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
|
||||||
|
* 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 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,
|
||||||
|
$associations_table = null,
|
||||||
|
$nonces_table = null)
|
||||||
|
{
|
||||||
|
global $__Auth_OpenID_PEAR_AVAILABLE;
|
||||||
|
|
||||||
|
$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 ($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(
|
||||||
|
sprintf("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));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
function _verifySQL()
|
||||||
|
{
|
||||||
|
$missing = array();
|
||||||
|
$empty = array();
|
||||||
|
|
||||||
|
$required_sql_keys = array(
|
||||||
|
'nonce_table',
|
||||||
|
'assoc_table',
|
||||||
|
'set_assoc',
|
||||||
|
'get_assoc',
|
||||||
|
'get_assocs',
|
||||||
|
'remove_assoc'
|
||||||
|
);
|
||||||
|
|
||||||
|
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',
|
||||||
|
'clean_nonce')
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'value' => $this->associations_table_name,
|
||||||
|
'keys' => array('assoc_table',
|
||||||
|
'set_assoc',
|
||||||
|
'get_assoc',
|
||||||
|
'get_assocs',
|
||||||
|
'remove_assoc',
|
||||||
|
'clean_assoc')
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
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();
|
||||||
|
$this->connection->autoCommit(false);
|
||||||
|
|
||||||
|
if ($n && $a) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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($server_url, $timestamp, $salt)
|
||||||
|
{
|
||||||
|
$sql = $this->sql['add_nonce'];
|
||||||
|
$result = $this->connection->query($sql, array($server_url,
|
||||||
|
$timestamp,
|
||||||
|
$salt));
|
||||||
|
if ($this->isError($result)) {
|
||||||
|
$this->connection->rollback();
|
||||||
|
} else {
|
||||||
|
$this->connection->commit();
|
||||||
|
}
|
||||||
|
return $this->resultToBool($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
function useNonce($server_url, $timestamp, $salt)
|
||||||
|
{
|
||||||
|
global $Auth_OpenID_SKEW;
|
||||||
|
|
||||||
|
if ( abs($timestamp - time()) > $Auth_OpenID_SKEW ) {
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->_add_nonce($server_url, $timestamp, $salt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* "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 < Auth_OpenID::bytes($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;
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanupNonces()
|
||||||
|
{
|
||||||
|
global $Auth_OpenID_SKEW;
|
||||||
|
$v = time() - $Auth_OpenID_SKEW;
|
||||||
|
|
||||||
|
$this->connection->query($this->sql['clean_nonce'], array($v));
|
||||||
|
$num = $this->connection->affectedRows();
|
||||||
|
$this->connection->commit();
|
||||||
|
return $num;
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanupAssociations()
|
||||||
|
{
|
||||||
|
$this->connection->query($this->sql['clean_assoc'],
|
||||||
|
array(time()));
|
||||||
|
$num = $this->connection->affectedRows();
|
||||||
|
$this->connection->commit();
|
||||||
|
return $num;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
71
libs/Auth/OpenID/SQLiteStore.php
Normal file
71
libs/Auth/OpenID/SQLiteStore.php
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<?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 (server_url VARCHAR(2047), timestamp INTEGER, ".
|
||||||
|
"salt CHAR(40), UNIQUE (server_url, timestamp, salt))";
|
||||||
|
|
||||||
|
$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['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 INTO %s (server_url, timestamp, salt) VALUES (?, ?, ?)";
|
||||||
|
|
||||||
|
$this->sql['clean_nonce'] =
|
||||||
|
"DELETE FROM %s WHERE timestamp < ?";
|
||||||
|
|
||||||
|
$this->sql['clean_assoc'] =
|
||||||
|
"DELETE FROM %s WHERE issued + lifetime < ?";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
function _add_nonce($server_url, $timestamp, $salt)
|
||||||
|
{
|
||||||
|
// PECL SQLite extensions 1.0.3 and older (1.0.3 is the
|
||||||
|
// current release at the time of this writing) have a broken
|
||||||
|
// sqlite_escape_string function that breaks when passed the
|
||||||
|
// empty string. Prefixing all strings with one character
|
||||||
|
// keeps them unique and avoids this bug. The nonce table is
|
||||||
|
// write-only, so we don't have to worry about updating other
|
||||||
|
// functions with this same bad hack.
|
||||||
|
return parent::_add_nonce('x' . $server_url, $timestamp, $salt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
521
libs/Auth/OpenID/SReg.php
Normal file
521
libs/Auth/OpenID/SReg.php
Normal file
@ -0,0 +1,521 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple registration request and response parsing and object
|
||||||
|
* representation.
|
||||||
|
*
|
||||||
|
* This module contains objects representing simple registration
|
||||||
|
* requests and responses that can be used with both OpenID relying
|
||||||
|
* parties and OpenID providers.
|
||||||
|
*
|
||||||
|
* 1. The relying party creates a request object and adds it to the
|
||||||
|
* {@link Auth_OpenID_AuthRequest} object before making the
|
||||||
|
* checkid request to the OpenID provider:
|
||||||
|
*
|
||||||
|
* $sreg_req = Auth_OpenID_SRegRequest::build(array('email'));
|
||||||
|
* $auth_request->addExtension($sreg_req);
|
||||||
|
*
|
||||||
|
* 2. The OpenID provider extracts the simple registration request
|
||||||
|
* from the OpenID request using {@link
|
||||||
|
* Auth_OpenID_SRegRequest::fromOpenIDRequest}, gets the user's
|
||||||
|
* approval and data, creates an {@link Auth_OpenID_SRegResponse}
|
||||||
|
* object and adds it to the id_res response:
|
||||||
|
*
|
||||||
|
* $sreg_req = Auth_OpenID_SRegRequest::fromOpenIDRequest(
|
||||||
|
* $checkid_request);
|
||||||
|
* // [ get the user's approval and data, informing the user that
|
||||||
|
* // the fields in sreg_response were requested ]
|
||||||
|
* $sreg_resp = Auth_OpenID_SRegResponse::extractResponse(
|
||||||
|
* $sreg_req, $user_data);
|
||||||
|
* $sreg_resp->toMessage($openid_response->fields);
|
||||||
|
*
|
||||||
|
* 3. The relying party uses {@link
|
||||||
|
* Auth_OpenID_SRegResponse::fromSuccessResponse} to extract the data
|
||||||
|
* from the OpenID response:
|
||||||
|
*
|
||||||
|
* $sreg_resp = Auth_OpenID_SRegResponse::fromSuccessResponse(
|
||||||
|
* $success_response);
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import message and extension internals.
|
||||||
|
*/
|
||||||
|
require_once 'Auth/OpenID/Message.php';
|
||||||
|
require_once 'Auth/OpenID/Extension.php';
|
||||||
|
|
||||||
|
// The data fields that are listed in the sreg spec
|
||||||
|
global $Auth_OpenID_sreg_data_fields;
|
||||||
|
$Auth_OpenID_sreg_data_fields = array(
|
||||||
|
'fullname' => 'Full Name',
|
||||||
|
'nickname' => 'Nickname',
|
||||||
|
'dob' => 'Date of Birth',
|
||||||
|
'email' => 'E-mail Address',
|
||||||
|
'gender' => 'Gender',
|
||||||
|
'postcode' => 'Postal Code',
|
||||||
|
'country' => 'Country',
|
||||||
|
'language' => 'Language',
|
||||||
|
'timezone' => 'Time Zone');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check to see that the given value is a valid simple registration
|
||||||
|
* data field name. Return true if so, false if not.
|
||||||
|
*/
|
||||||
|
function Auth_OpenID_checkFieldName($field_name)
|
||||||
|
{
|
||||||
|
global $Auth_OpenID_sreg_data_fields;
|
||||||
|
|
||||||
|
if (!in_array($field_name, array_keys($Auth_OpenID_sreg_data_fields))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// URI used in the wild for Yadis documents advertising simple
|
||||||
|
// registration support
|
||||||
|
define('Auth_OpenID_SREG_NS_URI_1_0', 'http://openid.net/sreg/1.0');
|
||||||
|
|
||||||
|
// URI in the draft specification for simple registration 1.1
|
||||||
|
// <http://openid.net/specs/openid-simple-registration-extension-1_1-01.html>
|
||||||
|
define('Auth_OpenID_SREG_NS_URI_1_1', 'http://openid.net/extensions/sreg/1.1');
|
||||||
|
|
||||||
|
// This attribute will always hold the preferred URI to use when
|
||||||
|
// adding sreg support to an XRDS file or in an OpenID namespace
|
||||||
|
// declaration.
|
||||||
|
define('Auth_OpenID_SREG_NS_URI', Auth_OpenID_SREG_NS_URI_1_1);
|
||||||
|
|
||||||
|
Auth_OpenID_registerNamespaceAlias(Auth_OpenID_SREG_NS_URI_1_1, 'sreg');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does the given endpoint advertise support for simple
|
||||||
|
* registration?
|
||||||
|
*
|
||||||
|
* $endpoint: The endpoint object as returned by OpenID discovery.
|
||||||
|
* returns whether an sreg type was advertised by the endpoint
|
||||||
|
*/
|
||||||
|
function Auth_OpenID_supportsSReg(&$endpoint)
|
||||||
|
{
|
||||||
|
return ($endpoint->usesExtension(Auth_OpenID_SREG_NS_URI_1_1) ||
|
||||||
|
$endpoint->usesExtension(Auth_OpenID_SREG_NS_URI_1_0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A base class for classes dealing with Simple Registration protocol
|
||||||
|
* messages.
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
*/
|
||||||
|
class Auth_OpenID_SRegBase extends Auth_OpenID_Extension {
|
||||||
|
/**
|
||||||
|
* Extract the simple registration namespace URI from the given
|
||||||
|
* OpenID message. Handles OpenID 1 and 2, as well as both sreg
|
||||||
|
* namespace URIs found in the wild, as well as missing namespace
|
||||||
|
* definitions (for OpenID 1)
|
||||||
|
*
|
||||||
|
* $message: The OpenID message from which to parse simple
|
||||||
|
* registration fields. This may be a request or response message.
|
||||||
|
*
|
||||||
|
* Returns the sreg namespace URI for the supplied message. The
|
||||||
|
* message may be modified to define a simple registration
|
||||||
|
* namespace.
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
function _getSRegNS(&$message)
|
||||||
|
{
|
||||||
|
$alias = null;
|
||||||
|
$found_ns_uri = null;
|
||||||
|
|
||||||
|
// See if there exists an alias for one of the two defined
|
||||||
|
// simple registration types.
|
||||||
|
foreach (array(Auth_OpenID_SREG_NS_URI_1_1,
|
||||||
|
Auth_OpenID_SREG_NS_URI_1_0) as $sreg_ns_uri) {
|
||||||
|
$alias = $message->namespaces->getAlias($sreg_ns_uri);
|
||||||
|
if ($alias !== null) {
|
||||||
|
$found_ns_uri = $sreg_ns_uri;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($alias === null) {
|
||||||
|
// There is no alias for either of the types, so try to
|
||||||
|
// add one. We default to using the modern value (1.1)
|
||||||
|
$found_ns_uri = Auth_OpenID_SREG_NS_URI_1_1;
|
||||||
|
if ($message->namespaces->addAlias(Auth_OpenID_SREG_NS_URI_1_1,
|
||||||
|
'sreg') === null) {
|
||||||
|
// An alias for the string 'sreg' already exists, but
|
||||||
|
// it's defined for something other than simple
|
||||||
|
// registration
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $found_ns_uri;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object to hold the state of a simple registration request.
|
||||||
|
*
|
||||||
|
* required: A list of the required fields in this simple registration
|
||||||
|
* request
|
||||||
|
*
|
||||||
|
* optional: A list of the optional fields in this simple registration
|
||||||
|
* request
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
*/
|
||||||
|
class Auth_OpenID_SRegRequest extends Auth_OpenID_SRegBase {
|
||||||
|
|
||||||
|
var $ns_alias = 'sreg';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize an empty simple registration request.
|
||||||
|
*/
|
||||||
|
function build($required=null, $optional=null,
|
||||||
|
$policy_url=null,
|
||||||
|
$sreg_ns_uri=Auth_OpenID_SREG_NS_URI,
|
||||||
|
$cls='Auth_OpenID_SRegRequest')
|
||||||
|
{
|
||||||
|
$obj = new $cls();
|
||||||
|
|
||||||
|
$obj->required = array();
|
||||||
|
$obj->optional = array();
|
||||||
|
$obj->policy_url = $policy_url;
|
||||||
|
$obj->ns_uri = $sreg_ns_uri;
|
||||||
|
|
||||||
|
if ($required) {
|
||||||
|
if (!$obj->requestFields($required, true, true)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($optional) {
|
||||||
|
if (!$obj->requestFields($optional, false, true)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a simple registration request that contains the fields
|
||||||
|
* that were requested in the OpenID request with the given
|
||||||
|
* arguments
|
||||||
|
*
|
||||||
|
* $request: The OpenID authentication request from which to
|
||||||
|
* extract an sreg request.
|
||||||
|
*
|
||||||
|
* $cls: name of class to use when creating sreg request object.
|
||||||
|
* Used for testing.
|
||||||
|
*
|
||||||
|
* Returns the newly created simple registration request
|
||||||
|
*/
|
||||||
|
function fromOpenIDRequest($request, $cls='Auth_OpenID_SRegRequest')
|
||||||
|
{
|
||||||
|
|
||||||
|
$obj = call_user_func_array(array($cls, 'build'),
|
||||||
|
array(null, null, null, Auth_OpenID_SREG_NS_URI, $cls));
|
||||||
|
|
||||||
|
// Since we're going to mess with namespace URI mapping, don't
|
||||||
|
// mutate the object that was passed in.
|
||||||
|
$m = $request->message;
|
||||||
|
|
||||||
|
$obj->ns_uri = $obj->_getSRegNS($m);
|
||||||
|
$args = $m->getArgs($obj->ns_uri);
|
||||||
|
|
||||||
|
if ($args === null || Auth_OpenID::isFailure($args)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$obj->parseExtensionArgs($args);
|
||||||
|
|
||||||
|
return $obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the unqualified simple registration request parameters
|
||||||
|
* and add them to this object.
|
||||||
|
*
|
||||||
|
* This method is essentially the inverse of
|
||||||
|
* getExtensionArgs. This method restores the serialized simple
|
||||||
|
* registration request fields.
|
||||||
|
*
|
||||||
|
* If you are extracting arguments from a standard OpenID
|
||||||
|
* checkid_* request, you probably want to use fromOpenIDRequest,
|
||||||
|
* which will extract the sreg namespace and arguments from the
|
||||||
|
* OpenID request. This method is intended for cases where the
|
||||||
|
* OpenID server needs more control over how the arguments are
|
||||||
|
* parsed than that method provides.
|
||||||
|
*
|
||||||
|
* $args == $message->getArgs($ns_uri);
|
||||||
|
* $request->parseExtensionArgs($args);
|
||||||
|
*
|
||||||
|
* $args: The unqualified simple registration arguments
|
||||||
|
*
|
||||||
|
* strict: Whether requests with fields that are not defined in
|
||||||
|
* the simple registration specification should be tolerated (and
|
||||||
|
* ignored)
|
||||||
|
*/
|
||||||
|
function parseExtensionArgs($args, $strict=false)
|
||||||
|
{
|
||||||
|
foreach (array('required', 'optional') as $list_name) {
|
||||||
|
$required = ($list_name == 'required');
|
||||||
|
$items = Auth_OpenID::arrayGet($args, $list_name);
|
||||||
|
if ($items) {
|
||||||
|
foreach (explode(',', $items) as $field_name) {
|
||||||
|
if (!$this->requestField($field_name, $required, $strict)) {
|
||||||
|
if ($strict) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->policy_url = Auth_OpenID::arrayGet($args, 'policy_url');
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of all of the simple registration fields that were
|
||||||
|
* requested, whether they were required or optional.
|
||||||
|
*/
|
||||||
|
function allRequestedFields()
|
||||||
|
{
|
||||||
|
return array_merge($this->required, $this->optional);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Have any simple registration fields been requested?
|
||||||
|
*/
|
||||||
|
function wereFieldsRequested()
|
||||||
|
{
|
||||||
|
return count($this->allRequestedFields());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Was this field in the request?
|
||||||
|
*/
|
||||||
|
function contains($field_name)
|
||||||
|
{
|
||||||
|
return (in_array($field_name, $this->required) ||
|
||||||
|
in_array($field_name, $this->optional));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request the specified field from the OpenID user
|
||||||
|
*
|
||||||
|
* $field_name: the unqualified simple registration field name
|
||||||
|
*
|
||||||
|
* required: whether the given field should be presented to the
|
||||||
|
* user as being a required to successfully complete the request
|
||||||
|
*
|
||||||
|
* strict: whether to raise an exception when a field is added to
|
||||||
|
* a request more than once
|
||||||
|
*/
|
||||||
|
function requestField($field_name,
|
||||||
|
$required=false, $strict=false)
|
||||||
|
{
|
||||||
|
if (!Auth_OpenID_checkFieldName($field_name)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($strict) {
|
||||||
|
if ($this->contains($field_name)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (in_array($field_name, $this->required)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_array($field_name, $this->optional)) {
|
||||||
|
if ($required) {
|
||||||
|
unset($this->optional[array_search($field_name,
|
||||||
|
$this->optional)]);
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($required) {
|
||||||
|
$this->required[] = $field_name;
|
||||||
|
} else {
|
||||||
|
$this->optional[] = $field_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the given list of fields to the request
|
||||||
|
*
|
||||||
|
* field_names: The simple registration data fields to request
|
||||||
|
*
|
||||||
|
* required: Whether these values should be presented to the user
|
||||||
|
* as required
|
||||||
|
*
|
||||||
|
* strict: whether to raise an exception when a field is added to
|
||||||
|
* a request more than once
|
||||||
|
*/
|
||||||
|
function requestFields($field_names, $required=false, $strict=false)
|
||||||
|
{
|
||||||
|
if (!is_array($field_names)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($field_names as $field_name) {
|
||||||
|
if (!$this->requestField($field_name, $required, $strict=$strict)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a dictionary of unqualified simple registration arguments
|
||||||
|
* representing this request.
|
||||||
|
*
|
||||||
|
* This method is essentially the inverse of
|
||||||
|
* C{L{parseExtensionArgs}}. This method serializes the simple
|
||||||
|
* registration request fields.
|
||||||
|
*/
|
||||||
|
function getExtensionArgs()
|
||||||
|
{
|
||||||
|
$args = array();
|
||||||
|
|
||||||
|
if ($this->required) {
|
||||||
|
$args['required'] = implode(',', $this->required);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->optional) {
|
||||||
|
$args['optional'] = implode(',', $this->optional);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->policy_url) {
|
||||||
|
$args['policy_url'] = $this->policy_url;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $args;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the data returned in a simple registration response
|
||||||
|
* inside of an OpenID C{id_res} response. This object will be created
|
||||||
|
* by the OpenID server, added to the C{id_res} response object, and
|
||||||
|
* then extracted from the C{id_res} message by the Consumer.
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
*/
|
||||||
|
class Auth_OpenID_SRegResponse extends Auth_OpenID_SRegBase {
|
||||||
|
|
||||||
|
var $ns_alias = 'sreg';
|
||||||
|
|
||||||
|
function Auth_OpenID_SRegResponse($data=null,
|
||||||
|
$sreg_ns_uri=Auth_OpenID_SREG_NS_URI)
|
||||||
|
{
|
||||||
|
if ($data === null) {
|
||||||
|
$this->data = array();
|
||||||
|
} else {
|
||||||
|
$this->data = $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->ns_uri = $sreg_ns_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Take a C{L{SRegRequest}} and a dictionary of simple
|
||||||
|
* registration values and create a C{L{SRegResponse}} object
|
||||||
|
* containing that data.
|
||||||
|
*
|
||||||
|
* request: The simple registration request object
|
||||||
|
*
|
||||||
|
* data: The simple registration data for this response, as a
|
||||||
|
* dictionary from unqualified simple registration field name to
|
||||||
|
* string (unicode) value. For instance, the nickname should be
|
||||||
|
* stored under the key 'nickname'.
|
||||||
|
*/
|
||||||
|
function extractResponse($request, $data)
|
||||||
|
{
|
||||||
|
$obj = new Auth_OpenID_SRegResponse();
|
||||||
|
$obj->ns_uri = $request->ns_uri;
|
||||||
|
|
||||||
|
foreach ($request->allRequestedFields() as $field) {
|
||||||
|
$value = Auth_OpenID::arrayGet($data, $field);
|
||||||
|
if ($value !== null) {
|
||||||
|
$obj->data[$field] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a C{L{SRegResponse}} object from a successful OpenID
|
||||||
|
* library response
|
||||||
|
* (C{L{openid.consumer.consumer.SuccessResponse}}) response
|
||||||
|
* message
|
||||||
|
*
|
||||||
|
* success_response: A SuccessResponse from consumer.complete()
|
||||||
|
*
|
||||||
|
* signed_only: Whether to process only data that was
|
||||||
|
* signed in the id_res message from the server.
|
||||||
|
*
|
||||||
|
* Returns a simple registration response containing the data that
|
||||||
|
* was supplied with the C{id_res} response.
|
||||||
|
*/
|
||||||
|
function fromSuccessResponse(&$success_response, $signed_only=true)
|
||||||
|
{
|
||||||
|
global $Auth_OpenID_sreg_data_fields;
|
||||||
|
|
||||||
|
$obj = new Auth_OpenID_SRegResponse();
|
||||||
|
$obj->ns_uri = $obj->_getSRegNS($success_response->message);
|
||||||
|
|
||||||
|
if ($signed_only) {
|
||||||
|
$args = $success_response->getSignedNS($obj->ns_uri);
|
||||||
|
} else {
|
||||||
|
$args = $success_response->message->getArgs($obj->ns_uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($args === null || Auth_OpenID::isFailure($args)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($Auth_OpenID_sreg_data_fields as $field_name => $desc) {
|
||||||
|
if (in_array($field_name, array_keys($args))) {
|
||||||
|
$obj->data[$field_name] = $args[$field_name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getExtensionArgs()
|
||||||
|
{
|
||||||
|
return $this->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read-only dictionary interface
|
||||||
|
function get($field_name, $default=null)
|
||||||
|
{
|
||||||
|
if (!Auth_OpenID_checkFieldName($field_name)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Auth_OpenID::arrayGet($this->data, $field_name, $default);
|
||||||
|
}
|
||||||
|
|
||||||
|
function contents()
|
||||||
|
{
|
||||||
|
return $this->data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
1760
libs/Auth/OpenID/Server.php
Normal file
1760
libs/Auth/OpenID/Server.php
Normal file
File diff suppressed because it is too large
Load Diff
37
libs/Auth/OpenID/ServerRequest.php
Normal file
37
libs/Auth/OpenID/ServerRequest.php
Normal 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-2008 Janrain, Inc.
|
||||||
|
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
462
libs/Auth/OpenID/TrustRoot.php
Normal file
462
libs/Auth/OpenID/TrustRoot.php
Normal file
@ -0,0 +1,462 @@
|
|||||||
|
<?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-2008 Janrain, Inc.
|
||||||
|
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once 'Auth/OpenID/Discover.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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',
|
||||||
|
'/\.(ac|ad|ae|aero|af|ag|ai|al|am|an|ao|aq|ar|arpa|as|asia' .
|
||||||
|
'|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|biz|bj|bm|bn|bo|br' .
|
||||||
|
'|bs|bt|bv|bw|by|bz|ca|cat|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co' .
|
||||||
|
'|com|coop|cr|cu|cv|cx|cy|cz|de|dj|dk|dm|do|dz|ec|edu|ee|eg' .
|
||||||
|
'|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl' .
|
||||||
|
'|gm|gn|gov|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie' .
|
||||||
|
'|il|im|in|info|int|io|iq|ir|is|it|je|jm|jo|jobs|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|me|mg|mh|mil|mk|ml|mm|mn|mo|mobi|mp|mq|mr|ms|mt' .
|
||||||
|
'|mu|museum|mv|mw|mx|my|mz|na|name|nc|ne|net|nf|ng|ni|nl|no' .
|
||||||
|
'|np|nr|nu|nz|om|org|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|pro|ps|pt' .
|
||||||
|
'|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl' .
|
||||||
|
'|sm|sn|so|sr|st|su|sv|sy|sz|tc|td|tel|tf|tg|th|tj|tk|tl|tm' .
|
||||||
|
'|tn|to|tp|tr|travel|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve' .
|
||||||
|
'|vg|vi|vn|vu|wf|ws|xn--0zwm56d|xn--11b5bs3a9aj6g' .
|
||||||
|
'|xn--80akhbyknj4f|xn--9t4b11yi5a|xn--deba0ad|xn--g6w251d' .
|
||||||
|
'|xn--hgbk6aj7f53bba|xn--hlcj6aya9esc7a|xn--jxalpdlp' .
|
||||||
|
'|xn--kgbechtv|xn--zckzah|ye|yt|yu|za|zm|zw)\.?$/');
|
||||||
|
|
||||||
|
define('Auth_OpenID___HostSegmentRe',
|
||||||
|
"/^(?:[-a-zA-Z0-9!$&'\\(\\)\\*+,;=._~]|%[a-zA-Z0-9]{2})*$/");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A wrapper for trust-root related functions
|
||||||
|
*/
|
||||||
|
class Auth_OpenID_TrustRoot {
|
||||||
|
/*
|
||||||
|
* Return a discovery URL for this realm.
|
||||||
|
*
|
||||||
|
* Return null if the realm could not be parsed or was not valid.
|
||||||
|
*
|
||||||
|
* @param return_to The relying party return URL of the OpenID
|
||||||
|
* authentication request
|
||||||
|
*
|
||||||
|
* @return The URL upon which relying party discovery should be
|
||||||
|
* run in order to verify the return_to URL
|
||||||
|
*/
|
||||||
|
function buildDiscoveryURL($realm)
|
||||||
|
{
|
||||||
|
$parsed = Auth_OpenID_TrustRoot::_parse($realm);
|
||||||
|
|
||||||
|
if ($parsed === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($parsed['wildcard']) {
|
||||||
|
// Use "www." in place of the star
|
||||||
|
if ($parsed['host'][0] != '.') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$www_domain = 'www' . $parsed['host'];
|
||||||
|
|
||||||
|
return sprintf('%s://%s%s', $parsed['scheme'],
|
||||||
|
$www_domain, $parsed['path']);
|
||||||
|
} else {
|
||||||
|
return $parsed['unparsed'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
$trust_root = Auth_OpenID_urinorm($trust_root);
|
||||||
|
if ($trust_root === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preg_match("/:\/\/[^:]+(:\d+){2,}(\/|$)/", $trust_root)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!preg_match(Auth_OpenID___HostSegmentRe, $parts['host'])) {
|
||||||
|
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, 0, 1) != '/') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$path = '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
$parts['path'] = $path;
|
||||||
|
if (!isset($parts['port'])) {
|
||||||
|
$parts['port'] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$parts['unparsed'] = $trust_root;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
$host_parts = explode('.', $parts['host']);
|
||||||
|
if ($parts['wildcard']) {
|
||||||
|
// Remove the empty string from the beginning of the array
|
||||||
|
array_shift($host_parts);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($host_parts && !$host_parts[count($host_parts) - 1]) {
|
||||||
|
array_pop($host_parts);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$host_parts) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't allow adjacent dots
|
||||||
|
if (in_array('', $host_parts, true)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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];
|
||||||
|
|
||||||
|
if (count($host_parts) == 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($parts['wildcard']) {
|
||||||
|
// It's a 2-letter tld with a short second to last segment
|
||||||
|
// so there needs to be more than two segments specified
|
||||||
|
// (e.g. *.co.uk is insane)
|
||||||
|
$second_level = $host_parts[count($host_parts) - 2];
|
||||||
|
if (strlen($tld) == 2 && strlen($second_level) <= 3) {
|
||||||
|
return count($host_parts) > 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 ($base_path != $path) {
|
||||||
|
if (substr($path, 0, strlen($base_path)) != $base_path) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (substr($base_path, strlen($base_path) - 1, 1) != '/' &&
|
||||||
|
substr($path, strlen($base_path), 1) != '/') {
|
||||||
|
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']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the endpoint is a relying party OpenID return_to endpoint,
|
||||||
|
* return the endpoint URL. Otherwise, return None.
|
||||||
|
*
|
||||||
|
* This function is intended to be used as a filter for the Yadis
|
||||||
|
* filtering interface.
|
||||||
|
*
|
||||||
|
* @see: C{L{openid.yadis.services}}
|
||||||
|
* @see: C{L{openid.yadis.filters}}
|
||||||
|
*
|
||||||
|
* @param endpoint: An XRDS BasicServiceEndpoint, as returned by
|
||||||
|
* performing Yadis dicovery.
|
||||||
|
*
|
||||||
|
* @returns: The endpoint URL or None if the endpoint is not a
|
||||||
|
* relying party endpoint.
|
||||||
|
*/
|
||||||
|
function filter_extractReturnURL(&$endpoint)
|
||||||
|
{
|
||||||
|
if ($endpoint->matchTypes(array(Auth_OpenID_RP_RETURN_TO_URL_TYPE))) {
|
||||||
|
return $endpoint;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function &Auth_OpenID_extractReturnURL(&$endpoint_list)
|
||||||
|
{
|
||||||
|
$result = array();
|
||||||
|
|
||||||
|
foreach ($endpoint_list as $endpoint) {
|
||||||
|
if (filter_extractReturnURL($endpoint)) {
|
||||||
|
$result[] = $endpoint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Is the return_to URL under one of the supplied allowed return_to
|
||||||
|
* URLs?
|
||||||
|
*/
|
||||||
|
function Auth_OpenID_returnToMatches($allowed_return_to_urls, $return_to)
|
||||||
|
{
|
||||||
|
foreach ($allowed_return_to_urls as $allowed_return_to) {
|
||||||
|
// A return_to pattern works the same as a realm, except that
|
||||||
|
// it's not allowed to use a wildcard. We'll model this by
|
||||||
|
// parsing it as a realm, and not trying to match it if it has
|
||||||
|
// a wildcard.
|
||||||
|
|
||||||
|
$return_realm = Auth_OpenID_TrustRoot::_parse($allowed_return_to);
|
||||||
|
if (// Parses as a trust root
|
||||||
|
($return_realm !== false) &&
|
||||||
|
// Does not have a wildcard
|
||||||
|
(!$return_realm['wildcard']) &&
|
||||||
|
// Matches the return_to that we passed in with it
|
||||||
|
(Auth_OpenID_TrustRoot::match($allowed_return_to, $return_to))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No URL in the list matched
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Given a relying party discovery URL return a list of return_to
|
||||||
|
* URLs.
|
||||||
|
*/
|
||||||
|
function Auth_OpenID_getAllowedReturnURLs($relying_party_url, &$fetcher,
|
||||||
|
$discover_function=null)
|
||||||
|
{
|
||||||
|
if ($discover_function === null) {
|
||||||
|
$discover_function = array('Auth_Yadis_Yadis', 'discover');
|
||||||
|
}
|
||||||
|
|
||||||
|
$xrds_parse_cb = array('Auth_OpenID_ServiceEndpoint', 'fromXRDS');
|
||||||
|
|
||||||
|
list($rp_url_after_redirects, $endpoints) =
|
||||||
|
Auth_Yadis_getServiceEndpoints($relying_party_url, $xrds_parse_cb,
|
||||||
|
$discover_function, $fetcher);
|
||||||
|
|
||||||
|
if ($rp_url_after_redirects != $relying_party_url) {
|
||||||
|
// Verification caused a redirect
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
call_user_func_array($discover_function,
|
||||||
|
array($relying_party_url, $fetcher));
|
||||||
|
|
||||||
|
$return_to_urls = array();
|
||||||
|
$matching_endpoints = Auth_OpenID_extractReturnURL($endpoints);
|
||||||
|
|
||||||
|
foreach ($matching_endpoints as $e) {
|
||||||
|
$return_to_urls[] = $e->server_url;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $return_to_urls;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Verify that a return_to URL is valid for the given realm.
|
||||||
|
*
|
||||||
|
* This function builds a discovery URL, performs Yadis discovery on
|
||||||
|
* it, makes sure that the URL does not redirect, parses out the
|
||||||
|
* return_to URLs, and finally checks to see if the current return_to
|
||||||
|
* URL matches the return_to.
|
||||||
|
*
|
||||||
|
* @return true if the return_to URL is valid for the realm
|
||||||
|
*/
|
||||||
|
function Auth_OpenID_verifyReturnTo($realm_str, $return_to, &$fetcher,
|
||||||
|
$_vrfy='Auth_OpenID_getAllowedReturnURLs')
|
||||||
|
{
|
||||||
|
$disco_url = Auth_OpenID_TrustRoot::buildDiscoveryURL($realm_str);
|
||||||
|
|
||||||
|
if ($disco_url === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$allowable_urls = call_user_func_array($_vrfy,
|
||||||
|
array($disco_url, &$fetcher));
|
||||||
|
|
||||||
|
// The realm_str could not be parsed.
|
||||||
|
if ($allowable_urls === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Auth_OpenID_returnToMatches($allowable_urls, $return_to)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
249
libs/Auth/OpenID/URINorm.php
Normal file
249
libs/Auth/OpenID/URINorm.php
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URI normalization routines.
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
* @author JanRain, Inc. <openid@janrain.com>
|
||||||
|
* @copyright 2005-2008 Janrain, Inc.
|
||||||
|
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once 'Auth/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})/';
|
||||||
|
}
|
||||||
|
|
||||||
|
# gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
|
||||||
|
#
|
||||||
|
# sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
|
||||||
|
# / "*" / "+" / "," / ";" / "="
|
||||||
|
#
|
||||||
|
# unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
|
||||||
|
function Auth_OpenID_getURLIllegalCharRE()
|
||||||
|
{
|
||||||
|
return "/([^-A-Za-z0-9:\/\?#\[\]@\!\$&'\(\)\*\+,;=\._~\%])/";
|
||||||
|
}
|
||||||
|
|
||||||
|
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(Auth_Yadis_getUCSChars(),
|
||||||
|
Auth_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 (Auth_Yadis_startswith($path, '../')) {
|
||||||
|
$path = substr($path, 3);
|
||||||
|
} else if (Auth_Yadis_startswith($path, './')) {
|
||||||
|
$path = substr($path, 2);
|
||||||
|
} else if (Auth_Yadis_startswith($path, '/./')) {
|
||||||
|
$path = substr($path, 2);
|
||||||
|
} else if ($path == '/.') {
|
||||||
|
$path = '/';
|
||||||
|
} else if (Auth_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[] = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$illegal_matches = array();
|
||||||
|
preg_match(Auth_OpenID_getURLIllegalCharRE(),
|
||||||
|
$uri, $illegal_matches);
|
||||||
|
if ($illegal_matches) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$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;
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
147
libs/Auth/Yadis/HTTPFetcher.php
Normal file
147
libs/Auth/Yadis/HTTPFetcher.php
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This module contains the HTTP fetcher interface
|
||||||
|
*
|
||||||
|
* PHP versions 4 and 5
|
||||||
|
*
|
||||||
|
* LICENSE: See the COPYING file included in this distribution.
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
* @author JanRain, Inc. <openid@janrain.com>
|
||||||
|
* @copyright 2005-2008 Janrain, Inc.
|
||||||
|
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Require logging functionality
|
||||||
|
*/
|
||||||
|
require_once "Auth/OpenID.php";
|
||||||
|
|
||||||
|
define('Auth_OpenID_FETCHER_MAX_RESPONSE_KB', 1024);
|
||||||
|
define('Auth_OpenID_USER_AGENT',
|
||||||
|
'php-openid/'.Auth_OpenID_VERSION.' (php/'.phpversion().')');
|
||||||
|
|
||||||
|
class Auth_Yadis_HTTPResponse {
|
||||||
|
function Auth_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 OpenID
|
||||||
|
*/
|
||||||
|
class Auth_Yadis_HTTPFetcher {
|
||||||
|
|
||||||
|
var $timeout = 20; // timeout in seconds.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether a URL can be fetched. Returns false if the URL
|
||||||
|
* scheme is not allowed or is not supported by this fetcher
|
||||||
|
* implementation; returns true otherwise.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
function canFetchURL($url)
|
||||||
|
{
|
||||||
|
if ($this->isHTTPS($url) && !$this->supportsSSL()) {
|
||||||
|
Auth_OpenID::log("HTTPS URL unsupported fetching %s",
|
||||||
|
$url);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->allowedURL($url)) {
|
||||||
|
Auth_OpenID::log("URL fetching not allowed for '%s'",
|
||||||
|
$url);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does this fetcher implementation (and runtime) support fetching
|
||||||
|
* HTTPS URLs? May inspect the runtime environment.
|
||||||
|
*
|
||||||
|
* @return bool $support True if this fetcher supports HTTPS
|
||||||
|
* fetching; false if not.
|
||||||
|
*/
|
||||||
|
function supportsSSL()
|
||||||
|
{
|
||||||
|
trigger_error("not implemented", E_USER_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this an https URL?
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
function isHTTPS($url)
|
||||||
|
{
|
||||||
|
return (bool)preg_match('/^https:\/\//i', $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(strtolower($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 = null)
|
||||||
|
{
|
||||||
|
trigger_error("not implemented", E_USER_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
529
libs/Auth/Yadis/Manager.php
Normal file
529
libs/Auth/Yadis/Manager.php
Normal file
@ -0,0 +1,529 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Yadis service manager to be used during yadis-driven authentication
|
||||||
|
* attempts.
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base session class used by the Auth_Yadis_Manager. This
|
||||||
|
* class wraps the default PHP session machinery and should be
|
||||||
|
* subclassed if your application doesn't use PHP sessioning.
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
*/
|
||||||
|
class Auth_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.
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
*/
|
||||||
|
class Auth_Yadis_SessionLoader {
|
||||||
|
/**
|
||||||
|
* Override this.
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
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).
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
function prepareForSave($obj)
|
||||||
|
{
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A concrete loader implementation for Auth_OpenID_ServiceEndpoints.
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
*/
|
||||||
|
class Auth_OpenID_ServiceEndpointLoader extends Auth_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']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A concrete loader implementation for Auth_Yadis_Managers.
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
*/
|
||||||
|
class Auth_Yadis_ManagerLoader extends Auth_Yadis_SessionLoader {
|
||||||
|
function requiredKeys()
|
||||||
|
{
|
||||||
|
return array('starting_url',
|
||||||
|
'yadis_url',
|
||||||
|
'services',
|
||||||
|
'session_key',
|
||||||
|
'_current',
|
||||||
|
'stale');
|
||||||
|
}
|
||||||
|
|
||||||
|
function newObject($data)
|
||||||
|
{
|
||||||
|
return new Auth_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 OpenID
|
||||||
|
*/
|
||||||
|
class Auth_Yadis_Manager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Intialize a new yadis service manager.
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
function Auth_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 .cleanup() to clean up the
|
||||||
|
* session state.
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
*/
|
||||||
|
class Auth_Yadis_Discovery {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
var $DEFAULT_SUFFIX = 'auth';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
var $PREFIX = '_yadis_services_';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a discovery object.
|
||||||
|
*
|
||||||
|
* @param Auth_Yadis_PHPSession $session An object which
|
||||||
|
* implements the Auth_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 Auth_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();
|
||||||
|
|
||||||
|
list($yadis_url, $services) = call_user_func($discover_cb,
|
||||||
|
$this->url,
|
||||||
|
$fetcher);
|
||||||
|
|
||||||
|
$manager = $this->createManager($services, $yadis_url);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($manager) {
|
||||||
|
$loader = new Auth_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.
|
||||||
|
*
|
||||||
|
* @param $force True if the manager should be deleted regardless
|
||||||
|
* of whether it's a manager for $this->url.
|
||||||
|
*/
|
||||||
|
function cleanup($force=false)
|
||||||
|
{
|
||||||
|
$manager = $this->getManager($force);
|
||||||
|
if ($manager) {
|
||||||
|
$service = $manager->current();
|
||||||
|
$this->destroyManager($force);
|
||||||
|
} 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
|
||||||
|
*
|
||||||
|
* @param $force True if the manager should be returned regardless
|
||||||
|
* of whether it's a manager for $this->url.
|
||||||
|
*/
|
||||||
|
function &getManager($force=false)
|
||||||
|
{
|
||||||
|
// 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 Auth_Yadis_ManagerLoader();
|
||||||
|
$manager = $loader->fromSession(unserialize($manager_str));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($manager && ($manager->forURL($this->url) || $force)) {
|
||||||
|
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 Auth_Yadis_ManagerLoader();
|
||||||
|
$manager = new Auth_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
|
||||||
|
*
|
||||||
|
* @param $force True if the manager should be deleted regardless
|
||||||
|
* of whether it's a manager for $this->url.
|
||||||
|
*/
|
||||||
|
function destroyManager($force=false)
|
||||||
|
{
|
||||||
|
if ($this->getManager($force) !== null) {
|
||||||
|
$key = $this->getSessionKey();
|
||||||
|
$this->session->del($key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
59
libs/Auth/Yadis/Misc.php
Normal file
59
libs/Auth/Yadis/Misc.php
Normal 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-2008 Janrain, Inc.
|
||||||
|
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
|
||||||
|
*/
|
||||||
|
|
||||||
|
function Auth_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 Auth_Yadis_getIPrivateChars()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
array(0xE000, 0xF8FF),
|
||||||
|
array(0xF0000, 0xFFFFD),
|
||||||
|
array(0x100000, 0x10FFFD)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Auth_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 Auth_Yadis_startswith($s, $stuff)
|
||||||
|
{
|
||||||
|
return strpos($s, $stuff) === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
226
libs/Auth/Yadis/ParanoidHTTPFetcher.php
Normal file
226
libs/Auth/Yadis/ParanoidHTTPFetcher.php
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
<?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 OpenID
|
||||||
|
* @author JanRain, Inc. <openid@janrain.com>
|
||||||
|
* @copyright 2005-2008 Janrain, Inc.
|
||||||
|
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface import
|
||||||
|
*/
|
||||||
|
require_once "Auth/Yadis/HTTPFetcher.php";
|
||||||
|
|
||||||
|
require_once "Auth/OpenID.php";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A paranoid {@link Auth_Yadis_HTTPFetcher} class which uses CURL
|
||||||
|
* for fetching.
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
*/
|
||||||
|
class Auth_Yadis_ParanoidHTTPFetcher extends Auth_Yadis_HTTPFetcher {
|
||||||
|
function Auth_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)
|
||||||
|
{
|
||||||
|
if (strlen($this->data) > 1024*Auth_OpenID_FETCHER_MAX_RESPONSE_KB) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
$this->data .= $data;
|
||||||
|
return strlen($data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does this fetcher support SSL URLs?
|
||||||
|
*/
|
||||||
|
function supportsSSL()
|
||||||
|
{
|
||||||
|
$v = curl_version();
|
||||||
|
if(is_array($v)) {
|
||||||
|
return in_array('https', $v['protocols']);
|
||||||
|
} elseif (is_string($v)) {
|
||||||
|
return preg_match('/OpenSSL/i', $v);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function get($url, $extra_headers = null)
|
||||||
|
{
|
||||||
|
if (!$this->canFetchURL($url)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$stop = time() + $this->timeout;
|
||||||
|
$off = $this->timeout;
|
||||||
|
|
||||||
|
$redir = true;
|
||||||
|
|
||||||
|
while ($redir && ($off > 0)) {
|
||||||
|
$this->reset();
|
||||||
|
|
||||||
|
$c = curl_init();
|
||||||
|
|
||||||
|
if ($c === false) {
|
||||||
|
Auth_OpenID::log(
|
||||||
|
"curl_init returned false; could not " .
|
||||||
|
"initialize for URL '%s'", $url);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (defined('CURLOPT_NOSIGNAL')) {
|
||||||
|
curl_setopt($c, CURLOPT_NOSIGNAL, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->allowedURL($url)) {
|
||||||
|
Auth_OpenID::log("Fetching URL not allowed: %s",
|
||||||
|
$url);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
$cv = curl_version();
|
||||||
|
if(is_array($cv)) {
|
||||||
|
$curl_user_agent = 'curl/'.$cv['version'];
|
||||||
|
} else {
|
||||||
|
$curl_user_agent = $cv;
|
||||||
|
}
|
||||||
|
curl_setopt($c, CURLOPT_USERAGENT,
|
||||||
|
Auth_OpenID_USER_AGENT.' '.$curl_user_agent);
|
||||||
|
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) {
|
||||||
|
Auth_OpenID::log("Got no response code when fetching %s", $url);
|
||||||
|
Auth_OpenID::log("CURL error (%s): %s",
|
||||||
|
curl_errno($c), curl_error($c));
|
||||||
|
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 (strpos($header, ': ')) {
|
||||||
|
list($name, $value) = explode(': ', $header, 2);
|
||||||
|
$new_headers[$name] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Auth_OpenID::log(
|
||||||
|
"Successfully fetched '%s': GET response code %s",
|
||||||
|
$url, $code);
|
||||||
|
|
||||||
|
return new Auth_Yadis_HTTPResponse($url, $code,
|
||||||
|
$new_headers, $body);
|
||||||
|
}
|
||||||
|
|
||||||
|
$off = $stop - time();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function post($url, $body, $extra_headers = null)
|
||||||
|
{
|
||||||
|
if (!$this->canFetchURL($url)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->reset();
|
||||||
|
|
||||||
|
$c = curl_init();
|
||||||
|
|
||||||
|
if (defined('CURLOPT_NOSIGNAL')) {
|
||||||
|
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) {
|
||||||
|
Auth_OpenID::log("Got no response code when fetching %s", $url);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$body = $this->data;
|
||||||
|
|
||||||
|
curl_close($c);
|
||||||
|
|
||||||
|
$new_headers = $extra_headers;
|
||||||
|
|
||||||
|
foreach ($this->headers as $header) {
|
||||||
|
if (strpos($header, ': ')) {
|
||||||
|
list($name, $value) = explode(': ', $header, 2);
|
||||||
|
$new_headers[$name] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Auth_OpenID::log("Successfully fetched '%s': POST response code %s",
|
||||||
|
$url, $code);
|
||||||
|
|
||||||
|
return new Auth_Yadis_HTTPResponse($url, $code,
|
||||||
|
$new_headers, $body);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
259
libs/Auth/Yadis/ParseHTML.php
Normal file
259
libs/Auth/Yadis/ParseHTML.php
Normal file
@ -0,0 +1,259 @@
|
|||||||
|
<?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 OpenID
|
||||||
|
* @author JanRain, Inc. <openid@janrain.com>
|
||||||
|
* @copyright 2005-2008 Janrain, Inc.
|
||||||
|
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 OpenID
|
||||||
|
*/
|
||||||
|
class Auth_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 Auth_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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
249
libs/Auth/Yadis/PlainHTTPFetcher.php
Normal file
249
libs/Auth/Yadis/PlainHTTPFetcher.php
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
<?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 OpenID
|
||||||
|
* @author JanRain, Inc. <openid@janrain.com>
|
||||||
|
* @copyright 2005-2008 Janrain, Inc.
|
||||||
|
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface import
|
||||||
|
*/
|
||||||
|
require_once "Auth/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 OpenID
|
||||||
|
*/
|
||||||
|
class Auth_Yadis_PlainHTTPFetcher extends Auth_Yadis_HTTPFetcher {
|
||||||
|
/**
|
||||||
|
* Does this fetcher support SSL URLs?
|
||||||
|
*/
|
||||||
|
function supportsSSL()
|
||||||
|
{
|
||||||
|
return function_exists('openssl_open');
|
||||||
|
}
|
||||||
|
|
||||||
|
function get($url, $extra_headers = null)
|
||||||
|
{
|
||||||
|
if (!$this->canFetchURL($url)) {
|
||||||
|
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 {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!array_key_exists('path', $parts)) {
|
||||||
|
$parts['path'] = '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
$host = $parts['host'];
|
||||||
|
|
||||||
|
if ($parts['scheme'] == 'https') {
|
||||||
|
$host = 'ssl://' . $host;
|
||||||
|
}
|
||||||
|
|
||||||
|
$user_agent = Auth_OpenID_USER_AGENT;
|
||||||
|
|
||||||
|
$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 = "";
|
||||||
|
$kilobytes = 0;
|
||||||
|
while (!feof($sock) &&
|
||||||
|
$kilobytes < Auth_OpenID_FETCHER_MAX_RESPONSE_KB ) {
|
||||||
|
$data .= fgets($sock, 1024);
|
||||||
|
$kilobytes += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)) {
|
||||||
|
$parts = explode(": ", $header, 2);
|
||||||
|
|
||||||
|
if (count($parts) == 2) {
|
||||||
|
list($name, $value) = $parts;
|
||||||
|
$new_headers[$name] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Auth_Yadis_HTTPResponse($url, $code, $new_headers, $body);
|
||||||
|
}
|
||||||
|
|
||||||
|
function post($url, $body, $extra_headers = null)
|
||||||
|
{
|
||||||
|
if (!$this->canFetchURL($url)) {
|
||||||
|
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 {
|
||||||
|
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) {
|
||||||
|
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 Auth_Yadis_HTTPResponse($url, $code,
|
||||||
|
$new_headers, $response_body);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
374
libs/Auth/Yadis/XML.php
Normal file
374
libs/Auth/Yadis/XML.php
Normal file
@ -0,0 +1,374 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XML-parsing classes to wrap the domxml and DOM extensions for PHP 4
|
||||||
|
* and 5, respectively.
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 Auth_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 OpenID
|
||||||
|
*/
|
||||||
|
class Auth_Yadis_XMLParser {
|
||||||
|
/**
|
||||||
|
* Initialize an instance of Auth_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 Auth_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 Auth_Yadis_XMLParser class for
|
||||||
|
* details on this class's methods.
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
*/
|
||||||
|
class Auth_Yadis_domxml extends Auth_Yadis_XMLParser {
|
||||||
|
function Auth_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) {
|
||||||
|
$n = array();
|
||||||
|
return $n;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 Auth_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 Auth_Yadis_XMLParser class for
|
||||||
|
* details on this class's methods.
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
*/
|
||||||
|
class Auth_Yadis_dom extends Auth_Yadis_XMLParser {
|
||||||
|
function Auth_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();
|
||||||
|
|
||||||
|
if (!$result) {
|
||||||
|
return $n;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 $__Auth_Yadis_defaultParser;
|
||||||
|
$__Auth_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 Auth_Yadis_XMLParser $parser An instance of a
|
||||||
|
* Auth_Yadis_XMLParser subclass.
|
||||||
|
*/
|
||||||
|
function Auth_Yadis_setDefaultParser(&$parser)
|
||||||
|
{
|
||||||
|
global $__Auth_Yadis_defaultParser;
|
||||||
|
$__Auth_Yadis_defaultParser =& $parser;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Auth_Yadis_getSupportedExtensions()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
'dom' => array('classname' => 'Auth_Yadis_dom',
|
||||||
|
'libname' => array('dom.so', 'dom.dll')),
|
||||||
|
'domxml' => array('classname' => 'Auth_Yadis_domxml',
|
||||||
|
'libname' => array('domxml.so', 'php_domxml.dll')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an instance of a Auth_Yadis_XMLParser subclass based on
|
||||||
|
* the availability of PHP extensions for XML parsing. If
|
||||||
|
* Auth_Yadis_setDefaultParser has been called, the parser used in
|
||||||
|
* that call will be returned instead.
|
||||||
|
*/
|
||||||
|
function &Auth_Yadis_getXMLParser()
|
||||||
|
{
|
||||||
|
global $__Auth_Yadis_defaultParser;
|
||||||
|
|
||||||
|
if (isset($__Auth_Yadis_defaultParser)) {
|
||||||
|
return $__Auth_Yadis_defaultParser;
|
||||||
|
}
|
||||||
|
|
||||||
|
$p = null;
|
||||||
|
$classname = null;
|
||||||
|
|
||||||
|
$extensions = Auth_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 {
|
||||||
|
Auth_Yadis_setDefaultParser($p);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $p;
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
478
libs/Auth/Yadis/XRDS.php
Normal file
478
libs/Auth/Yadis/XRDS.php
Normal file
@ -0,0 +1,478 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This module contains the XRDS parsing code.
|
||||||
|
*
|
||||||
|
* PHP versions 4 and 5
|
||||||
|
*
|
||||||
|
* LICENSE: See the COPYING file included in this distribution.
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
* @author JanRain, Inc. <openid@janrain.com>
|
||||||
|
* @copyright 2005-2008 Janrain, Inc.
|
||||||
|
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Require the XPath implementation.
|
||||||
|
*/
|
||||||
|
require_once 'Auth/Yadis/XML.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This match mode means a given service must match ALL filters passed
|
||||||
|
* to the Auth_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 Auth_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));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XRD XML namespace
|
||||||
|
*/
|
||||||
|
define('Auth_Yadis_XMLNS_XRD_2_0', 'xri://$xrd*($v*2.0)');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XRDS XML namespace
|
||||||
|
*/
|
||||||
|
define('Auth_Yadis_XMLNS_XRDS', 'xri://$xrds');
|
||||||
|
|
||||||
|
function Auth_Yadis_getNSMap()
|
||||||
|
{
|
||||||
|
return array('xrds' => Auth_Yadis_XMLNS_XRDS,
|
||||||
|
'xrd' => Auth_Yadis_XMLNS_XRD_2_0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
function Auth_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
|
||||||
|
* Auth_Yadis_XRDS::services() and
|
||||||
|
* Auth_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 Auth_Yadis_Yadis} for more
|
||||||
|
* information on the role this class plays in Yadis discovery.
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
*/
|
||||||
|
class Auth_Yadis_Service {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an empty service object.
|
||||||
|
*/
|
||||||
|
function Auth_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
function matchTypes($type_uris)
|
||||||
|
{
|
||||||
|
$result = array();
|
||||||
|
|
||||||
|
foreach ($this->getTypes() as $typ) {
|
||||||
|
if (in_array($typ, $type_uris)) {
|
||||||
|
$result[] = $typ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 = Auth_Yadis_array_scramble($uris[$k]);
|
||||||
|
$result = array_merge($result, $new_uris);
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = array_merge($result,
|
||||||
|
Auth_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 Auth_Yadis_XMLParser}).
|
||||||
|
*/
|
||||||
|
function getElements($name)
|
||||||
|
{
|
||||||
|
return $this->parser->evalXPath($name, $this->element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the expiration date of this XRD element, or None if no
|
||||||
|
* expiration was specified.
|
||||||
|
*
|
||||||
|
* @param $default The value to use as the expiration if no expiration
|
||||||
|
* was specified in the XRD.
|
||||||
|
*/
|
||||||
|
function Auth_Yadis_getXRDExpiration($xrd_element, $default=null)
|
||||||
|
{
|
||||||
|
$expires_element = $xrd_element->$parser->evalXPath('/xrd:Expires');
|
||||||
|
if ($expires_element === null) {
|
||||||
|
return $default;
|
||||||
|
} else {
|
||||||
|
$expires_string = $expires_element->text;
|
||||||
|
|
||||||
|
// Will raise ValueError if the string is not the expected
|
||||||
|
// format
|
||||||
|
$t = strptime($expires_string, "%Y-%m-%dT%H:%M:%SZ");
|
||||||
|
|
||||||
|
if ($t === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// [int $hour [, int $minute [, int $second [,
|
||||||
|
// int $month [, int $day [, int $year ]]]]]]
|
||||||
|
return mktime($t['tm_hour'], $t['tm_min'], $t['tm_sec'],
|
||||||
|
$t['tm_mon'], $t['tm_day'], $t['tm_year']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class performs parsing of XRDS documents.
|
||||||
|
*
|
||||||
|
* You should not instantiate this class directly; rather, call
|
||||||
|
* parseXRDS statically:
|
||||||
|
*
|
||||||
|
* <pre> $xrds = Auth_Yadis_XRDS::parseXRDS($xml_string);</pre>
|
||||||
|
*
|
||||||
|
* If the XRDS can be parsed and is valid, an instance of
|
||||||
|
* Auth_Yadis_XRDS will be returned. Otherwise, null will be
|
||||||
|
* returned. This class is used by the Auth_Yadis_Yadis::discover
|
||||||
|
* method.
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
*/
|
||||||
|
class Auth_Yadis_XRDS {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiate a Auth_Yadis_XRDS object. Requires an XPath
|
||||||
|
* instance which has been used to parse a valid XRDS document.
|
||||||
|
*/
|
||||||
|
function Auth_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
|
||||||
|
* Auth_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 Auth_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 = Auth_Yadis_getXMLParser();
|
||||||
|
|
||||||
|
$ns_map = Auth_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'] != Auth_Yadis_XMLNS_XRDS) {
|
||||||
|
return $_null;
|
||||||
|
} else if (array_key_exists('xmlns', $attrs) &&
|
||||||
|
preg_match('/xri/', $attrs['xmlns']) &&
|
||||||
|
$attrs['xmlns'] != Auth_Yadis_XMLNS_XRD_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 Auth_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 Auth_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
|
||||||
|
* Auth_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
|
||||||
|
* Auth_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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
234
libs/Auth/Yadis/XRI.php
Normal file
234
libs/Auth/Yadis/XRI.php
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Routines for XRI resolution.
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
* @author JanRain, Inc. <openid@janrain.com>
|
||||||
|
* @copyright 2005-2008 Janrain, Inc.
|
||||||
|
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once 'Auth/Yadis/Misc.php';
|
||||||
|
require_once 'Auth/Yadis/Yadis.php';
|
||||||
|
require_once 'Auth/OpenID.php';
|
||||||
|
|
||||||
|
function Auth_Yadis_getDefaultProxy()
|
||||||
|
{
|
||||||
|
return 'http://xri.net/';
|
||||||
|
}
|
||||||
|
|
||||||
|
function Auth_Yadis_getXRIAuthorities()
|
||||||
|
{
|
||||||
|
return array('!', '=', '@', '+', '$', '(');
|
||||||
|
}
|
||||||
|
|
||||||
|
function Auth_Yadis_getEscapeRE()
|
||||||
|
{
|
||||||
|
$parts = array();
|
||||||
|
foreach (array_merge(Auth_Yadis_getUCSChars(),
|
||||||
|
Auth_Yadis_getIPrivateChars()) as $pair) {
|
||||||
|
list($m, $n) = $pair;
|
||||||
|
$parts[] = sprintf("%s-%s", chr($m), chr($n));
|
||||||
|
}
|
||||||
|
|
||||||
|
return sprintf('/[%s]/', implode('', $parts));
|
||||||
|
}
|
||||||
|
|
||||||
|
function Auth_Yadis_getXrefRE()
|
||||||
|
{
|
||||||
|
return '/\((.*?)\)/';
|
||||||
|
}
|
||||||
|
|
||||||
|
function Auth_Yadis_identifierScheme($identifier)
|
||||||
|
{
|
||||||
|
if (Auth_Yadis_startswith($identifier, 'xri://') ||
|
||||||
|
($identifier &&
|
||||||
|
in_array($identifier[0], Auth_Yadis_getXRIAuthorities()))) {
|
||||||
|
return "XRI";
|
||||||
|
} else {
|
||||||
|
return "URI";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Auth_Yadis_toIRINormal($xri)
|
||||||
|
{
|
||||||
|
if (!Auth_Yadis_startswith($xri, 'xri://')) {
|
||||||
|
$xri = 'xri://' . $xri;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Auth_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 Auth_Yadis_escapeForIRI($xri)
|
||||||
|
{
|
||||||
|
$xri = str_replace('%', '%25', $xri);
|
||||||
|
$xri = preg_replace_callback(Auth_Yadis_getXrefRE(),
|
||||||
|
'_escape_xref', $xri);
|
||||||
|
return $xri;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Auth_Yadis_toURINormal($xri)
|
||||||
|
{
|
||||||
|
return Auth_Yadis_iriToURI(Auth_Yadis_toIRINormal($xri));
|
||||||
|
}
|
||||||
|
|
||||||
|
function Auth_Yadis_iriToURI($iri)
|
||||||
|
{
|
||||||
|
if (1) {
|
||||||
|
return $iri;
|
||||||
|
} else {
|
||||||
|
// According to RFC 3987, section 3.1, "Mapping of IRIs to URIs"
|
||||||
|
return preg_replace_callback(Auth_Yadis_getEscapeRE(),
|
||||||
|
'Auth_Yadis_pct_escape_unicode', $iri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function Auth_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 Auth_Yadis_providerIsAuthoritative($providerID, $canonicalID)
|
||||||
|
{
|
||||||
|
$lastbang = strrpos($canonicalID, '!');
|
||||||
|
$p = substr($canonicalID, 0, $lastbang);
|
||||||
|
return $p == $providerID;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Auth_Yadis_rootAuthority($xri)
|
||||||
|
{
|
||||||
|
// Return the root authority for an XRI.
|
||||||
|
|
||||||
|
$root = null;
|
||||||
|
|
||||||
|
if (Auth_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], Auth_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 Auth_Yadis_XRI($root);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Auth_Yadis_XRI($xri)
|
||||||
|
{
|
||||||
|
if (!Auth_Yadis_startswith($xri, 'xri://')) {
|
||||||
|
$xri = 'xri://' . $xri;
|
||||||
|
}
|
||||||
|
return $xri;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Auth_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[0];
|
||||||
|
$canonicalID = Auth_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, '!'));
|
||||||
|
$parentCID = $parser->evalXPath('xrd:CanonicalID', $xrd);
|
||||||
|
if (!$parentCID) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$parentCID = Auth_Yadis_XRI($parser->content($parentCID[0]));
|
||||||
|
|
||||||
|
if (strcasecmp($parent_sought, $parentCID)) {
|
||||||
|
// raise XRDSFraud.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$childID = $parent_sought;
|
||||||
|
}
|
||||||
|
|
||||||
|
$root = Auth_Yadis_rootAuthority($iname);
|
||||||
|
if (!Auth_Yadis_providerIsAuthoritative($root, $childID)) {
|
||||||
|
// raise XRDSFraud.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $canonicalID;
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
72
libs/Auth/Yadis/XRIRes.php
Normal file
72
libs/Auth/Yadis/XRIRes.php
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Code for using a proxy XRI resolver.
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once 'Auth/Yadis/XRDS.php';
|
||||||
|
require_once 'Auth/Yadis/XRI.php';
|
||||||
|
|
||||||
|
class Auth_Yadis_ProxyResolver {
|
||||||
|
function Auth_Yadis_ProxyResolver(&$fetcher, $proxy_url = null)
|
||||||
|
{
|
||||||
|
$this->fetcher =& $fetcher;
|
||||||
|
$this->proxy_url = $proxy_url;
|
||||||
|
if (!$this->proxy_url) {
|
||||||
|
$this->proxy_url = Auth_Yadis_getDefaultProxy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function queryURL($xri, $service_type = null)
|
||||||
|
{
|
||||||
|
// trim off the xri:// prefix
|
||||||
|
$qxri = substr(Auth_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 = Auth_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 and $response->status != 206) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$xrds = Auth_Yadis_XRDS::parseXRDS($response->body);
|
||||||
|
if (!$xrds) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$canonicalID = Auth_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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
382
libs/Auth/Yadis/Yadis.php
Normal file
382
libs/Auth/Yadis/Yadis.php
Normal file
@ -0,0 +1,382 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The core PHP Yadis implementation.
|
||||||
|
*
|
||||||
|
* PHP versions 4 and 5
|
||||||
|
*
|
||||||
|
* LICENSE: See the COPYING file included in this distribution.
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
* @author JanRain, Inc. <openid@janrain.com>
|
||||||
|
* @copyright 2005-2008 Janrain, Inc.
|
||||||
|
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Need both fetcher types so we can use the right one based on the
|
||||||
|
* presence or absence of CURL.
|
||||||
|
*/
|
||||||
|
require_once "Auth/Yadis/PlainHTTPFetcher.php";
|
||||||
|
require_once "Auth/Yadis/ParanoidHTTPFetcher.php";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Need this for parsing HTML (looking for META tags).
|
||||||
|
*/
|
||||||
|
require_once "Auth/Yadis/ParseHTML.php";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Need this to parse the XRDS document during Yadis discovery.
|
||||||
|
*/
|
||||||
|
require_once "Auth/Yadis/XRDS.php";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XRDS (yadis) content type
|
||||||
|
*/
|
||||||
|
define('Auth_Yadis_CONTENT_TYPE', 'application/xrds+xml');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Yadis header
|
||||||
|
*/
|
||||||
|
define('Auth_Yadis_HEADER_NAME', 'X-XRDS-Location');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains the result of performing Yadis discovery on a URI.
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
*/
|
||||||
|
class Auth_Yadis_DiscoveryResult {
|
||||||
|
|
||||||
|
// The URI that was passed to the fetcher
|
||||||
|
var $request_uri = null;
|
||||||
|
|
||||||
|
// The result of following redirects from the request_uri
|
||||||
|
var $normalized_uri = null;
|
||||||
|
|
||||||
|
// The URI from which the response text was returned (set to
|
||||||
|
// None if there was no XRDS document found)
|
||||||
|
var $xrds_uri = null;
|
||||||
|
|
||||||
|
var $xrds = null;
|
||||||
|
|
||||||
|
// The content-type returned with the response_text
|
||||||
|
var $content_type = null;
|
||||||
|
|
||||||
|
// The document returned from the xrds_uri
|
||||||
|
var $response_text = null;
|
||||||
|
|
||||||
|
// Did the discovery fail miserably?
|
||||||
|
var $failed = false;
|
||||||
|
|
||||||
|
function Auth_Yadis_DiscoveryResult($request_uri)
|
||||||
|
{
|
||||||
|
// Initialize the state of the object
|
||||||
|
// sets all attributes to None except the request_uri
|
||||||
|
$this->request_uri = $request_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
function fail()
|
||||||
|
{
|
||||||
|
$this->failed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isFailure()
|
||||||
|
{
|
||||||
|
return $this->failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 Auth_Yadis_Service}
|
||||||
|
* objects
|
||||||
|
*/
|
||||||
|
function services()
|
||||||
|
{
|
||||||
|
if ($this->xrds) {
|
||||||
|
return $this->xrds->services();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function usedYadisLocation()
|
||||||
|
{
|
||||||
|
// Was the Yadis protocol's indirection used?
|
||||||
|
return $this->normalized_uri != $this->xrds_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isXRDS()
|
||||||
|
{
|
||||||
|
// Is the response text supposed to be an XRDS document?
|
||||||
|
return ($this->usedYadisLocation() ||
|
||||||
|
$this->content_type == Auth_Yadis_CONTENT_TYPE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Perform the Yadis protocol on the input URL and return an iterable
|
||||||
|
* of resulting endpoint objects.
|
||||||
|
*
|
||||||
|
* input_url: The URL on which to perform the Yadis protocol
|
||||||
|
*
|
||||||
|
* @return: The normalized identity URL and an iterable of endpoint
|
||||||
|
* objects generated by the filter function.
|
||||||
|
*
|
||||||
|
* xrds_parse_func: a callback which will take (uri, xrds_text) and
|
||||||
|
* return an array of service endpoint objects or null. Usually
|
||||||
|
* array('Auth_OpenID_ServiceEndpoint', 'fromXRDS').
|
||||||
|
*
|
||||||
|
* discover_func: if not null, a callback which should take (uri) and
|
||||||
|
* return an Auth_Yadis_Yadis object or null.
|
||||||
|
*/
|
||||||
|
function Auth_Yadis_getServiceEndpoints($input_url, $xrds_parse_func,
|
||||||
|
$discover_func=null, $fetcher=null)
|
||||||
|
{
|
||||||
|
if ($discover_func === null) {
|
||||||
|
$discover_function = array('Auth_Yadis_Yadis', 'discover');
|
||||||
|
}
|
||||||
|
|
||||||
|
$yadis_result = call_user_func_array($discover_func,
|
||||||
|
array($input_url, $fetcher));
|
||||||
|
|
||||||
|
if ($yadis_result === null) {
|
||||||
|
return array($input_url, array());
|
||||||
|
}
|
||||||
|
|
||||||
|
$endpoints = call_user_func_array($xrds_parse_func,
|
||||||
|
array($yadis_result->normalized_uri,
|
||||||
|
$yadis_result->response_text));
|
||||||
|
|
||||||
|
if ($endpoints === null) {
|
||||||
|
$endpoints = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
return array($yadis_result->normalized_uri, $endpoints);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 "Auth/Yadis/Yadis.php";</pre>
|
||||||
|
*
|
||||||
|
* To perform Yadis discovery, first call the "discover" method
|
||||||
|
* statically with a URI parameter:
|
||||||
|
*
|
||||||
|
* <pre> $http_response = array();
|
||||||
|
* $fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
|
||||||
|
* $yadis_object = Auth_Yadis_Yadis::discover($uri,
|
||||||
|
* $http_response, $fetcher);</pre>
|
||||||
|
*
|
||||||
|
* If the discovery succeeds, $yadis_object will be an instance of
|
||||||
|
* {@link Auth_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 Auth_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 Auth_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
|
||||||
|
* Auth_Yadis_Service}.
|
||||||
|
*
|
||||||
|
* @package OpenID
|
||||||
|
*/
|
||||||
|
class Auth_Yadis_Yadis {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an HTTP fetcher object. If the CURL extension is
|
||||||
|
* present, an instance of {@link Auth_Yadis_ParanoidHTTPFetcher}
|
||||||
|
* is returned. If not, an instance of
|
||||||
|
* {@link Auth_Yadis_PlainHTTPFetcher} is returned.
|
||||||
|
*
|
||||||
|
* If Auth_Yadis_CURL_OVERRIDE is defined, this method will always
|
||||||
|
* return a {@link Auth_Yadis_PlainHTTPFetcher}.
|
||||||
|
*/
|
||||||
|
function getHTTPFetcher($timeout = 20)
|
||||||
|
{
|
||||||
|
if (Auth_Yadis_Yadis::curlPresent() &&
|
||||||
|
(!defined('Auth_Yadis_CURL_OVERRIDE'))) {
|
||||||
|
$fetcher = new Auth_Yadis_ParanoidHTTPFetcher($timeout);
|
||||||
|
} else {
|
||||||
|
$fetcher = new Auth_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
|
||||||
|
* Auth_Yadis_HTTPResponse}.
|
||||||
|
*
|
||||||
|
* @param Auth_Yadis_HTTPFetcher $fetcher An instance of a
|
||||||
|
* Auth_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
|
||||||
|
* Auth_Yadis_Yadis, depending on whether the discovery
|
||||||
|
* succeeded.
|
||||||
|
*/
|
||||||
|
function discover($uri, &$fetcher,
|
||||||
|
$extra_ns_map = null, $timeout = 20)
|
||||||
|
{
|
||||||
|
$result = new Auth_Yadis_DiscoveryResult($uri);
|
||||||
|
|
||||||
|
$request_uri = $uri;
|
||||||
|
$headers = array("Accept: " . Auth_Yadis_CONTENT_TYPE .
|
||||||
|
', text/html; q=0.3, application/xhtml+xml; q=0.5');
|
||||||
|
|
||||||
|
if ($fetcher === null) {
|
||||||
|
$fetcher = Auth_Yadis_Yadis::getHTTPFetcher($timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = $fetcher->get($uri, $headers);
|
||||||
|
|
||||||
|
if (!$response || ($response->status != 200 and
|
||||||
|
$response->status != 206)) {
|
||||||
|
$result->fail();
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result->normalized_uri = $response->final_url;
|
||||||
|
$result->content_type = Auth_Yadis_Yadis::_getHeader(
|
||||||
|
$response->headers,
|
||||||
|
array('content-type'));
|
||||||
|
|
||||||
|
if ($result->content_type &&
|
||||||
|
(Auth_Yadis_Yadis::_getContentType($result->content_type) ==
|
||||||
|
Auth_Yadis_CONTENT_TYPE)) {
|
||||||
|
$result->xrds_uri = $result->normalized_uri;
|
||||||
|
} else {
|
||||||
|
$yadis_location = Auth_Yadis_Yadis::_getHeader(
|
||||||
|
$response->headers,
|
||||||
|
array(Auth_Yadis_HEADER_NAME));
|
||||||
|
|
||||||
|
if (!$yadis_location) {
|
||||||
|
$parser = new Auth_Yadis_ParseHTML();
|
||||||
|
$yadis_location = $parser->getHTTPEquiv($response->body);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($yadis_location) {
|
||||||
|
$result->xrds_uri = $yadis_location;
|
||||||
|
|
||||||
|
$response = $fetcher->get($yadis_location);
|
||||||
|
|
||||||
|
if ((!$response) || ($response->status != 200 and
|
||||||
|
$response->status != 206)) {
|
||||||
|
$result->fail();
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result->content_type = Auth_Yadis_Yadis::_getHeader(
|
||||||
|
$response->headers,
|
||||||
|
array('content-type'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$result->response_text = $response->body;
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
67
libs/CommunityID/Controller/Action.php
Normal file
67
libs/CommunityID/Controller/Action.php
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @copyright Copyright (C) 2005-2009 Keyboard Monkeys Ltd. http://www.kb-m.com
|
||||||
|
* @license http://creativecommons.org/licenses/BSD/ BSD License
|
||||||
|
* @author Keyboard Monkey Ltd
|
||||||
|
* @since CommunityID 0.9
|
||||||
|
* @package CommunityID
|
||||||
|
* @packager Keyboard Monkeys
|
||||||
|
*/
|
||||||
|
|
||||||
|
abstract class CommunityID_Controller_Action extends Monkeys_Controller_Action
|
||||||
|
{
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
parent::init();
|
||||||
|
Zend_Controller_Action_HelperBroker::addPrefix('CommunityID_Controller_Action_Helper');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _setBase()
|
||||||
|
{
|
||||||
|
if ($this->_config->subdomain->enabled) {
|
||||||
|
$protocol = $this->getProtocol();
|
||||||
|
|
||||||
|
$this->view->base = "$protocol://"
|
||||||
|
. ($this->_config->subdomain->use_www? 'www.' : '')
|
||||||
|
. $this->_config->subdomain->hostname;
|
||||||
|
} else {
|
||||||
|
$this->view->base = $this->view->getBase();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _validateTargetUser()
|
||||||
|
{
|
||||||
|
if (Zend_Registry::isRegistered('targetUser')) {
|
||||||
|
// used by unit tests to inject the target user
|
||||||
|
$this->targetUser = Zend_Registry::get('targetUser');
|
||||||
|
} else {
|
||||||
|
$userId = $this->_getParam('userid');
|
||||||
|
|
||||||
|
if (is_null($userId)) {
|
||||||
|
$this->targetUser = $this->user;
|
||||||
|
} elseif ($this->_getParam('userid') == 0) {
|
||||||
|
$users = new Users_Model_Users();
|
||||||
|
$this->targetUser = $users->createRow();
|
||||||
|
} else {
|
||||||
|
if ($userId != $this->user->id && $this->user->role != Users_Model_User::ROLE_ADMIN) {
|
||||||
|
$this->_helper->FlashMessenger->addMessage('Error: Invalid user id');
|
||||||
|
$this->_redirect('profile/edit');
|
||||||
|
}
|
||||||
|
$users = new Users_Model_Users();
|
||||||
|
$this->targetUser = $users->getRowInstance($userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->view->targetUser = $this->targetUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _redirectToNormalConnection()
|
||||||
|
{
|
||||||
|
if ($this->_config->SSL->enable_mixed_mode) {
|
||||||
|
$this->_redirect('http://' . $_SERVER['HTTP_HOST'] . $this->view->base);
|
||||||
|
} else {
|
||||||
|
$this->_redirect('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
36
libs/CommunityID/Controller/Action/Helper/ProviderUrl.php
Normal file
36
libs/CommunityID/Controller/Action/Helper/ProviderUrl.php
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @copyright Copyright (C) 2005-2009 Keyboard Monkeys Ltd. http://www.kb-m.com
|
||||||
|
* @license http://creativecommons.org/licenses/BSD/ BSD License
|
||||||
|
* @author Keyboard Monkey Ltd
|
||||||
|
* @since CommunityID 0.9
|
||||||
|
* @package CommunityID
|
||||||
|
* @packager Keyboard Monkeys
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This helper can only be used from IdentityController and OpenidController
|
||||||
|
*/
|
||||||
|
class CommunityID_Controller_Action_Helper_ProviderUrl
|
||||||
|
extends Zend_Controller_Action_Helper_Abstract
|
||||||
|
{
|
||||||
|
public function direct($config)
|
||||||
|
{
|
||||||
|
$currentUrl = urldecode(Zend_OpenId::selfURL());
|
||||||
|
|
||||||
|
if ($config->subdomain->enabled) {
|
||||||
|
$protocol = $this->_actionController->getProtocol();
|
||||||
|
preg_match('#(.*)\.'.$config->subdomain->hostname.'#', $currentUrl, $matches);
|
||||||
|
|
||||||
|
return "$protocol://"
|
||||||
|
. ($config->subdomain->use_www? 'www.' : '')
|
||||||
|
. $config->subdomain->hostname
|
||||||
|
. '/openid/provider';
|
||||||
|
} else {
|
||||||
|
preg_match('#(.*)/(identity|openid)?/#', $currentUrl, $matches);
|
||||||
|
|
||||||
|
return $matches[1] . '/openid/provider';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
79
libs/CommunityID/OpenId/DatabaseConnection.php
Normal file
79
libs/CommunityID/OpenId/DatabaseConnection.php
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @copyright Copyright (C) 2005-2009 Keyboard Monkeys Ltd. http://www.kb-m.com
|
||||||
|
* @license http://creativecommons.org/licenses/BSD/ BSD License
|
||||||
|
* @author Keyboard Monkey Ltd
|
||||||
|
* @since CommunityID 0.9
|
||||||
|
* @package CommunityID
|
||||||
|
* @packager Keyboard Monkeys
|
||||||
|
*/
|
||||||
|
|
||||||
|
class CommunityId_OpenId_DatabaseConnection extends Auth_OpenID_DatabaseConnection
|
||||||
|
{
|
||||||
|
private $_db;
|
||||||
|
|
||||||
|
public function __construct(Zend_Db_Adapter_Abstract $db)
|
||||||
|
{
|
||||||
|
$this->_db = $db;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function autoCommit($mode)
|
||||||
|
{
|
||||||
|
// we'll use autocommit
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function begin()
|
||||||
|
{
|
||||||
|
// unsupported
|
||||||
|
}
|
||||||
|
|
||||||
|
public function commit()
|
||||||
|
{
|
||||||
|
// unsupported
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAll($sql, $params = array())
|
||||||
|
{
|
||||||
|
$query = $this->_db->query($sql, $params);
|
||||||
|
|
||||||
|
return $result->fetchAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getOne($sql, $params = array())
|
||||||
|
{
|
||||||
|
$query = $this->_db->query($sql, $params);
|
||||||
|
|
||||||
|
$result = $query->fetch();
|
||||||
|
if (!$result) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRow($sql, $params = array())
|
||||||
|
{
|
||||||
|
$query = $this->_db->query($sql, $params);
|
||||||
|
|
||||||
|
return $query->fetch();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function query($sql, $params = array())
|
||||||
|
{
|
||||||
|
$this->_db->query($sql, $params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rollback()
|
||||||
|
{
|
||||||
|
// unsupported
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Not part of the interface, but bug in Auth_OpenID_SQLStore obliges me to define it
|
||||||
|
*/
|
||||||
|
public function setFetchMode($whateva)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
62
libs/Monkeys/AntiSpam.php
Normal file
62
libs/Monkeys/AntiSpam.php
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @copyright Copyright (C) 2005-2008 Keyboard Monkeys Ltd. http://www.kb-m.com
|
||||||
|
* @license http://www.fsf.org/copyleft/lgpl.html GNU Lesser General Public License
|
||||||
|
* @author Alejandro Pedraza
|
||||||
|
* @since Sciret 1.2
|
||||||
|
* @package Sciret
|
||||||
|
* @packager Keyboard Monkeys
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Monkeys_AntiSpam extends Zend_Service_Akismet
|
||||||
|
{
|
||||||
|
const TYPE_AKISMET = 1;
|
||||||
|
const TYPE_TYPEPAD = 2;
|
||||||
|
|
||||||
|
const TYPEPAD_API_URL = 'api.antispam.typepad.com';
|
||||||
|
|
||||||
|
private $_type;
|
||||||
|
|
||||||
|
public function __construct($type)
|
||||||
|
{
|
||||||
|
$this->_type = $type;
|
||||||
|
|
||||||
|
switch ($type) {
|
||||||
|
case self::TYPE_AKISMET:
|
||||||
|
$apiKey = Zend_Registry::get('config')->akismet->key;
|
||||||
|
break;
|
||||||
|
case self::TYPE_TYPEPAD:
|
||||||
|
$apiKey = Zend_Registry::get('config')->typePadAntiSpam->key;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception('Wrong spam service type');
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::__construct($apiKey, 'http://www.kb-m.com');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _post($host, $path, array $params)
|
||||||
|
{
|
||||||
|
if ($this->_type == self::TYPE_TYPEPAD) {
|
||||||
|
$caller = $this->_getCallerMethod();
|
||||||
|
if (strtolower($caller) == 'verifykey') {
|
||||||
|
$host = self::TYPEPAD_API_URL;
|
||||||
|
} else {
|
||||||
|
$host = $this->getApiKey() . '.' . self::TYPEPAD_API_URL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::_post($host, $path, $params);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function _getCallerMethod()
|
||||||
|
{
|
||||||
|
$backTrace = debug_backtrace();
|
||||||
|
|
||||||
|
return $backTrace[2]['function'];
|
||||||
|
}
|
||||||
|
}
|
10
libs/Monkeys/Application/Module/Autoloader.php
Normal file
10
libs/Monkeys/Application/Module/Autoloader.php
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class Monkeys_Application_Module_Autoloader extends Zend_Application_Module_Autoloader
|
||||||
|
{
|
||||||
|
public function __construct($options)
|
||||||
|
{
|
||||||
|
parent::__construct($options);
|
||||||
|
$this->addResourceType('controllerHelpers', 'controllers', 'Controller');
|
||||||
|
}
|
||||||
|
}
|
@ -1,14 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
|
||||||
* @copyright Copyright (C) 2005-2009 Keyboard Monkeys Ltd. http://www.kb-m.com
|
|
||||||
* @license http://creativecommons.org/licenses/BSD/ BSD License
|
|
||||||
* @author Keyboard Monkey Ltd
|
|
||||||
* @since CommunityID 0.9
|
|
||||||
* @package CommunityID
|
|
||||||
* @packager Keyboard Monkeys
|
|
||||||
*/
|
|
||||||
|
|
||||||
abstract class Monkeys_Controller_Action extends Zend_Controller_Action
|
abstract class Monkeys_Controller_Action extends Zend_Controller_Action
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@ -18,20 +9,30 @@ abstract class Monkeys_Controller_Action extends Zend_Controller_Action
|
|||||||
protected $targetUser;
|
protected $targetUser;
|
||||||
|
|
||||||
protected $_config;
|
protected $_config;
|
||||||
|
protected $_settings;
|
||||||
protected $_numCols = 2;
|
protected $_numCols = 2;
|
||||||
|
protected $_title = '';
|
||||||
protected $underMaintenance = false;
|
protected $underMaintenance = false;
|
||||||
|
|
||||||
public function init()
|
public function init()
|
||||||
{
|
{
|
||||||
|
$this->_config = Zend_Registry::get('config');
|
||||||
|
$this->_settings = new Model_Settings();
|
||||||
|
|
||||||
|
if ($this->_request->getModuleName() != 'install'
|
||||||
|
&& strtoupper(get_class($this)) != 'ERRORCONTROLLER'
|
||||||
|
&& $this->_needsUpgrade()) {
|
||||||
|
$this->_redirect('/install/upgrade');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!Zend_Registry::isRegistered('user')) {
|
if (!Zend_Registry::isRegistered('user')) {
|
||||||
// guest user
|
// guest user
|
||||||
$users = new Users();
|
$users = new Users_Model_Users();
|
||||||
$user = $users->createRow();
|
$user = $users->createRow();
|
||||||
Zend_Registry::set('user', $user);
|
Zend_Registry::set('user', $user);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->_config = Zend_Registry::get('config');
|
|
||||||
|
|
||||||
$this->user = Zend_Registry::get('user');
|
$this->user = Zend_Registry::get('user');
|
||||||
$this->view->user = $this->user;
|
$this->view->user = $this->user;
|
||||||
|
|
||||||
@ -45,6 +46,18 @@ abstract class Monkeys_Controller_Action extends Zend_Controller_Action
|
|||||||
$this->_setBase();
|
$this->_setBase();
|
||||||
$this->view->numCols = $this->_numCols;
|
$this->view->numCols = $this->_numCols;
|
||||||
|
|
||||||
|
$this->view->module = $this->getRequest()->getModuleName();
|
||||||
|
|
||||||
|
if ($this->_getParam('subtitle')) {
|
||||||
|
$this->view->pageSubtitle = $this->view->escape($this->_getParam('subtitle'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->getRequest()->getParam('next')) {
|
||||||
|
$this->view->nextAction = $this->getRequest()->getParam('next');
|
||||||
|
} else {
|
||||||
|
$this->view->nextAction = '';
|
||||||
|
}
|
||||||
|
|
||||||
if ($this->getRequest()->isXmlHttpRequest()) {
|
if ($this->getRequest()->isXmlHttpRequest()) {
|
||||||
$slowdown = $this->_config->environment->ajax_slowdown;
|
$slowdown = $this->_config->environment->ajax_slowdown;
|
||||||
if ($slowdown > 0) {
|
if ($slowdown > 0) {
|
||||||
@ -52,13 +65,20 @@ abstract class Monkeys_Controller_Action extends Zend_Controller_Action
|
|||||||
}
|
}
|
||||||
$this->_helper->layout->disableLayout();
|
$this->_helper->layout->disableLayout();
|
||||||
} else {
|
} else {
|
||||||
$this->view->version = Setup::VERSION;
|
$this->view->version = Application::VERSION;
|
||||||
$this->view->messages = $this->_helper->FlashMessenger->getMessages();
|
$this->view->messages = $this->_helper->FlashMessenger->getMessages();
|
||||||
$this->view->loaderCombine = $this->_config->environment->YDN? 'true' : 'false';
|
$this->view->loaderCombine = $this->_config->environment->YDN? 'true' : 'false';
|
||||||
$this->view->loaderBase = $this->_config->environment->YDN?
|
$this->view->loaderBase = $this->_config->environment->YDN?
|
||||||
'http://yui.yahooapis.com/2.6.0/build/'
|
'http://yui.yahooapis.com/2.7.0/build/'
|
||||||
: $this->view->base . '/javascript/yui/';
|
: $this->view->base . '/javascript/yui/';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->view->min = $this->_config->environment->production ? '-min' : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function postDispatch()
|
||||||
|
{
|
||||||
|
$this->view->title = $this->_title;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function _setScriptPaths()
|
private function _setScriptPaths()
|
||||||
@ -75,43 +95,29 @@ abstract class Monkeys_Controller_Action extends Zend_Controller_Action
|
|||||||
$view->addScriptPath($newPath);
|
$view->addScriptPath($newPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function _setBase()
|
protected function _setBase()
|
||||||
{
|
{
|
||||||
if ($this->_config->subdomain->enabled) {
|
$this->view->base = $this->view->getBase();
|
||||||
$protocol = $this->_getProtocol();
|
|
||||||
|
|
||||||
$this->view->base = "$protocol://"
|
|
||||||
. ($this->_config->subdomain->use_www? 'www.' : '')
|
|
||||||
. $this->_config->subdomain->hostname;
|
|
||||||
} else {
|
|
||||||
$this->view->base = $this->view->getBase();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function _validateTargetUser()
|
protected abstract function _validateTargetUser();
|
||||||
{
|
|
||||||
if (Zend_Registry::isRegistered('targetUser')) {
|
|
||||||
// used by unit tests to inject the target user
|
|
||||||
$this->targetUser = Zend_Registry::get('targetUser');
|
|
||||||
} else {
|
|
||||||
$userId = $this->_getParam('userid');
|
|
||||||
|
|
||||||
if (is_null($userId)) {
|
protected function _needsUpgrade()
|
||||||
$this->targetUser = $this->user;
|
{
|
||||||
} elseif ($this->_getParam('userid') == 0) {
|
require 'setup/versions.php';
|
||||||
$users = new Users();
|
|
||||||
$this->targetUser = $users->createRow();
|
$lastVersion = array_pop($versions);
|
||||||
} else {
|
|
||||||
if ($userId != $this->user->id && $this->user->role != User::ROLE_ADMIN) {
|
return $lastVersion != $this->_getDbVersion();
|
||||||
$this->_helper->FlashMessenger->addMessage('Error: Invalid user id');
|
}
|
||||||
$this->_redirect('profile/edit');
|
|
||||||
}
|
protected function _getDbVersion()
|
||||||
$users = new Users();
|
{
|
||||||
$this->targetUser = $users->getRowInstance($userId);
|
if (!$version = $this->_settings->getVersion()) {
|
||||||
}
|
$version = '1.0.1';
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->view->targetUser = $this->targetUser;
|
return $version;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function _checkMaintenanceMode()
|
protected function _checkMaintenanceMode()
|
||||||
@ -122,20 +128,10 @@ abstract class Monkeys_Controller_Action extends Zend_Controller_Action
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$settings = new Settings();
|
$this->underMaintenance = $this->_settings->isMaintenanceMode();
|
||||||
$this->underMaintenance = $settings->isMaintenanceMode();
|
|
||||||
$this->view->underMaintenance = $this->underMaintenance;
|
$this->view->underMaintenance = $this->underMaintenance;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function _redirectToNormalConnection()
|
|
||||||
{
|
|
||||||
if ($this->_config->SSL->enable_mixed_mode) {
|
|
||||||
$this->_redirect('http://' . $_SERVER['HTTP_HOST'] . $this->view->base);
|
|
||||||
} else {
|
|
||||||
$this->_redirect('');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function _redirectForMaintenance($backToNormalConnection = false)
|
protected function _redirectForMaintenance($backToNormalConnection = false)
|
||||||
{
|
{
|
||||||
if ($backToNormalConnection) {
|
if ($backToNormalConnection) {
|
||||||
@ -152,7 +148,7 @@ abstract class Monkeys_Controller_Action extends Zend_Controller_Action
|
|||||||
return parent::_redirect($url, $options);
|
return parent::_redirect($url, $options);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function _getProtocol()
|
public function getProtocol()
|
||||||
{
|
{
|
||||||
if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
|
if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
|
||||||
return 'https';
|
return 'https';
|
||||||
@ -160,4 +156,16 @@ abstract class Monkeys_Controller_Action extends Zend_Controller_Action
|
|||||||
return 'http';
|
return 'http';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function _checkPermission($permission)
|
||||||
|
{
|
||||||
|
if (!$this->_hasPermission($permission)) {
|
||||||
|
throw new Monkeys_AccessDeniedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _overrideNumCols($numCols)
|
||||||
|
{
|
||||||
|
$this->view->numCols = $this->_numCols = $numCols;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,5 @@
|
|||||||
<?
|
<?
|
||||||
|
|
||||||
/*
|
|
||||||
* @copyright Copyright (C) 2005-2009 Keyboard Monkeys Ltd. http://www.kb-m.com
|
|
||||||
* @license http://creativecommons.org/licenses/BSD/ BSD License
|
|
||||||
* @author Keyboard Monkey Ltd
|
|
||||||
* @since CommunityID 0.9
|
|
||||||
* @package CommunityID
|
|
||||||
* @packager Keyboard Monkeys
|
|
||||||
*/
|
|
||||||
|
|
||||||
abstract class Monkeys_Controller_Error extends Monkeys_Controller_Action
|
abstract class Monkeys_Controller_Error extends Monkeys_Controller_Action
|
||||||
{
|
{
|
||||||
protected $_numCols = 1;
|
protected $_numCols = 1;
|
||||||
@ -115,4 +106,8 @@ EOD;
|
|||||||
|
|
||||||
return $mail;
|
return $mail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function _validateTargetUser()
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
|
||||||
* @copyright Copyright (C) 2005-2009 Keyboard Monkeys Ltd. http://www.kb-m.com
|
|
||||||
* @license http://creativecommons.org/licenses/BSD/ BSD License
|
|
||||||
* @author Keyboard Monkey Ltd
|
|
||||||
* @since CommunityID 0.9
|
|
||||||
* @package CommunityID
|
|
||||||
* @packager Keyboard Monkeys
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Monkeys_Controller_Plugin_Auth extends Zend_Controller_Plugin_Abstract
|
class Monkeys_Controller_Plugin_Auth extends Zend_Controller_Plugin_Abstract
|
||||||
{
|
{
|
||||||
private $_acl;
|
private $_acl;
|
||||||
@ -18,6 +9,10 @@ class Monkeys_Controller_Plugin_Auth extends Zend_Controller_Plugin_Abstract
|
|||||||
$this->_acl = $acl;
|
$this->_acl = $acl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Here we only check for the basic action access permissions.
|
||||||
|
* In Monkeys_Controller_Action we check for more specific permissions
|
||||||
|
*/
|
||||||
public function preDispatch($request)
|
public function preDispatch($request)
|
||||||
{
|
{
|
||||||
if (!Zend_Registry::get('config')->environment->installed
|
if (!Zend_Registry::get('config')->environment->installed
|
||||||
@ -36,7 +31,7 @@ class Monkeys_Controller_Plugin_Auth extends Zend_Controller_Plugin_Abstract
|
|||||||
$user= Zend_Registry::get('user');
|
$user= Zend_Registry::get('user');
|
||||||
} else {
|
} else {
|
||||||
$auth = Zend_Auth::getInstance();
|
$auth = Zend_Auth::getInstance();
|
||||||
$users = new Users();
|
$users = new Users_Model_Users();
|
||||||
if ($auth->hasIdentity()) {
|
if ($auth->hasIdentity()) {
|
||||||
$user = $auth->getStorage()->read();
|
$user = $auth->getStorage()->read();
|
||||||
$user->init();
|
$user->init();
|
||||||
@ -59,7 +54,7 @@ class Monkeys_Controller_Plugin_Auth extends Zend_Controller_Plugin_Abstract
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if an admin is not allowed for this action, then the action doesn't exist
|
// if an admin is not allowed for this action, then the action doesn't exist
|
||||||
if (!$this->_acl->isAllowed(User::ROLE_ADMIN, $resource, $request->getActionName())) {
|
if (!$this->_acl->isAllowed(Users_Model_User::ROLE_ADMIN, $resource, $request->getActionName())) {
|
||||||
//echo "role: " . $user->role . " - resource: $resource - privilege: " . $request->getActionName() . "<br>\n";
|
//echo "role: " . $user->role . " - resource: $resource - privilege: " . $request->getActionName() . "<br>\n";
|
||||||
throw new Monkeys_BadUrlException($this->getRequest()->getRequestUri());
|
throw new Monkeys_BadUrlException($this->getRequest()->getRequestUri());
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
|
||||||
* @copyright Copyright (C) 2005-2009 Keyboard Monkeys Ltd. http://www.kb-m.com
|
|
||||||
* @license http://creativecommons.org/licenses/BSD/ BSD License
|
|
||||||
* @author Keyboard Monkey Ltd
|
|
||||||
* @since CommunityID 0.9
|
|
||||||
* @package CommunityID
|
|
||||||
* @packager Keyboard Monkeys
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Monkeys_Db_Profiler extends Zend_Db_Profiler
|
class Monkeys_Db_Profiler extends Zend_Db_Profiler
|
||||||
{
|
{
|
||||||
public function Monkeys_Db_Profiler()
|
public function Monkeys_Db_Profiler()
|
||||||
|
@ -1,14 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
|
||||||
* @copyright Copyright (C) 2005-2009 Keyboard Monkeys Ltd. http://www.kb-m.com
|
|
||||||
* @license http://creativecommons.org/licenses/BSD/ BSD License
|
|
||||||
* @author Keyboard Monkey Ltd
|
|
||||||
* @since CommunityID 0.9
|
|
||||||
* @package CommunityID
|
|
||||||
* @packager Keyboard Monkeys
|
|
||||||
*/
|
|
||||||
|
|
||||||
abstract class Monkeys_Db_Table_Gateway extends Zend_Db_Table_Abstract
|
abstract class Monkeys_Db_Table_Gateway extends Zend_Db_Table_Abstract
|
||||||
{
|
{
|
||||||
public function getRowInstance($id)
|
public function getRowInstance($id)
|
||||||
|
4
libs/Monkeys/DuplicateException.php
Normal file
4
libs/Monkeys/DuplicateException.php
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class Monkeys_DuplicateException extends Zend_Exception {}
|
||||||
|
|
@ -1,15 +1,20 @@
|
|||||||
<?
|
<?
|
||||||
|
|
||||||
class Monkeys_Form_Decorator_Composite extends Zend_Form_Decorator_Abstract
|
class Monkeys_Form_Decorator_Composite extends Zend_Form_Decorator_Abstract
|
||||||
|
implements Zend_Form_Decorator_Marker_File_Interface // to avoid Zend_Form_Element_File to whine
|
||||||
{
|
{
|
||||||
public function buildLabel()
|
public function buildLabel()
|
||||||
{
|
{
|
||||||
$element = $this->getElement();
|
$element = $this->getElement();
|
||||||
$label = $element->getLabel();
|
$label = $element->getLabel();
|
||||||
|
if ($label == '') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if ($translator = $element->getTranslator()) {
|
if ($translator = $element->getTranslator()) {
|
||||||
$label = $translator->translate($label);
|
$label = $translator->translate($label);
|
||||||
}
|
}
|
||||||
if ($element->isRequired()) {
|
if ($element->isRequired() && !$this->getOption('dontMarkRequired')) {
|
||||||
$label .= '*';
|
$label .= '*';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,6 +88,7 @@ class Monkeys_Form_Decorator_Composite extends Zend_Form_Decorator_Abstract
|
|||||||
return $content;
|
return $content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$separator = $this->getSeparator();
|
||||||
$placement = $this->getPlacement();
|
$placement = $this->getPlacement();
|
||||||
$label = $this->buildLabel();
|
$label = $this->buildLabel();
|
||||||
$input = $this->buildInput($content);
|
$input = $this->buildInput($content);
|
||||||
@ -102,15 +108,30 @@ class Monkeys_Form_Decorator_Composite extends Zend_Form_Decorator_Abstract
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($this->getOption('wideLabel')) {
|
if ($this->getOption('wideLabel')) {
|
||||||
$output = "<div class=\"yui-$yuiGridType\" style=\"padding-bottom:10px\">\n"
|
if ($label !== false) {
|
||||||
." <div class=\"formLabel\" style=\"padding-bottom:10px\">$label</div>\n"
|
$output = "<div class=\"yui-$yuiGridType\" style=\"padding-bottom:10px\">\n"
|
||||||
." <div class=\"yui-u first\"> </div>\n"
|
." <div class=\"formLabel\" style=\"padding-bottom:10px\">$label</div>\n"
|
||||||
." <div class=\"yui-u\">\n"
|
." <div class=\"yui-u first\"> </div>\n"
|
||||||
." $input\n"
|
." <div class=\"yui-u\">\n"
|
||||||
." $desc\n"
|
." $input\n"
|
||||||
. ($errors? " <div>$errors</div>\n" : "")
|
." $desc\n"
|
||||||
." </div>\n"
|
. ($errors? " <div>$errors</div>\n" : "")
|
||||||
."</div>\n";
|
." </div>\n"
|
||||||
|
."</div>\n";
|
||||||
|
} else {
|
||||||
|
$output = "<div style=\"padding-bottom:10px\">\n"
|
||||||
|
." $input\n"
|
||||||
|
." $desc\n"
|
||||||
|
. ($errors? " <div>$errors</div>\n" : "")
|
||||||
|
."</div>\n";
|
||||||
|
}
|
||||||
|
} else if ($this->getOption('separateLine')) {
|
||||||
|
$output = "<div class=\"yui-$yuiGridType\" style=\"font-weight:bold\">\n"
|
||||||
|
." $label\n"
|
||||||
|
."</div>\n"
|
||||||
|
."<div>$input</div>\n"
|
||||||
|
."<div>$desc</div>\n"
|
||||||
|
. ($errors? "<div>$errors</div>\n" : "");
|
||||||
} else if ($this->getOption('continuous')) {
|
} else if ($this->getOption('continuous')) {
|
||||||
$output = "<div style=\"padding-bottom:10px\">\n"
|
$output = "<div style=\"padding-bottom:10px\">\n"
|
||||||
." <span class=\"formLabel\">$label</span> $input"
|
." <span class=\"formLabel\">$label</span> $input"
|
||||||
@ -131,6 +152,15 @@ class Monkeys_Form_Decorator_Composite extends Zend_Form_Decorator_Abstract
|
|||||||
}
|
}
|
||||||
|
|
||||||
return $output;
|
return $output;
|
||||||
|
|
||||||
|
// I believe we shouldn't use $placement (messes up the captcha, but I'm not sure about radios)
|
||||||
|
/*switch ($placement) {
|
||||||
|
case (self::PREPEND):
|
||||||
|
return $output . $separator . $content;
|
||||||
|
case (self::APPEND):
|
||||||
|
default:
|
||||||
|
return $content . $separator . $output;
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
142
libs/Monkeys/Form/Element/DateTime.php
Normal file
142
libs/Monkeys/Form/Element/DateTime.php
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @copyright Copyright (C) 2005-2009 Keyboard Monkeys Ltd. http://www.kb-m.com
|
||||||
|
* @license http://creativecommons.org/licenses/BSD/ BSD Licensese
|
||||||
|
* @author Keyboard Monkeys Ltd.
|
||||||
|
* @since CommunityID0.9
|
||||||
|
* @package CommunityID
|
||||||
|
* @packager Keyboard Monkeys
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Monkeys_Form_Element_DateTime extends Zend_Form_Element_Xhtml
|
||||||
|
{
|
||||||
|
public $helper = 'formDateTimeSelects';
|
||||||
|
|
||||||
|
public $options = array();
|
||||||
|
|
||||||
|
protected $_decorator;
|
||||||
|
|
||||||
|
public function __construct($spec, $options = array())
|
||||||
|
{
|
||||||
|
$options = array_merge($options, array('disableLoadDefaultDecorators' =>true));
|
||||||
|
parent::__construct($spec, $options);
|
||||||
|
|
||||||
|
$this->_decorator = new Monkeys_Form_Decorator_Composite();
|
||||||
|
$this->addDecorator($this->_decorator);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDecoratorOptions(array $options)
|
||||||
|
{
|
||||||
|
$this->_decorator->setOptions($options);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->options['showEmpty'] = true;
|
||||||
|
$this->options['startYear'] = 1900;
|
||||||
|
$this->options['endYear'] = (int) date("Y");
|
||||||
|
$this->options['reverseYears'] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setShowEmptyValues($value)
|
||||||
|
{
|
||||||
|
$this->options['showEmpty'] = (bool) $value;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setStartEndYear($start = null, $end = null)
|
||||||
|
{
|
||||||
|
if ($start)
|
||||||
|
{
|
||||||
|
$this->options['startYear'] = (int) $start;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($end)
|
||||||
|
{
|
||||||
|
$this->options['endYear'] = (int) $end;
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setReverseYears($value)
|
||||||
|
{
|
||||||
|
$this->options['reverseYears'] = (bool) $value;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isValid($value, $context = null)
|
||||||
|
{
|
||||||
|
$fieldName = $this->getName();
|
||||||
|
$auxiliaryFieldsNames = $this->getDayMonthYearTimeFieldNames($fieldName);
|
||||||
|
if (isset($context[$auxiliaryFieldsNames['day']]) && isset($context[$auxiliaryFieldsNames['month']])
|
||||||
|
&& isset($context[$auxiliaryFieldsNames['year']]) && isset($context[$auxiliaryFieldsNames['hour']])
|
||||||
|
&& isset($context[$auxiliaryFieldsNames['minutes']]) && isset($context[$auxiliaryFieldsNames['ampm']]))
|
||||||
|
{
|
||||||
|
if ($context[$auxiliaryFieldsNames['year']] == '-'
|
||||||
|
|| $context[$auxiliaryFieldsNames['month']] == '-'
|
||||||
|
|| $context[$auxiliaryFieldsNames['day']] == '-'
|
||||||
|
|| $context[$auxiliaryFieldsNames['hour']] == '-'
|
||||||
|
|| $context[$auxiliaryFieldsNames['minutes']] == '-'
|
||||||
|
|| $context[$auxiliaryFieldsNames['ampm']] == '-')
|
||||||
|
{
|
||||||
|
$value = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$hour = $context[$auxiliaryFieldsNames['hour']];
|
||||||
|
if ($context[$auxiliaryFieldsNames['ampm']] == 'pm') {
|
||||||
|
$hour += 12;
|
||||||
|
}
|
||||||
|
$value = str_pad($context[$auxiliaryFieldsNames['year']], 4, '0', STR_PAD_LEFT) . '-'
|
||||||
|
. str_pad($context[$auxiliaryFieldsNames['month']], 2, '0', STR_PAD_LEFT) . '-'
|
||||||
|
. str_pad($context[$auxiliaryFieldsNames['day']], 2, '0', STR_PAD_LEFT) . ' '
|
||||||
|
. str_pad($hour, 2, '0', STR_PAD_LEFT) . ':'
|
||||||
|
. str_pad($context[$auxiliaryFieldsNames['minutes']], 2, '0', STR_PAD_LEFT) . ':00';
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->setValue($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::isValid($value, $context);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getDayMonthYearTimeFieldNames($value)
|
||||||
|
{
|
||||||
|
if (empty($value) || !is_string($value)) {
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ret = array(
|
||||||
|
'day' => $value . '_day',
|
||||||
|
'month' => $value . '_month',
|
||||||
|
'year' => $value . '_year',
|
||||||
|
'hour' => $value . '_hour',
|
||||||
|
'minutes' => $value . '_minutes',
|
||||||
|
'ampm' => $value . '_ampm',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (strstr($value, '['))
|
||||||
|
{
|
||||||
|
$endPos = strlen($value) - 1;
|
||||||
|
if (']' != $value[$endPos]) {
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
$start = strrpos($value, '[') + 1;
|
||||||
|
$name = substr($value, $start, $endPos - $start);
|
||||||
|
$arrayName = substr($value, 0, $start-1);
|
||||||
|
$ret = array(
|
||||||
|
'day' => $arrayName . '[' . $name . '_day' . ']',
|
||||||
|
'month' => $arrayName . '[' . $name . '_month' . ']',
|
||||||
|
'year' => $arrayName . '[' . $name . '_year' . ']',
|
||||||
|
'hour' => $arrayName . '[' . $name . '_hour' . ']',
|
||||||
|
'minutes' => $arrayName . '[' . $name . '_minutes' . ']',
|
||||||
|
'ampm' => $arrayName . '[' . $name . '_ampm' . ']',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
}
|
@ -2,12 +2,22 @@
|
|||||||
|
|
||||||
class Monkeys_Form_Element_Password extends Zend_Form_Element_Password
|
class Monkeys_Form_Element_Password extends Zend_Form_Element_Password
|
||||||
{
|
{
|
||||||
|
private $_decorator;
|
||||||
|
|
||||||
public function __construct($spec, $options = array())
|
public function __construct($spec, $options = array())
|
||||||
{
|
{
|
||||||
$options = array_merge($options, array('disableLoadDefaultDecorators' =>true));
|
$options = array_merge($options, array('disableLoadDefaultDecorators' =>true));
|
||||||
parent::__construct($spec, $options);
|
parent::__construct($spec, $options);
|
||||||
|
|
||||||
$this->addDecorator(new Monkeys_Form_Decorator_Composite());
|
$this->_decorator = new Monkeys_Form_Decorator_Composite();
|
||||||
|
$this->addDecorator($this->_decorator);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDecoratorOptions(array $options)
|
||||||
|
{
|
||||||
|
$this->_decorator->setOptions($options);
|
||||||
|
|
||||||
|
return $this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
24
libs/Monkeys/Form/Element/Richtextarea.php
Normal file
24
libs/Monkeys/Form/Element/Richtextarea.php
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class Monkeys_Form_Element_Richtextarea extends Zend_Form_Element_Xhtml
|
||||||
|
{
|
||||||
|
public $helper = 'formRichtextarea';
|
||||||
|
|
||||||
|
private $_decorator;
|
||||||
|
|
||||||
|
public function __construct($spec, $options = array())
|
||||||
|
{
|
||||||
|
$options = array_merge($options, array('disableLoadDefaultDecorators' =>true));
|
||||||
|
parent::__construct($spec, $options);
|
||||||
|
|
||||||
|
$this->_decorator = new Monkeys_Form_Decorator_Composite();
|
||||||
|
$this->addDecorator($this->_decorator);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDecoratorOptions(array $options)
|
||||||
|
{
|
||||||
|
$this->_decorator->setOptions($options);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
23
libs/Monkeys/Form/Element/Select.php
Normal file
23
libs/Monkeys/Form/Element/Select.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class Monkeys_Form_Element_Select extends Zend_Form_Element_Select
|
||||||
|
{
|
||||||
|
private $_decorator;
|
||||||
|
|
||||||
|
public function __construct($spec, $options = array())
|
||||||
|
{
|
||||||
|
$options = array_merge($options, array('disableLoadDefaultDecorators' =>true));
|
||||||
|
parent::__construct($spec, $options);
|
||||||
|
|
||||||
|
$this->_decorator = new Monkeys_Form_Decorator_Composite();
|
||||||
|
$this->addDecorator($this->_decorator);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDecoratorOptions(array $options)
|
||||||
|
{
|
||||||
|
$this->_decorator->setOptions($options);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
246
libs/Monkeys/Form/Element/list-en1-semic-2.txt
Normal file
246
libs/Monkeys/Form/Element/list-en1-semic-2.txt
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
AFGHANISTAN;AF
|
||||||
|
ÅLAND ISLANDS;AX
|
||||||
|
ALBANIA;AL
|
||||||
|
ALGERIA;DZ
|
||||||
|
AMERICAN SAMOA;AS
|
||||||
|
ANDORRA;AD
|
||||||
|
ANGOLA;AO
|
||||||
|
ANGUILLA;AI
|
||||||
|
ANTARCTICA;AQ
|
||||||
|
ANTIGUA AND BARBUDA;AG
|
||||||
|
ARGENTINA;AR
|
||||||
|
ARMENIA;AM
|
||||||
|
ARUBA;AW
|
||||||
|
AUSTRALIA;AU
|
||||||
|
AUSTRIA;AT
|
||||||
|
AZERBAIJAN;AZ
|
||||||
|
BAHAMAS;BS
|
||||||
|
BAHRAIN;BH
|
||||||
|
BANGLADESH;BD
|
||||||
|
BARBADOS;BB
|
||||||
|
BELARUS;BY
|
||||||
|
BELGIUM;BE
|
||||||
|
BELIZE;BZ
|
||||||
|
BENIN;BJ
|
||||||
|
BERMUDA;BM
|
||||||
|
BHUTAN;BT
|
||||||
|
BOLIVIA;BO
|
||||||
|
BOSNIA AND HERZEGOVINA;BA
|
||||||
|
BOTSWANA;BW
|
||||||
|
BOUVET ISLAND;BV
|
||||||
|
BRAZIL;BR
|
||||||
|
BRITISH INDIAN OCEAN TERRITORY;IO
|
||||||
|
BRUNEI DARUSSALAM;BN
|
||||||
|
BULGARIA;BG
|
||||||
|
BURKINA FASO;BF
|
||||||
|
BURUNDI;BI
|
||||||
|
CAMBODIA;KH
|
||||||
|
CAMEROON;CM
|
||||||
|
CANADA;CA
|
||||||
|
CAPE VERDE;CV
|
||||||
|
CAYMAN ISLANDS;KY
|
||||||
|
CENTRAL AFRICAN REPUBLIC;CF
|
||||||
|
CHAD;TD
|
||||||
|
CHILE;CL
|
||||||
|
CHINA;CN
|
||||||
|
CHRISTMAS ISLAND;CX
|
||||||
|
COCOS (KEELING) ISLANDS;CC
|
||||||
|
COLOMBIA;CO
|
||||||
|
COMOROS;KM
|
||||||
|
CONGO;CG
|
||||||
|
CONGO, THE DEMOCRATIC REPUBLIC OF THE;CD
|
||||||
|
COOK ISLANDS;CK
|
||||||
|
COSTA RICA;CR
|
||||||
|
CÔTE D'IVOIRE;CI
|
||||||
|
CROATIA;HR
|
||||||
|
CUBA;CU
|
||||||
|
CYPRUS;CY
|
||||||
|
CZECH REPUBLIC;CZ
|
||||||
|
DENMARK;DK
|
||||||
|
DJIBOUTI;DJ
|
||||||
|
DOMINICA;DM
|
||||||
|
DOMINICAN REPUBLIC;DO
|
||||||
|
ECUADOR;EC
|
||||||
|
EGYPT;EG
|
||||||
|
EL SALVADOR;SV
|
||||||
|
EQUATORIAL GUINEA;GQ
|
||||||
|
ERITREA;ER
|
||||||
|
ESTONIA;EE
|
||||||
|
ETHIOPIA;ET
|
||||||
|
FALKLAND ISLANDS (MALVINAS);FK
|
||||||
|
FAROE ISLANDS;FO
|
||||||
|
FIJI;FJ
|
||||||
|
FINLAND;FI
|
||||||
|
FRANCE;FR
|
||||||
|
FRENCH GUIANA;GF
|
||||||
|
FRENCH POLYNESIA;PF
|
||||||
|
FRENCH SOUTHERN TERRITORIES;TF
|
||||||
|
GABON;GA
|
||||||
|
GAMBIA;GM
|
||||||
|
GEORGIA;GE
|
||||||
|
GERMANY;DE
|
||||||
|
GHANA;GH
|
||||||
|
GIBRALTAR;GI
|
||||||
|
GREECE;GR
|
||||||
|
GREENLAND;GL
|
||||||
|
GRENADA;GD
|
||||||
|
GUADELOUPE;GP
|
||||||
|
GUAM;GU
|
||||||
|
GUATEMALA;GT
|
||||||
|
GUERNSEY;GG
|
||||||
|
GUINEA;GN
|
||||||
|
GUINEA-BISSAU;GW
|
||||||
|
GUYANA;GY
|
||||||
|
HAITI;HT
|
||||||
|
HEARD ISLAND AND MCDONALD ISLANDS;HM
|
||||||
|
HOLY SEE (VATICAN CITY STATE);VA
|
||||||
|
HONDURAS;HN
|
||||||
|
HONG KONG;HK
|
||||||
|
HUNGARY;HU
|
||||||
|
ICELAND;IS
|
||||||
|
INDIA;IN
|
||||||
|
INDONESIA;ID
|
||||||
|
IRAN, ISLAMIC REPUBLIC OF;IR
|
||||||
|
IRAQ;IQ
|
||||||
|
IRELAND;IE
|
||||||
|
ISLE OF MAN;IM
|
||||||
|
ISRAEL;IL
|
||||||
|
ITALY;IT
|
||||||
|
JAMAICA;JM
|
||||||
|
JAPAN;JP
|
||||||
|
JERSEY;JE
|
||||||
|
JORDAN;JO
|
||||||
|
KAZAKHSTAN;KZ
|
||||||
|
KENYA;KE
|
||||||
|
KIRIBATI;KI
|
||||||
|
KOREA, DEMOCRATIC PEOPLE'S REPUBLIC OF;KP
|
||||||
|
KOREA, REPUBLIC OF;KR
|
||||||
|
KUWAIT;KW
|
||||||
|
KYRGYZSTAN;KG
|
||||||
|
LAO PEOPLE'S DEMOCRATIC REPUBLIC;LA
|
||||||
|
LATVIA;LV
|
||||||
|
LEBANON;LB
|
||||||
|
LESOTHO;LS
|
||||||
|
LIBERIA;LR
|
||||||
|
LIBYAN ARAB JAMAHIRIYA;LY
|
||||||
|
LIECHTENSTEIN;LI
|
||||||
|
LITHUANIA;LT
|
||||||
|
LUXEMBOURG;LU
|
||||||
|
MACAO;MO
|
||||||
|
MACEDONIA, THE FORMER YUGOSLAV REPUBLIC OF;MK
|
||||||
|
MADAGASCAR;MG
|
||||||
|
MALAWI;MW
|
||||||
|
MALAYSIA;MY
|
||||||
|
MALDIVES;MV
|
||||||
|
MALI;ML
|
||||||
|
MALTA;MT
|
||||||
|
MARSHALL ISLANDS;MH
|
||||||
|
MARTINIQUE;MQ
|
||||||
|
MAURITANIA;MR
|
||||||
|
MAURITIUS;MU
|
||||||
|
MAYOTTE;YT
|
||||||
|
MEXICO;MX
|
||||||
|
MICRONESIA, FEDERATED STATES OF;FM
|
||||||
|
MOLDOVA, REPUBLIC OF;MD
|
||||||
|
MONACO;MC
|
||||||
|
MONGOLIA;MN
|
||||||
|
MONTENEGRO;ME
|
||||||
|
MONTSERRAT;MS
|
||||||
|
MOROCCO;MA
|
||||||
|
MOZAMBIQUE;MZ
|
||||||
|
MYANMAR;MM
|
||||||
|
NAMIBIA;NA
|
||||||
|
NAURU;NR
|
||||||
|
NEPAL;NP
|
||||||
|
NETHERLANDS;NL
|
||||||
|
NETHERLANDS ANTILLES;AN
|
||||||
|
NEW CALEDONIA;NC
|
||||||
|
NEW ZEALAND;NZ
|
||||||
|
NICARAGUA;NI
|
||||||
|
NIGER;NE
|
||||||
|
NIGERIA;NG
|
||||||
|
NIUE;NU
|
||||||
|
NORFOLK ISLAND;NF
|
||||||
|
NORTHERN MARIANA ISLANDS;MP
|
||||||
|
NORWAY;NO
|
||||||
|
OMAN;OM
|
||||||
|
PAKISTAN;PK
|
||||||
|
PALAU;PW
|
||||||
|
PALESTINIAN TERRITORY, OCCUPIED;PS
|
||||||
|
PANAMA;PA
|
||||||
|
PAPUA NEW GUINEA;PG
|
||||||
|
PARAGUAY;PY
|
||||||
|
PERU;PE
|
||||||
|
PHILIPPINES;PH
|
||||||
|
PITCAIRN;PN
|
||||||
|
POLAND;PL
|
||||||
|
PORTUGAL;PT
|
||||||
|
PUERTO RICO;PR
|
||||||
|
QATAR;QA
|
||||||
|
REUNION;RE
|
||||||
|
ROMANIA;RO
|
||||||
|
RUSSIAN FEDERATION;RU
|
||||||
|
RWANDA;RW
|
||||||
|
SAINT BARTHÉLEMY;BL
|
||||||
|
SAINT HELENA;SH
|
||||||
|
SAINT KITTS AND NEVIS;KN
|
||||||
|
SAINT LUCIA;LC
|
||||||
|
SAINT MARTIN;MF
|
||||||
|
SAINT PIERRE AND MIQUELON;PM
|
||||||
|
SAINT VINCENT AND THE GRENADINES;VC
|
||||||
|
SAMOA;WS
|
||||||
|
SAN MARINO;SM
|
||||||
|
SAO TOME AND PRINCIPE;ST
|
||||||
|
SAUDI ARABIA;SA
|
||||||
|
SENEGAL;SN
|
||||||
|
SERBIA;RS
|
||||||
|
SEYCHELLES;SC
|
||||||
|
SIERRA LEONE;SL
|
||||||
|
SINGAPORE;SG
|
||||||
|
SLOVAKIA;SK
|
||||||
|
SLOVENIA;SI
|
||||||
|
SOLOMON ISLANDS;SB
|
||||||
|
SOMALIA;SO
|
||||||
|
SOUTH AFRICA;ZA
|
||||||
|
SOUTH GEORGIA AND THE SOUTH SANDWICH ISLANDS;GS
|
||||||
|
SPAIN;ES
|
||||||
|
SRI LANKA;LK
|
||||||
|
SUDAN;SD
|
||||||
|
SURINAME;SR
|
||||||
|
SVALBARD AND JAN MAYEN;SJ
|
||||||
|
SWAZILAND;SZ
|
||||||
|
SWEDEN;SE
|
||||||
|
SWITZERLAND;CH
|
||||||
|
SYRIAN ARAB REPUBLIC;SY
|
||||||
|
TAIWAN, PROVINCE OF CHINA;TW
|
||||||
|
TAJIKISTAN;TJ
|
||||||
|
TANZANIA, UNITED REPUBLIC OF;TZ
|
||||||
|
THAILAND;TH
|
||||||
|
TIMOR-LESTE;TL
|
||||||
|
TOGO;TG
|
||||||
|
TOKELAU;TK
|
||||||
|
TONGA;TO
|
||||||
|
TRINIDAD AND TOBAGO;TT
|
||||||
|
TUNISIA;TN
|
||||||
|
TURKEY;TR
|
||||||
|
TURKMENISTAN;TM
|
||||||
|
TURKS AND CAICOS ISLANDS;TC
|
||||||
|
TUVALU;TV
|
||||||
|
UGANDA;UG
|
||||||
|
UKRAINE;UA
|
||||||
|
UNITED ARAB EMIRATES;AE
|
||||||
|
UNITED KINGDOM;GB
|
||||||
|
UNITED STATES;US
|
||||||
|
UNITED STATES MINOR OUTLYING ISLANDS;UM
|
||||||
|
URUGUAY;UY
|
||||||
|
UZBEKISTAN;UZ
|
||||||
|
VANUATU;VU
|
||||||
|
VENEZUELA;VE
|
||||||
|
VIET NAM;VN
|
||||||
|
VIRGIN ISLANDS, BRITISH;VG
|
||||||
|
VIRGIN ISLANDS, U.S.;VI
|
||||||
|
WALLIS AND FUTUNA;WF
|
||||||
|
WESTERN SAHARA;EH
|
||||||
|
YEMEN;YE
|
||||||
|
ZAMBIA;ZM
|
||||||
|
ZIMBABWE;ZW
|
54
libs/Monkeys/Iterator.php
Normal file
54
libs/Monkeys/Iterator.php
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This iterator builds a collection filled with zeroes, except for the range it knows
|
||||||
|
* the paginator will query it for.
|
||||||
|
*/
|
||||||
|
class Monkeys_Iterator implements Iterator, Countable
|
||||||
|
{
|
||||||
|
private $_numItems;
|
||||||
|
private $_items;
|
||||||
|
private $_index = 0;
|
||||||
|
|
||||||
|
public function __construct($items, $numItems, $recordsPerPage, $page)
|
||||||
|
{
|
||||||
|
if ($items) {
|
||||||
|
$this->_items = array_fill(0, $numItems- 1, 0);
|
||||||
|
} else {
|
||||||
|
$this->_items = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
array_splice($this->_items, $recordsPerPage * ($page - 1), $recordsPerPage, $items);
|
||||||
|
$this->_numItems = $numItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function current()
|
||||||
|
{
|
||||||
|
return $this->_items[$this->_index];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function key()
|
||||||
|
{
|
||||||
|
return $this->_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function next()
|
||||||
|
{
|
||||||
|
$this->_index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rewind()
|
||||||
|
{
|
||||||
|
$this->_index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function valid()
|
||||||
|
{
|
||||||
|
return isset($this->_items[$this->_index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function count()
|
||||||
|
{
|
||||||
|
return $this->_numItems;
|
||||||
|
}
|
||||||
|
}
|
100
libs/Monkeys/Ldap.php
Normal file
100
libs/Monkeys/Ldap.php
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class Monkeys_Ldap
|
||||||
|
{
|
||||||
|
private static $_instance;
|
||||||
|
|
||||||
|
private $_ldapConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ldap link identifier
|
||||||
|
*/
|
||||||
|
private $_dp;
|
||||||
|
|
||||||
|
private function __construct()
|
||||||
|
{
|
||||||
|
$this->_ldapConfig = Zend_Registry::get('config')->ldap;
|
||||||
|
|
||||||
|
if (!$this->_dp= @ldap_connect($this->_ldapConfig->host)) {
|
||||||
|
throw new Exception('Could not connect to LDAP server');
|
||||||
|
}
|
||||||
|
ldap_set_option($this->_dp, LDAP_OPT_PROTOCOL_VERSION, 3);
|
||||||
|
if (!@ldap_bind($this->_dp, $this->_ldapConfig->username, $this->_ldapConfig->password)) {
|
||||||
|
throw new Exception('Could not bind to LDAP server: ' . ldap_error($this->_dp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getInstance()
|
||||||
|
{
|
||||||
|
if (!isset(self::$_instance)) {
|
||||||
|
self::$_instance = new Monkeys_Ldap();
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function get($dn)
|
||||||
|
{
|
||||||
|
if (!$resultId = @ldap_search($this->_dp, $dn, "(&(objectClass=*))")) {
|
||||||
|
throw new Exception('Could not retrieve record to LDAP server (1): ' . ldap_error($this->_dp));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$result = @ldap_get_entries($this->_dp, $resultId)) {
|
||||||
|
throw new Exception('Could not retrieve record to LDAP server (2): ' . ldap_error($this->_dp));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* lastname (sn) is required for the "inetOrgPerson" schema
|
||||||
|
*/
|
||||||
|
public function add(Users_Model_User $user)
|
||||||
|
{
|
||||||
|
$dn = 'cn=' . $user->username . ',' . $this->_ldapConfig->baseDn;
|
||||||
|
$info = array(
|
||||||
|
'cn' => $user->username,
|
||||||
|
'givenName' => $user->firstname,
|
||||||
|
'sn' => $user->lastname,
|
||||||
|
'mail' => $user->email,
|
||||||
|
'userPassword' => $user->password,
|
||||||
|
'objectclass' => 'inetOrgPerson',
|
||||||
|
);
|
||||||
|
if (!@ldap_add($this->_dp, $dn, $info) && ldap_error($this->_dp) != 'Success') {
|
||||||
|
throw new Exception('Could not add record to LDAP server: ' . ldap_error($this->_dp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function modify(User $user)
|
||||||
|
{
|
||||||
|
$dn = 'cn=' . $user->username . ',' . $this->_ldapConfig->baseDn;
|
||||||
|
$info = array(
|
||||||
|
'cn' => $user->username,
|
||||||
|
'givenName' => $user->firstname,
|
||||||
|
'sn' => $user->lastname,
|
||||||
|
'mail' => $user->email,
|
||||||
|
'objectclass' => 'inetOrgPerson',
|
||||||
|
);
|
||||||
|
if (!@ldap_modify($this->_dp, $dn, $info) && ldap_error($this->_dp) != 'Success') {
|
||||||
|
throw new Exception('Could not modify record in LDAP server: ' . ldap_error($this->_dp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function modifyUsername(User $user, $oldUsername)
|
||||||
|
{
|
||||||
|
$dn = 'cn=' . $oldUsername . ',' . $this->_ldapConfig->baseDn;
|
||||||
|
$newRdn = 'cn=' . $user->username;
|
||||||
|
if (!@ldap_rename($this->_dp, $dn, $newRdn, $this->_ldapConfig->baseDn, true) && ldap_error($this->_dp) != 'Success') {
|
||||||
|
throw new Exception('Could not modify username in LDAP server: ' . ldap_error($this->_dp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete($username)
|
||||||
|
{
|
||||||
|
$dn = "cn=$username," . $this->_ldapConfig->baseDn;
|
||||||
|
if (!@ldap_delete($this->_dp, $dn) && ldap_error($this->_dp) != 'Success') {
|
||||||
|
throw new Exception('Could not delete record from LDAP server: ' . ldap_error($this->_dp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
libs/Monkeys/Lib.php
Normal file
21
libs/Monkeys/Lib.php
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class Monkeys_Lib
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Converts the HTML BR tag into plain-text linebreaks
|
||||||
|
*
|
||||||
|
* Taken from comments on the nl2br function PHP's online manual.
|
||||||
|
* "Since nl2br doesn't remove the line breaks when adding in the <br /> tags, it is necessary to strip those off before you convert all of the tags, otherwise you will get double spacing"
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @static
|
||||||
|
* @param string $str
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
static function br2nl($str)
|
||||||
|
{
|
||||||
|
$str = preg_replace("/(\r\n|\n|\r)/", "", $str);
|
||||||
|
return preg_replace('=<br */?>=i', "\n", $str);
|
||||||
|
}
|
||||||
|
}
|
89
libs/Monkeys/Lucene.php
Normal file
89
libs/Monkeys/Lucene.php
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @copyright Copyright (C) 2005-2009 Keyboard Monkeys Ltd. http://www.kb-m.com
|
||||||
|
* @license http://creativecommons.org/licenses/BSD/ BSD Licensese
|
||||||
|
* @author Keyboard Monkeys Ltd.
|
||||||
|
* @since Textroller 0.9
|
||||||
|
* @package TextRoller
|
||||||
|
* @packager Keyboard Monkeys
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Monkeys_Lucene
|
||||||
|
{
|
||||||
|
const LUCENE_DIR = '/lucene';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Zend_Search_Lucene_exception
|
||||||
|
*/
|
||||||
|
public static function getIndex()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$index = Zend_Search_Lucene::open(APP_DIR . self::LUCENE_DIR);
|
||||||
|
} catch (Zend_Search_Lucene_Exception $e) {
|
||||||
|
$index = Zend_Search_Lucene::create(APP_DIR . self::LUCENE_DIR);
|
||||||
|
Zend_Registry::get('logger')->log('Created Lucene index file', Zend_Log::INFO);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Zend_Search_Lucene_exception
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function indexArticle(Model_Blog $blog, Zend_Db_Table_Rowset $tagsSet, $isNew)
|
||||||
|
{
|
||||||
|
if ($blog->draft || !$blog->hasBeenPublished()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$tags = array();
|
||||||
|
foreach ($tagsSet as $tag) {
|
||||||
|
$tags[] = $tag->tag;
|
||||||
|
}
|
||||||
|
$tags = implode(' ', $tags);
|
||||||
|
|
||||||
|
$index = self::getIndex();
|
||||||
|
|
||||||
|
if (!$isNew) {
|
||||||
|
$existingDocIds = $index->termDocs(new Zend_Search_Lucene_Index_Term($blog->id, 'blog_id'));
|
||||||
|
if ($existingDocIds) {
|
||||||
|
$index->delete($existingDocIds[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// I won't be using Zend_Search_Lucene_Document_HTML 'cause articles are not full HTML documents
|
||||||
|
$doc = new Zend_Search_Lucene_Document();
|
||||||
|
|
||||||
|
$doc->addField(Zend_Search_Lucene_Field::Keyword('blog_id', $blog->id));
|
||||||
|
|
||||||
|
$doc->addField(Zend_Search_Lucene_Field::Text('title', $blog->title, 'utf-8'));
|
||||||
|
$doc->addField(Zend_Search_Lucene_Field::Text('excerpt', $blog->excerpt, 'utf-8'));
|
||||||
|
$doc->addField(Zend_Search_Lucene_Field::Unstored('tag', $tags, 'utf-8'));
|
||||||
|
$doc->addField(Zend_Search_Lucene_Field::Unstored('contents', $blog->getContentWithoutTags(), 'utf-8'));
|
||||||
|
$index->addDocument($doc);
|
||||||
|
$index->commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function unIndexArticle(Blog $blog)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$index = self::getIndex();
|
||||||
|
} catch (Zend_Search_Lucene_Exception $e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$existingDocIds = $index->termDocs(new Zend_Search_Lucene_Index_Term($blog->id, 'blog_id'));
|
||||||
|
|
||||||
|
if ($existingDocIds) {
|
||||||
|
$index->delete($existingDocIds[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function optimizeIndex()
|
||||||
|
{
|
||||||
|
$index = self::getIndex();
|
||||||
|
$index->optimize();
|
||||||
|
}
|
||||||
|
}
|
@ -13,7 +13,7 @@ class Monkeys_OpenId_Provider_Storage_Database extends Zend_OpenId_Provider_Stor
|
|||||||
{
|
{
|
||||||
public function addAssociation($handle, $macFunc, $secret, $expires)
|
public function addAssociation($handle, $macFunc, $secret, $expires)
|
||||||
{
|
{
|
||||||
$associations = new Associations();
|
$associations = new Model_Associations();
|
||||||
$association = $associations->createRow();
|
$association = $associations->createRow();
|
||||||
$association->handle = $handle;
|
$association->handle = $handle;
|
||||||
$association->macfunc = $macFunc;
|
$association->macfunc = $macFunc;
|
||||||
@ -26,7 +26,7 @@ class Monkeys_OpenId_Provider_Storage_Database extends Zend_OpenId_Provider_Stor
|
|||||||
|
|
||||||
public function getAssociation($handle, &$macFunc, &$secret, &$expires)
|
public function getAssociation($handle, &$macFunc, &$secret, &$expires)
|
||||||
{
|
{
|
||||||
$associations = new Associations();
|
$associations = new Model_Associations();
|
||||||
$association = $associations->getAssociationGivenHandle($handle);
|
$association = $associations->getAssociationGivenHandle($handle);
|
||||||
if (!$association) {
|
if (!$association) {
|
||||||
return false;
|
return false;
|
||||||
@ -52,7 +52,7 @@ class Monkeys_OpenId_Provider_Storage_Database extends Zend_OpenId_Provider_Stor
|
|||||||
|
|
||||||
public function hasUser($id)
|
public function hasUser($id)
|
||||||
{
|
{
|
||||||
$users = new Users();
|
$users = new Users_Model_Users();
|
||||||
$user = $users->getUserWithOpenId($id);
|
$user = $users->getUserWithOpenId($id);
|
||||||
|
|
||||||
return $user? true : false;
|
return $user? true : false;
|
||||||
@ -86,10 +86,10 @@ class Monkeys_OpenId_Provider_Storage_Database extends Zend_OpenId_Provider_Stor
|
|||||||
*/
|
*/
|
||||||
public function getTrustedSites($id)
|
public function getTrustedSites($id)
|
||||||
{
|
{
|
||||||
$users = new Users();
|
$users = new Users_Model_Users();
|
||||||
$user = $users->getUserWithOpenId($id);
|
$user = $users->getUserWithOpenId($id);
|
||||||
|
|
||||||
$sites = new Sites();
|
$sites = new Model_Sites();
|
||||||
|
|
||||||
$trustedSites = array();
|
$trustedSites = array();
|
||||||
foreach ($sites->getTrusted($user) as $site) {
|
foreach ($sites->getTrusted($user) as $site) {
|
||||||
@ -109,10 +109,10 @@ class Monkeys_OpenId_Provider_Storage_Database extends Zend_OpenId_Provider_Stor
|
|||||||
*/
|
*/
|
||||||
public function addSite($id, $site, $trusted)
|
public function addSite($id, $site, $trusted)
|
||||||
{
|
{
|
||||||
$users = new Users();
|
$users = new Users_Model_Users();
|
||||||
$user = $users->getUserWithOpenId($id);
|
$user = $users->getUserWithOpenId($id);
|
||||||
|
|
||||||
$sites = new Sites();
|
$sites = new Model_Sites();
|
||||||
$sites->deleteForUserSite($user, $site);
|
$sites->deleteForUserSite($user, $site);
|
||||||
|
|
||||||
if (!is_null($trusted)) {
|
if (!is_null($trusted)) {
|
||||||
|
34
libs/Monkeys/Validate/Username.php
Normal file
34
libs/Monkeys/Validate/Username.php
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @copyright Copyright (C) 2005-2009 Keyboard Monkeys Ltd. http://www.kb-m.com
|
||||||
|
* @license http://creativecommons.org/licenses/BSD/ BSD License
|
||||||
|
* @author Keyboard Monkey Ltd
|
||||||
|
* @since CommunityID 0.9
|
||||||
|
* @package CommunityID
|
||||||
|
* @packager Keyboard Monkeys
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates URL element syntax to avoid encoding issues, according to rfc 1738, section 2.2
|
||||||
|
*/
|
||||||
|
class Monkeys_Validate_Username extends Zend_Validate_Abstract
|
||||||
|
{
|
||||||
|
const BAD = 'bad';
|
||||||
|
|
||||||
|
protected $_messageTemplates = array(
|
||||||
|
self::BAD => 'Username can only contain US-ASCII alphanumeric characters, plus any of the symbols $-_.+!*\'(), and "'
|
||||||
|
);
|
||||||
|
|
||||||
|
public function isValid($value, $context = null)
|
||||||
|
{
|
||||||
|
$this->_setValue($value);
|
||||||
|
|
||||||
|
if (preg_match('/^[A-Za-z\$-_.\+!\*\'\(\)",]+$/', $value)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
$this->_error(self::BAD);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -15,7 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
class Monkeys_View_Helper_FormDateSelects extends Zend_View_Helper_FormElement
|
class Monkeys_View_Helper_FormDateSelects extends Zend_View_Helper_FormElement
|
||||||
{
|
{
|
||||||
private $_months = array(
|
protected $_months = array(
|
||||||
1 => 'January',
|
1 => 'January',
|
||||||
2 => 'February',
|
2 => 'February',
|
||||||
3 => 'March',
|
3 => 'March',
|
||||||
@ -38,7 +38,7 @@ class Monkeys_View_Helper_FormDateSelects extends Zend_View_Helper_FormElement
|
|||||||
protected $_translator;
|
protected $_translator;
|
||||||
|
|
||||||
public function formDateSelects($name, $value = null, $attribs = null,
|
public function formDateSelects($name, $value = null, $attribs = null,
|
||||||
$options = null, $listsep = "<br />\n")
|
$options = null, $listsep = "<br />\n")
|
||||||
{
|
{
|
||||||
$info = $this->_getInfo($name, $value, $attribs, $options, $listsep);
|
$info = $this->_getInfo($name, $value, $attribs, $options, $listsep);
|
||||||
extract($info); // name, id, value, attribs, options, listsep, disable
|
extract($info); // name, id, value, attribs, options, listsep, disable
|
||||||
@ -262,7 +262,7 @@ class Monkeys_View_Helper_FormDateSelects extends Zend_View_Helper_FormElement
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function _translationsHolder()
|
protected function _translationsHolder()
|
||||||
{
|
{
|
||||||
translate('January');
|
translate('January');
|
||||||
translate('February');
|
translate('February');
|
||||||
|
254
libs/Monkeys/View/Helper/FormDateTimeSelects.php
Normal file
254
libs/Monkeys/View/Helper/FormDateTimeSelects.php
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @copyright Copyright (C) 2005-2009 Keyboard Monkeys Ltd. http://www.kb-m.com
|
||||||
|
* @license http://creativecommons.org/licenses/BSD/ BSD Licensese
|
||||||
|
* @author Keyboard Monkeys Ltd.
|
||||||
|
* @since Textroller 0.9
|
||||||
|
* @package TextRoller
|
||||||
|
* @packager Keyboard Monkeys
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Monkeys_View_Helper_FormDateTimeSelects extends Monkeys_View_Helper_FormDateSelects
|
||||||
|
{
|
||||||
|
public function formDateTimeSelects($name, $value = null, $attribs = null,
|
||||||
|
$options = null, $listsep = "<br />\n")
|
||||||
|
{
|
||||||
|
$info = $this->_getInfo($name, $value, $attribs, $options, $listsep);
|
||||||
|
extract($info); // name, id, value, attribs, options, listsep, disable
|
||||||
|
|
||||||
|
// now start building the XHTML.
|
||||||
|
$disabled = '';
|
||||||
|
if (true === $disable) {
|
||||||
|
$disabled = ' disabled="disabled"';
|
||||||
|
}
|
||||||
|
|
||||||
|
$elementNamesArray = $this->getDayMonthYearTimeFieldNames($name);
|
||||||
|
$valueDay = $valueMonth = $valueYear = $valueHour = $valueMinutes = $valueAmPm = null;
|
||||||
|
|
||||||
|
if ($value !== null)
|
||||||
|
{
|
||||||
|
$valueExploded = explode(' ', $value);
|
||||||
|
|
||||||
|
$dateValueExploded = explode('-', $valueExploded[0]);
|
||||||
|
if (!isset($dateValueExploded[2])) {
|
||||||
|
$value = null;
|
||||||
|
} else {
|
||||||
|
$valueDay = (int) $dateValueExploded[2];
|
||||||
|
$valueMonth = (int) $dateValueExploded[1];
|
||||||
|
$valueYear = (int) $dateValueExploded[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
$timeValueExploded = explode(':', $valueExploded[1]);
|
||||||
|
$valueHour = $timeValueExploded[0];
|
||||||
|
if ($valueHour > 12) {
|
||||||
|
$valueHour -= 12;
|
||||||
|
$valueAmPm = 'pm';
|
||||||
|
} elseif ($valueHour == 0) {
|
||||||
|
$valueHour = 12;
|
||||||
|
$valueAmPm = 'am';
|
||||||
|
} else {
|
||||||
|
$valueAmPm = 'am';
|
||||||
|
}
|
||||||
|
$valueMinutes = (int) $timeValueExploded[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the surrounding day element first.
|
||||||
|
$xhtml = '<select '
|
||||||
|
. ' name="' . $this->view->escape($elementNamesArray['day']) . '"'
|
||||||
|
. ' id="' . $this->view->escape($id . '_day') . '"'
|
||||||
|
. $disabled
|
||||||
|
. $this->_htmlAttribs($attribs)
|
||||||
|
. ">\n ";
|
||||||
|
|
||||||
|
// build the list of options
|
||||||
|
$list = array();
|
||||||
|
if ($options['showEmpty'])
|
||||||
|
{
|
||||||
|
$list[] = '<option value="-"> </option>';
|
||||||
|
}
|
||||||
|
for ($i = 1; $i <= 31; $i++)
|
||||||
|
{
|
||||||
|
$list[] = '<option'
|
||||||
|
. ' value="' . $i . '"'
|
||||||
|
. ($valueDay === $i ? ' selected="selected"' : '')
|
||||||
|
. '>' . $i . '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the options to the xhtml and close the select
|
||||||
|
$xhtml .= implode("\n ", $list) . "\n</select>";
|
||||||
|
|
||||||
|
// Build the month next
|
||||||
|
$xhtml .= ' <select '
|
||||||
|
. ' name="' . $this->view->escape($elementNamesArray['month']) . '"'
|
||||||
|
. ' id="' . $this->view->escape($id . '_month') . '"'
|
||||||
|
. $disabled
|
||||||
|
. $this->_htmlAttribs($attribs)
|
||||||
|
. ">\n ";
|
||||||
|
|
||||||
|
// build the list of options
|
||||||
|
$list = array();
|
||||||
|
if ($options['showEmpty'])
|
||||||
|
{
|
||||||
|
$list[] = '<option value="-"> </option>';
|
||||||
|
}
|
||||||
|
for ($i = 1; $i <= 12; $i++)
|
||||||
|
{
|
||||||
|
$list[] = '<option'
|
||||||
|
. ' value="' . $i . '"'
|
||||||
|
. ($valueMonth === $i ? ' selected="selected"' : '')
|
||||||
|
. '>' . $this->_translateValue($this->_months[$i]) . '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the options to the xhtml and close the select
|
||||||
|
$xhtml .= implode("\n ", $list) . "\n</select>";
|
||||||
|
|
||||||
|
|
||||||
|
// Build the years next
|
||||||
|
$xhtml .= ' <select '
|
||||||
|
. ' name="' . $this->view->escape($elementNamesArray['year']) . '"'
|
||||||
|
. ' id="' . $this->view->escape($id . '_year') . '"'
|
||||||
|
. $disabled
|
||||||
|
. $this->_htmlAttribs($attribs)
|
||||||
|
. ">\n ";
|
||||||
|
|
||||||
|
// build the list of options
|
||||||
|
$list = array();
|
||||||
|
if ($options['showEmpty'])
|
||||||
|
{
|
||||||
|
$list[] = '<option value="-"> </option>';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ($options['reverseYears'])
|
||||||
|
{
|
||||||
|
for ($i = $options['endYear']; $i >= $options['startYear']; $i--)
|
||||||
|
{
|
||||||
|
$list[] = '<option '
|
||||||
|
. ' value="' . $i . '"'
|
||||||
|
. ($valueYear === $i ? ' selected="selected"' : '')
|
||||||
|
. '>' . $i . '</option>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for ($i = $options['startYear']; $i >= $options['endYear']; $i++)
|
||||||
|
{
|
||||||
|
$list[] = '<option '
|
||||||
|
. ' value="' . $i . '"'
|
||||||
|
. ($valueYear === $i ? ' selected="selected"' : '')
|
||||||
|
. '>' . $i . '</option>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the options to the xhtml and close the select
|
||||||
|
$xhtml .= implode("\n ", $list) . "\n</select>";
|
||||||
|
|
||||||
|
// Build the hours next
|
||||||
|
$xhtml .= ' <select '
|
||||||
|
. ' name="' . $this->view->escape($elementNamesArray['hour']) . '"'
|
||||||
|
. ' id="' . $this->view->escape($id . '_hour') . '"'
|
||||||
|
. $disabled
|
||||||
|
. $this->_htmlAttribs($attribs)
|
||||||
|
. ">\n ";
|
||||||
|
|
||||||
|
$list = array();
|
||||||
|
if ($options['showEmpty'])
|
||||||
|
{
|
||||||
|
$list[] = '<option value="-"> </option>';
|
||||||
|
}
|
||||||
|
for ($i = 1; $i <= 12; $i++)
|
||||||
|
{
|
||||||
|
$list[] = '<option'
|
||||||
|
. ' value="' . $i . '"'
|
||||||
|
. ($valueHour === $i ? ' selected="selected"' : '')
|
||||||
|
. '>' . sprintf('%02u', $i) . '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the options to the xhtml and close the select
|
||||||
|
$xhtml .= implode("\n ", $list) . "\n</select>";
|
||||||
|
|
||||||
|
// Build the minutes next
|
||||||
|
$xhtml .= '<select '
|
||||||
|
. ' name="' . $this->view->escape($elementNamesArray['minutes']) . '"'
|
||||||
|
. ' id="' . $this->view->escape($id . '_minutes') . '"'
|
||||||
|
. $disabled
|
||||||
|
. $this->_htmlAttribs($attribs)
|
||||||
|
. ">\n ";
|
||||||
|
|
||||||
|
$list = array();
|
||||||
|
if ($options['showEmpty'])
|
||||||
|
{
|
||||||
|
$list[] = '<option value="-"> </option>';
|
||||||
|
}
|
||||||
|
for ($i = 0; $i <= 59; $i++)
|
||||||
|
{
|
||||||
|
$list[] = '<option'
|
||||||
|
. ' value="' . $i . '"'
|
||||||
|
. ($valueMinutes === $i ? ' selected="selected"' : '')
|
||||||
|
. '>' . sprintf('%02u', $i) . '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the options to the xhtml and close the select
|
||||||
|
$xhtml .= implode("\n ", $list) . "\n</select>";
|
||||||
|
|
||||||
|
|
||||||
|
// Build the ampm next
|
||||||
|
$xhtml .= '<select '
|
||||||
|
. ' name="' . $this->view->escape($elementNamesArray['ampm']) . '"'
|
||||||
|
. ' id="' . $this->view->escape($id . '_ampm') . '"'
|
||||||
|
. $disabled
|
||||||
|
. $this->_htmlAttribs($attribs)
|
||||||
|
. ">\n ";
|
||||||
|
|
||||||
|
$list = array();
|
||||||
|
if ($options['showEmpty'])
|
||||||
|
{
|
||||||
|
$list[] = '<option value="-"> </option>';
|
||||||
|
}
|
||||||
|
$list[] = '<option value="am" ' . ($valueAmPm == 'am' ? 'selected="selected"' : '') . '>am';
|
||||||
|
$list[] = '<option value="pm" ' . ($valueAmPm == 'pm' ? 'selected="selected"' : '') . '>pm';
|
||||||
|
|
||||||
|
// add the options to the xhtml and close the select
|
||||||
|
$xhtml .= implode("\n ", $list) . "\n</select>";
|
||||||
|
|
||||||
|
return $xhtml;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getDayMonthYearTimeFieldNames($value)
|
||||||
|
{
|
||||||
|
if (empty($value) || !is_string($value)) {
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ret = array(
|
||||||
|
'day' => $value . '_day',
|
||||||
|
'month' => $value . '_month',
|
||||||
|
'year' => $value . '_year',
|
||||||
|
'hour' => $value . '_hour',
|
||||||
|
'minutes' => $value . '_minutes',
|
||||||
|
'ampm' => $value . '_ampm',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (strstr($value, '['))
|
||||||
|
{
|
||||||
|
$endPos = strlen($value) - 1;
|
||||||
|
if (']' != $value[$endPos]) {
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
$start = strrpos($value, '[') + 1;
|
||||||
|
$name = substr($value, $start, $endPos - $start);
|
||||||
|
$arrayName = substr($value, 0, $start-1);
|
||||||
|
$ret = array(
|
||||||
|
'day' => $arrayName . '[' . $name . '_day' . ']',
|
||||||
|
'month' => $arrayName . '[' . $name . '_month' . ']',
|
||||||
|
'year' => $arrayName . '[' . $name . '_year' . ']',
|
||||||
|
'hour' => $arrayName . '[' . $name . '_hour' . ']',
|
||||||
|
'minutes' => $arrayName . '[' . $name . '_minutes' . ']',
|
||||||
|
'ampm' => $arrayName . '[' . $name . '_ampm' . ']',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
}
|
25
libs/Monkeys/View/Helper/FormRichtextarea.php
Normal file
25
libs/Monkeys/View/Helper/FormRichtextarea.php
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require_once WEB_DIR . '/fckeditor/fckeditor.php';
|
||||||
|
|
||||||
|
class Monkeys_View_Helper_FormRichtextarea extends Zend_View_Helper_FormElement
|
||||||
|
{
|
||||||
|
public function formRichtextarea($name, $value = null, $attribs = null, $options = null, $listSep = null)
|
||||||
|
{
|
||||||
|
$info = $this->_getInfo($name, $value, $attribs);
|
||||||
|
extract($info); // name, value, attribs, options, listsep, disable
|
||||||
|
|
||||||
|
$fck = new FCKEditor($this->view->escape($name));
|
||||||
|
$fck->BasePath = $this->view->base . '/fckeditor/';
|
||||||
|
$fck->Value = $value;
|
||||||
|
if (isset($attribs['width'])) {
|
||||||
|
$fck->Width = $attribs['width'];
|
||||||
|
} else {
|
||||||
|
$fck->Width = '890';
|
||||||
|
}
|
||||||
|
$fck->Height = '600';
|
||||||
|
$fck->Config['CustomConfigurationsPath'] = '../../javascript/fck_custom_config.js';
|
||||||
|
$fck->ToolbarSet = 'MonkeysToolbar';
|
||||||
|
return $fck->CreateHtml();
|
||||||
|
}
|
||||||
|
}
|
@ -1,14 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
|
||||||
* @copyright Copyright (C) 2005-2009 Keyboard Monkeys Ltd. http://www.kb-m.com
|
|
||||||
* @license http://creativecommons.org/licenses/BSD/ BSD License
|
|
||||||
* @author Keyboard Monkey Ltd
|
|
||||||
* @since CommunityID 0.9
|
|
||||||
* @package CommunityID
|
|
||||||
* @packager Keyboard Monkeys
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Monkeys_View_Helper_GetBase
|
class Monkeys_View_Helper_GetBase
|
||||||
{
|
{
|
||||||
public function getBase()
|
public function getBase()
|
||||||
|
1637
libs/Monkeys/tests/sampletext.txt
Normal file
1637
libs/Monkeys/tests/sampletext.txt
Normal file
File diff suppressed because it is too large
Load Diff
@ -175626,6 +175626,7 @@ scytopetalaceous
|
|||||||
Scytopetalum
|
Scytopetalum
|
||||||
sdeath
|
sdeath
|
||||||
sdrucciola
|
sdrucciola
|
||||||
|
se
|
||||||
sea
|
sea
|
||||||
seabeach
|
seabeach
|
||||||
seabeard
|
seabeard
|
||||||
|
132
libs/Zend/Amf/Adobe/Auth.php
Executable file
132
libs/Zend/Amf/Adobe/Auth.php
Executable file
@ -0,0 +1,132 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Zend Framework
|
||||||
|
*
|
||||||
|
* LICENSE
|
||||||
|
*
|
||||||
|
* This source file is subject to the new BSD license that is bundled
|
||||||
|
* with this package in the file LICENSE.txt.
|
||||||
|
* It is also available through the world-wide-web at this URL:
|
||||||
|
* http://framework.zend.com/license/new-bsd
|
||||||
|
* If you did not receive a copy of the license and are unable to
|
||||||
|
* obtain it through the world-wide-web, please send an email
|
||||||
|
* to license@zend.com so we can send you a copy immediately.
|
||||||
|
*
|
||||||
|
* @category Zend
|
||||||
|
* @package Zend_Amf
|
||||||
|
* @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||||||
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Zend_Amf_Auth_Abstract */
|
||||||
|
require_once 'Zend/Amf/Auth/Abstract.php';
|
||||||
|
|
||||||
|
/** Zend_Acl */
|
||||||
|
require_once 'Zend/Acl.php';
|
||||||
|
|
||||||
|
/** Zend_Auth_Result */
|
||||||
|
require_once 'Zend/Auth/Result.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class implements authentication against XML file with roles for Flex Builder.
|
||||||
|
*
|
||||||
|
* @package Zend_Amf
|
||||||
|
* @subpackage Adobe
|
||||||
|
* @copyright Copyright (c) 2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||||||
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||||
|
*/
|
||||||
|
class Zend_Amf_Adobe_Auth extends Zend_Amf_Auth_Abstract
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ACL for authorization
|
||||||
|
*
|
||||||
|
* @var Zend_Acl
|
||||||
|
*/
|
||||||
|
protected $_acl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Username/password array
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $_users = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create auth adapter
|
||||||
|
*
|
||||||
|
* @param string $rolefile File containing XML with users and roles
|
||||||
|
*/
|
||||||
|
public function __construct($rolefile)
|
||||||
|
{
|
||||||
|
$this->_acl = new Zend_Acl();
|
||||||
|
$xml = simplexml_load_file($rolefile);
|
||||||
|
/*
|
||||||
|
Roles file format:
|
||||||
|
<roles>
|
||||||
|
<role id=”admin”>
|
||||||
|
<user name=”user1” password=”pwd”/>
|
||||||
|
</role>
|
||||||
|
<role id=”hr”>
|
||||||
|
<user name=”user2” password=”pwd2”/>
|
||||||
|
</role>
|
||||||
|
</roles>
|
||||||
|
*/
|
||||||
|
foreach($xml->role as $role) {
|
||||||
|
$this->_acl->addRole(new Zend_Acl_Role((string)$role["id"]));
|
||||||
|
foreach($role->user as $user) {
|
||||||
|
$this->_users[(string)$user["name"]] = array("password" => (string)$user["password"],
|
||||||
|
"role" => (string)$role["id"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get ACL with roles from XML file
|
||||||
|
*
|
||||||
|
* @return Zend_Acl
|
||||||
|
*/
|
||||||
|
public function getAcl()
|
||||||
|
{
|
||||||
|
return $this->_acl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform authentication
|
||||||
|
*
|
||||||
|
* @throws Zend_Auth_Adapter_Exception
|
||||||
|
* @return Zend_Auth_Result
|
||||||
|
* @see Zend_Auth_Adapter_Interface#authenticate()
|
||||||
|
*/
|
||||||
|
public function authenticate()
|
||||||
|
{
|
||||||
|
if (empty($this->_username) ||
|
||||||
|
empty($this->_password)) {
|
||||||
|
/**
|
||||||
|
* @see Zend_Auth_Adapter_Exception
|
||||||
|
*/
|
||||||
|
require_once 'Zend/Auth/Adapter/Exception.php';
|
||||||
|
throw new Zend_Auth_Adapter_Exception('Username/password should be set');
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!isset($this->_users[$this->_username])) {
|
||||||
|
return new Zend_Auth_Result(Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND,
|
||||||
|
null,
|
||||||
|
array('Username not found')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = $this->_users[$this->_username];
|
||||||
|
if($user["password"] != $this->_password) {
|
||||||
|
return new Zend_Auth_Result(Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID,
|
||||||
|
null,
|
||||||
|
array('Authentication failed')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$id = new stdClass();
|
||||||
|
$id->role = $user["role"];
|
||||||
|
$id->name = $this->_username;
|
||||||
|
return new Zend_Auth_Result(Zend_Auth_Result::SUCCESS, $id);
|
||||||
|
}
|
||||||
|
}
|
102
libs/Zend/Amf/Adobe/DbInspector.php
Executable file
102
libs/Zend/Amf/Adobe/DbInspector.php
Executable file
@ -0,0 +1,102 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Zend Framework
|
||||||
|
*
|
||||||
|
* LICENSE
|
||||||
|
*
|
||||||
|
* This source file is subject to the new BSD license that is bundled
|
||||||
|
* with this package in the file LICENSE.txt.
|
||||||
|
* It is also available through the world-wide-web at this URL:
|
||||||
|
* http://framework.zend.com/license/new-bsd
|
||||||
|
* If you did not receive a copy of the license and are unable to
|
||||||
|
* obtain it through the world-wide-web, please send an email
|
||||||
|
* to license@zend.com so we can send you a copy immediately.
|
||||||
|
*
|
||||||
|
* @category Zend
|
||||||
|
* @package Zend_Amf
|
||||||
|
* @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||||||
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class implements authentication against XML file with roles for Flex Builder.
|
||||||
|
*
|
||||||
|
* @package Zend_Amf
|
||||||
|
* @subpackage Adobe
|
||||||
|
* @copyright Copyright (c) 2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||||||
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||||
|
*/
|
||||||
|
class Zend_Amf_Adobe_DbInspector
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connect to the database
|
||||||
|
*
|
||||||
|
* @param string $dbType Database adapter type for Zend_Db
|
||||||
|
* @param array|object $dbDescription Adapter-specific connection settings
|
||||||
|
* @return Zend_Db_Adapter_Abstract
|
||||||
|
* @see Zend_Db::factory()
|
||||||
|
*/
|
||||||
|
protected function _connect($dbType, $dbDescription)
|
||||||
|
{
|
||||||
|
if(is_object($dbDescription)) {
|
||||||
|
$dbDescription = get_object_vars($dbDescription);
|
||||||
|
}
|
||||||
|
return Zend_Db::factory($dbType, $dbDescription);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describe database object.
|
||||||
|
*
|
||||||
|
* Usage example:
|
||||||
|
* $inspector->describeTable('Pdo_Mysql',
|
||||||
|
* array(
|
||||||
|
* 'host' => '127.0.0.1',
|
||||||
|
* 'username' => 'webuser',
|
||||||
|
* 'password' => 'xxxxxxxx',
|
||||||
|
* 'dbname' => 'test'
|
||||||
|
* ),
|
||||||
|
* 'mytable'
|
||||||
|
* );
|
||||||
|
*
|
||||||
|
* @param string $dbType Database adapter type for Zend_Db
|
||||||
|
* @param array|object $dbDescription Adapter-specific connection settings
|
||||||
|
* @param string $tableName Table name
|
||||||
|
* @return array Table description
|
||||||
|
* @see Zend_Db::describeTable()
|
||||||
|
* @see Zend_Db::factory()
|
||||||
|
*/
|
||||||
|
public function describeTable($dbType, $dbDescription, $tableName)
|
||||||
|
{
|
||||||
|
$db = $this->_connect($dbType, $dbDescription);
|
||||||
|
return $db->describeTable($tableName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test database connection
|
||||||
|
*
|
||||||
|
* @param string $dbType Database adapter type for Zend_Db
|
||||||
|
* @param array|object $dbDescription Adapter-specific connection settings
|
||||||
|
* @return bool
|
||||||
|
* @see Zend_Db::factory()
|
||||||
|
*/
|
||||||
|
public function connect($dbType, $dbDescription)
|
||||||
|
{
|
||||||
|
$db = $this->_connect($dbType, $dbDescription);
|
||||||
|
$db->listTables();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the list of database tables
|
||||||
|
*
|
||||||
|
* @param string $dbType Database adapter type for Zend_Db
|
||||||
|
* @param array|object $dbDescription Adapter-specific connection settings
|
||||||
|
* @return array List of the tables
|
||||||
|
*/
|
||||||
|
public function getTables($dbType, $dbDescription)
|
||||||
|
{
|
||||||
|
$db = $this->_connect($dbType, $dbDescription);
|
||||||
|
return $db->listTables();
|
||||||
|
}
|
||||||
|
}
|
308
libs/Zend/Amf/Adobe/Introspector.php
Executable file
308
libs/Zend/Amf/Adobe/Introspector.php
Executable file
@ -0,0 +1,308 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Zend Framework
|
||||||
|
*
|
||||||
|
* LICENSE
|
||||||
|
*
|
||||||
|
* This source file is subject to the new BSD license that is bundled
|
||||||
|
* with this package in the file LICENSE.txt.
|
||||||
|
* It is also available through the world-wide-web at this URL:
|
||||||
|
* http://framework.zend.com/license/new-bsd
|
||||||
|
* If you did not receive a copy of the license and are unable to
|
||||||
|
* obtain it through the world-wide-web, please send an email
|
||||||
|
* to license@zend.com so we can send you a copy immediately.
|
||||||
|
*
|
||||||
|
* @category Zend
|
||||||
|
* @package Zend_Amf
|
||||||
|
* @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||||||
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Zend_Amf_Parse_TypeLoader */
|
||||||
|
require_once 'Zend/Amf/Parse/TypeLoader.php';
|
||||||
|
|
||||||
|
/** Zend_Reflection_Class */
|
||||||
|
require_once 'Zend/Reflection/Class.php';
|
||||||
|
|
||||||
|
/** Zend_Server_Reflection */
|
||||||
|
require_once 'Zend/Server/Reflection.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class implements a service for generating AMF service descriptions as XML.
|
||||||
|
*
|
||||||
|
* @package Zend_Amf
|
||||||
|
* @subpackage Adobe
|
||||||
|
* @copyright Copyright (c) 2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||||||
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||||
|
*/
|
||||||
|
class Zend_Amf_Adobe_Introspector
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Options used:
|
||||||
|
* - server: instance of Zend_Amf_Server to use
|
||||||
|
* - directories: directories where class files may be looked up
|
||||||
|
*
|
||||||
|
* @var array Introspector options
|
||||||
|
*/
|
||||||
|
protected $_options;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var DOMElement DOM element to store types
|
||||||
|
*/
|
||||||
|
protected $_types;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array Map of the known types
|
||||||
|
*/
|
||||||
|
protected $_typesMap = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var DOMDocument XML document to store data
|
||||||
|
*/
|
||||||
|
protected $_xml;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->_xml = new DOMDocument('1.0', 'utf-8');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create XML definition on an AMF service class
|
||||||
|
*
|
||||||
|
* @param string $serviceClass Service class name
|
||||||
|
* @param array $options invocation options
|
||||||
|
* @return string XML with service class introspection
|
||||||
|
*/
|
||||||
|
public function introspect($serviceClass, $options = array())
|
||||||
|
{
|
||||||
|
$this->_options = $options;
|
||||||
|
|
||||||
|
if (strpbrk($serviceClass, '\\/<>')) {
|
||||||
|
return $this->_returnError('Invalid service name');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transform com.foo.Bar into com_foo_Bar
|
||||||
|
$serviceClass = str_replace('.' , '_', $serviceClass);
|
||||||
|
|
||||||
|
// Introspect!
|
||||||
|
if (!class_exists($serviceClass)) {
|
||||||
|
require_once 'Zend/Loader.php';
|
||||||
|
Zend_Loader::loadClass($serviceClass, $this->_getServicePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
$serv = $this->_xml->createElement('service-description');
|
||||||
|
$serv->setAttribute('xmlns', 'http://ns.adobe.com/flex/service-description/2008');
|
||||||
|
|
||||||
|
$this->_types = $this->_xml->createElement('types');
|
||||||
|
$this->_ops = $this->_xml->createElement('operations');
|
||||||
|
|
||||||
|
$r = Zend_Server_Reflection::reflectClass($serviceClass);
|
||||||
|
$this->_addService($r, $this->_ops);
|
||||||
|
|
||||||
|
$serv->appendChild($this->_types);
|
||||||
|
$serv->appendChild($this->_ops);
|
||||||
|
$this->_xml->appendChild($serv);
|
||||||
|
|
||||||
|
return $this->_xml->saveXML();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authentication handler
|
||||||
|
*
|
||||||
|
* @param Zend_Acl $acl
|
||||||
|
* @return unknown_type
|
||||||
|
*/
|
||||||
|
public function initAcl(Zend_Acl $acl)
|
||||||
|
{
|
||||||
|
return false; // we do not need auth for this class
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate map of public class attributes
|
||||||
|
*
|
||||||
|
* @param string $typename type name
|
||||||
|
* @param DOMElement $typexml target XML element
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function _addClassAttributes($typename, DOMElement $typexml)
|
||||||
|
{
|
||||||
|
// Do not try to autoload here because _phpTypeToAS should
|
||||||
|
// have already attempted to load this class
|
||||||
|
if (!class_exists($typename, false)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$rc = new Zend_Reflection_Class($typename);
|
||||||
|
foreach ($rc->getProperties() as $prop) {
|
||||||
|
if (!$prop->isPublic()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$propxml = $this->_xml->createElement('property');
|
||||||
|
$propxml->setAttribute('name', $prop->getName());
|
||||||
|
|
||||||
|
$type = $this->_registerType($this->_getPropertyType($prop));
|
||||||
|
$propxml->setAttribute('type', $type);
|
||||||
|
|
||||||
|
$typexml->appendChild($propxml);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build XML service description from reflection class
|
||||||
|
*
|
||||||
|
* @param Zend_Server_Reflection_Class $refclass
|
||||||
|
* @param DOMElement $target target XML element
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function _addService(Zend_Server_Reflection_Class $refclass, DOMElement $target)
|
||||||
|
{
|
||||||
|
foreach ($refclass->getMethods() as $method) {
|
||||||
|
if (!$method->isPublic()
|
||||||
|
|| $method->isConstructor()
|
||||||
|
|| ('__' == substr($method->name, 0, 2))
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($method->getPrototypes() as $proto) {
|
||||||
|
$op = $this->_xml->createElement('operation');
|
||||||
|
$op->setAttribute('name', $method->getName());
|
||||||
|
|
||||||
|
$rettype = $this->_registerType($proto->getReturnType());
|
||||||
|
$op->setAttribute('returnType', $rettype);
|
||||||
|
|
||||||
|
foreach ($proto->getParameters() as $param) {
|
||||||
|
$arg = $this->_xml->createElement('argument');
|
||||||
|
$arg->setAttribute('name', $param->getName());
|
||||||
|
|
||||||
|
$type = $param->getType();
|
||||||
|
if ($type == 'mixed' && ($pclass = $param->getClass())) {
|
||||||
|
$type = $pclass->getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
$ptype = $this->_registerType($type);
|
||||||
|
$arg->setAttribute('type', $ptype);
|
||||||
|
|
||||||
|
$op->appendChild($arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
$target->appendChild($op);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract type of the property from DocBlock
|
||||||
|
*
|
||||||
|
* @param Zend_Reflection_Property $prop reflection property object
|
||||||
|
* @return string Property type
|
||||||
|
*/
|
||||||
|
protected function _getPropertyType(Zend_Reflection_Property $prop)
|
||||||
|
{
|
||||||
|
$docBlock = $prop->getDocComment();
|
||||||
|
|
||||||
|
if (!$docBlock) {
|
||||||
|
return 'Unknown';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$docBlock->hasTag('var')) {
|
||||||
|
return 'Unknown';
|
||||||
|
}
|
||||||
|
|
||||||
|
$tag = $docBlock->getTag('var');
|
||||||
|
return trim($tag->getDescription());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the array of service directories
|
||||||
|
*
|
||||||
|
* @return array Service class directories
|
||||||
|
*/
|
||||||
|
protected function _getServicePath()
|
||||||
|
{
|
||||||
|
if (isset($this->_options['server'])) {
|
||||||
|
return $this->_options['server']->getDirectory();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($this->_options['directories'])) {
|
||||||
|
return $this->_options['directories'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map from PHP type name to AS type name
|
||||||
|
*
|
||||||
|
* @param string $typename PHP type name
|
||||||
|
* @return string AS type name
|
||||||
|
*/
|
||||||
|
protected function _phpTypeToAS($typename)
|
||||||
|
{
|
||||||
|
if (class_exists($typename)) {
|
||||||
|
$vars = get_class_vars($typename);
|
||||||
|
|
||||||
|
if (isset($vars['_explicitType'])) {
|
||||||
|
return $vars['_explicitType'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false !== ($asname = Zend_Amf_Parse_TypeLoader::getMappedClassName($typename))) {
|
||||||
|
return $asname;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $typename;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register new type on the system
|
||||||
|
*
|
||||||
|
* @param string $typename type name
|
||||||
|
* @return string New type name
|
||||||
|
*/
|
||||||
|
protected function _registerType($typename)
|
||||||
|
{
|
||||||
|
// Known type - return its AS name
|
||||||
|
if (isset($this->_typesMap[$typename])) {
|
||||||
|
return $this->_typesMap[$typename];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Standard types
|
||||||
|
if (in_array($typename, array('void', 'null', 'mixed', 'unknown_type'))) {
|
||||||
|
return 'Unknown';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_array($typename, array('int', 'integer', 'bool', 'boolean', 'float', 'string', 'object', 'Unknown', 'stdClass', 'array'))) {
|
||||||
|
return $typename;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve and store AS name
|
||||||
|
$asTypeName = $this->_phpTypeToAS($typename);
|
||||||
|
$this->_typesMap[$typename] = $asTypeName;
|
||||||
|
|
||||||
|
// Create element for the name
|
||||||
|
$typeEl = $this->_xml->createElement('type');
|
||||||
|
$typeEl->setAttribute('name', $asTypeName);
|
||||||
|
$this->_addClassAttributes($typename, $typeEl);
|
||||||
|
$this->_types->appendChild($typeEl);
|
||||||
|
|
||||||
|
return $asTypeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return error with error message
|
||||||
|
*
|
||||||
|
* @param string $msg Error message
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function _returnError($msg)
|
||||||
|
{
|
||||||
|
return 'ERROR: $msg';
|
||||||
|
}
|
||||||
|
}
|
41
libs/Zend/Amf/Auth/Abstract.php
Executable file
41
libs/Zend/Amf/Auth/Abstract.php
Executable file
@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Zend Framework
|
||||||
|
*
|
||||||
|
* LICENSE
|
||||||
|
*
|
||||||
|
* This source file is subject to the new BSD license that is bundled
|
||||||
|
* with this package in the file LICENSE.txt.
|
||||||
|
* It is also available through the world-wide-web at this URL:
|
||||||
|
* http://framework.zend.com/license/new-bsd
|
||||||
|
* If you did not receive a copy of the license and are unable to
|
||||||
|
* obtain it through the world-wide-web, please send an email
|
||||||
|
* to license@zend.com so we can send you a copy immediately.
|
||||||
|
*
|
||||||
|
* @category Zend
|
||||||
|
* @package Zend_Amf
|
||||||
|
* @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||||||
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Zend_Auth_Adapter_Interface */
|
||||||
|
require_once 'Zend/Auth/Adapter/Interface.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base abstract class for AMF authentication implementation
|
||||||
|
*
|
||||||
|
* @package Zend_Amf
|
||||||
|
* @subpackage Auth
|
||||||
|
* @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||||||
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||||
|
*/
|
||||||
|
abstract class Zend_Amf_Auth_Abstract implements Zend_Auth_Adapter_Interface
|
||||||
|
{
|
||||||
|
protected $_username;
|
||||||
|
protected $_password;
|
||||||
|
|
||||||
|
public function setCredentials($username, $password) {
|
||||||
|
$this->_username = $username;
|
||||||
|
$this->_password = $password;
|
||||||
|
}
|
||||||
|
}
|
@ -14,7 +14,7 @@
|
|||||||
*
|
*
|
||||||
* @category Zend
|
* @category Zend
|
||||||
* @package Zend_Amf
|
* @package Zend_Amf
|
||||||
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
|
* @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||||||
* @license http://framework.zend.com/license/new-bsd New BSD License
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -23,7 +23,7 @@
|
|||||||
* deserialization to detect the AMF marker and encoding types.
|
* deserialization to detect the AMF marker and encoding types.
|
||||||
*
|
*
|
||||||
* @package Zend_Amf
|
* @package Zend_Amf
|
||||||
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
|
* @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||||||
* @license http://framework.zend.com/license/new-bsd New BSD License
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||||
*/
|
*/
|
||||||
final class Zend_Amf_Constants
|
final class Zend_Amf_Constants
|
||||||
@ -67,6 +67,8 @@ final class Zend_Amf_Constants
|
|||||||
const ET_EXTERNAL = 0x01;
|
const ET_EXTERNAL = 0x01;
|
||||||
const ET_DYNAMIC = 0x02;
|
const ET_DYNAMIC = 0x02;
|
||||||
const ET_PROXY = 0x03;
|
const ET_PROXY = 0x03;
|
||||||
|
|
||||||
|
const FMS_OBJECT_ENCODING = 0x01;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Special content length value that indicates "unknown" content length
|
* Special content length value that indicates "unknown" content length
|
||||||
@ -76,4 +78,9 @@ final class Zend_Amf_Constants
|
|||||||
const URL_APPEND_HEADER = 'AppendToGatewayUrl';
|
const URL_APPEND_HEADER = 'AppendToGatewayUrl';
|
||||||
const RESULT_METHOD = '/onResult';
|
const RESULT_METHOD = '/onResult';
|
||||||
const STATUS_METHOD = '/onStatus';
|
const STATUS_METHOD = '/onStatus';
|
||||||
|
const CREDENTIALS_HEADER = 'Credentials';
|
||||||
|
const PERSISTENT_HEADER = 'RequestPersistentHeader';
|
||||||
|
const DESCRIBE_HEADER = 'DescribeService';
|
||||||
|
|
||||||
|
const GUEST_ROLE = 'anonymous';
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
*
|
*
|
||||||
* @category Zend
|
* @category Zend
|
||||||
* @package Zend_Amf
|
* @package Zend_Amf
|
||||||
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
|
* @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||||||
* @license http://framework.zend.com/license/new-bsd New BSD License
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -25,7 +25,7 @@ require_once 'Zend/Exception.php';
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @package Zend_Amf
|
* @package Zend_Amf
|
||||||
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
|
* @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||||||
* @license http://framework.zend.com/license/new-bsd New BSD License
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||||
*/
|
*/
|
||||||
class Zend_Amf_Exception extends Zend_Exception
|
class Zend_Amf_Exception extends Zend_Exception
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
* @category Zend
|
* @category Zend
|
||||||
* @package Zend_Amf
|
* @package Zend_Amf
|
||||||
* @subpackage Parse_Amf0
|
* @subpackage Parse_Amf0
|
||||||
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
|
* @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||||||
* @license http://framework.zend.com/license/new-bsd New BSD License
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ require_once 'Zend/Amf/Parse/Deserializer.php';
|
|||||||
* @todo Class could be implmented as Factory Class with each data type it's own class
|
* @todo Class could be implmented as Factory Class with each data type it's own class
|
||||||
* @package Zend_Amf
|
* @package Zend_Amf
|
||||||
* @subpackage Parse_Amf0
|
* @subpackage Parse_Amf0
|
||||||
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
|
* @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||||||
* @license http://framework.zend.com/license/new-bsd New BSD License
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||||
*/
|
*/
|
||||||
class Zend_Amf_Parse_Amf0_Deserializer extends Zend_Amf_Parse_Deserializer
|
class Zend_Amf_Parse_Amf0_Deserializer extends Zend_Amf_Parse_Deserializer
|
||||||
@ -47,13 +47,6 @@ class Zend_Amf_Parse_Amf0_Deserializer extends Zend_Amf_Parse_Deserializer
|
|||||||
*/
|
*/
|
||||||
protected $_objectEncoding = Zend_Amf_Constants::AMF0_OBJECT_ENCODING;
|
protected $_objectEncoding = Zend_Amf_Constants::AMF0_OBJECT_ENCODING;
|
||||||
|
|
||||||
/**
|
|
||||||
* refrence to AMF3 deserializer
|
|
||||||
*
|
|
||||||
* @var Zend_Amf_Parse_Amf3_Deserializer
|
|
||||||
*/
|
|
||||||
protected $_deserializer = null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read AMF markers and dispatch for deserialization
|
* Read AMF markers and dispatch for deserialization
|
||||||
*
|
*
|
||||||
@ -68,7 +61,7 @@ class Zend_Amf_Parse_Amf0_Deserializer extends Zend_Amf_Parse_Deserializer
|
|||||||
*/
|
*/
|
||||||
public function readTypeMarker($typeMarker = null)
|
public function readTypeMarker($typeMarker = null)
|
||||||
{
|
{
|
||||||
if (is_null($typeMarker)) {
|
if ($typeMarker === null) {
|
||||||
$typeMarker = $this->_stream->readByte();
|
$typeMarker = $this->_stream->readByte();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,7 +145,7 @@ class Zend_Amf_Parse_Amf0_Deserializer extends Zend_Amf_Parse_Deserializer
|
|||||||
*/
|
*/
|
||||||
public function readObject($object = null)
|
public function readObject($object = null)
|
||||||
{
|
{
|
||||||
if (is_null($object)) {
|
if ($object === null) {
|
||||||
$object = array();
|
$object = array();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,7 +254,7 @@ class Zend_Amf_Parse_Amf0_Deserializer extends Zend_Amf_Parse_Deserializer
|
|||||||
* Commonly used for Value Objects on the server
|
* Commonly used for Value Objects on the server
|
||||||
*
|
*
|
||||||
* @todo implement Typed Class mapping
|
* @todo implement Typed Class mapping
|
||||||
* @return object
|
* @return object|array
|
||||||
* @throws Zend_Amf_Exception if unable to load type
|
* @throws Zend_Amf_Exception if unable to load type
|
||||||
*/
|
*/
|
||||||
public function readTypedObject()
|
public function readTypedObject()
|
||||||
@ -277,7 +270,9 @@ class Zend_Amf_Parse_Amf0_Deserializer extends Zend_Amf_Parse_Deserializer
|
|||||||
$returnObject->$key = $value;
|
$returnObject->$key = $value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if($returnObject instanceof Zend_Amf_Value_Messaging_ArrayCollection) {
|
||||||
|
$returnObject = get_object_vars($returnObject);
|
||||||
|
}
|
||||||
return $returnObject;
|
return $returnObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,7 +284,8 @@ class Zend_Amf_Parse_Amf0_Deserializer extends Zend_Amf_Parse_Deserializer
|
|||||||
*/
|
*/
|
||||||
public function readAmf3TypeMarker()
|
public function readAmf3TypeMarker()
|
||||||
{
|
{
|
||||||
$deserializer = $this->getDeserializer();
|
require_once 'Zend/Amf/Parse/Amf3/Deserializer.php';
|
||||||
|
$deserializer = new Zend_Amf_Parse_Amf3_Deserializer($this->_stream);
|
||||||
$this->_objectEncoding = Zend_Amf_Constants::AMF3_OBJECT_ENCODING;
|
$this->_objectEncoding = Zend_Amf_Constants::AMF3_OBJECT_ENCODING;
|
||||||
return $deserializer->readTypeMarker();
|
return $deserializer->readTypeMarker();
|
||||||
}
|
}
|
||||||
@ -304,18 +300,4 @@ class Zend_Amf_Parse_Amf0_Deserializer extends Zend_Amf_Parse_Deserializer
|
|||||||
{
|
{
|
||||||
return $this->_objectEncoding;
|
return $this->_objectEncoding;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get deserializer
|
|
||||||
*
|
|
||||||
* @return Zend_Amf_Parse_Amf3_Deserializer
|
|
||||||
*/
|
|
||||||
public function getDeserializer()
|
|
||||||
{
|
|
||||||
if (null === $this->_deserializer) {
|
|
||||||
require_once 'Zend/Amf/Parse/Amf3/Deserializer.php';
|
|
||||||
$this->_deserializer = new Zend_Amf_Parse_Amf3_Deserializer($this->_stream);
|
|
||||||
}
|
|
||||||
return $this->_deserializer;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
* @category Zend
|
* @category Zend
|
||||||
* @package Zend_Amf
|
* @package Zend_Amf
|
||||||
* @subpackage Parse_Amf0
|
* @subpackage Parse_Amf0
|
||||||
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
|
* @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||||||
* @license http://framework.zend.com/license/new-bsd New BSD License
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ require_once 'Zend/Amf/Parse/Serializer.php';
|
|||||||
* @uses Zend_Amf_Parse_Serializer
|
* @uses Zend_Amf_Parse_Serializer
|
||||||
* @package Zend_Amf
|
* @package Zend_Amf
|
||||||
* @subpackage Parse_Amf0
|
* @subpackage Parse_Amf0
|
||||||
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
|
* @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||||||
* @license http://framework.zend.com/license/new-bsd New BSD License
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||||
*/
|
*/
|
||||||
class Zend_Amf_Parse_Amf0_Serializer extends Zend_Amf_Parse_Serializer
|
class Zend_Amf_Parse_Amf0_Serializer extends Zend_Amf_Parse_Serializer
|
||||||
@ -37,6 +37,12 @@ class Zend_Amf_Parse_Amf0_Serializer extends Zend_Amf_Parse_Serializer
|
|||||||
* @var string Name of the class to be returned
|
* @var string Name of the class to be returned
|
||||||
*/
|
*/
|
||||||
protected $_className = '';
|
protected $_className = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array of reference objects
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $_referenceObjects = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine type and serialize accordingly
|
* Determine type and serialize accordingly
|
||||||
@ -53,50 +59,60 @@ class Zend_Amf_Parse_Amf0_Serializer extends Zend_Amf_Parse_Serializer
|
|||||||
public function writeTypeMarker($data, $markerType = null)
|
public function writeTypeMarker($data, $markerType = null)
|
||||||
{
|
{
|
||||||
if (null !== $markerType) {
|
if (null !== $markerType) {
|
||||||
// Write the Type Marker to denote the following action script data type
|
//try to refrence the given object
|
||||||
$this->_stream->writeByte($markerType);
|
if( !$this->writeObjectReference($data, $markerType) ) {
|
||||||
switch($markerType) {
|
|
||||||
case Zend_Amf_Constants::AMF0_NUMBER:
|
// Write the Type Marker to denote the following action script data type
|
||||||
$this->_stream->writeDouble($data);
|
$this->_stream->writeByte($markerType);
|
||||||
break;
|
switch($markerType) {
|
||||||
case Zend_Amf_Constants::AMF0_BOOLEAN:
|
case Zend_Amf_Constants::AMF0_NUMBER:
|
||||||
$this->_stream->writeByte($data);
|
$this->_stream->writeDouble($data);
|
||||||
break;
|
break;
|
||||||
case Zend_Amf_Constants::AMF0_STRING:
|
case Zend_Amf_Constants::AMF0_BOOLEAN:
|
||||||
$this->_stream->writeUTF($data);
|
$this->_stream->writeByte($data);
|
||||||
break;
|
break;
|
||||||
case Zend_Amf_Constants::AMF0_OBJECT:
|
case Zend_Amf_Constants::AMF0_STRING:
|
||||||
$this->writeObject($data);
|
$this->_stream->writeUTF($data);
|
||||||
break;
|
break;
|
||||||
case Zend_Amf_Constants::AMF0_NULL:
|
case Zend_Amf_Constants::AMF0_OBJECT:
|
||||||
break;
|
$this->writeObject($data);
|
||||||
case Zend_Amf_Constants::AMF0_MIXEDARRAY:
|
break;
|
||||||
// Write length of numeric keys as zero.
|
case Zend_Amf_Constants::AMF0_NULL:
|
||||||
$this->_stream->writeLong(0);
|
break;
|
||||||
$this->writeObject($data);
|
case Zend_Amf_Constants::AMF0_REFERENCE:
|
||||||
break;
|
$this->_stream->writeInt($data);
|
||||||
case Zend_Amf_Constants::AMF0_ARRAY:
|
break;
|
||||||
$this->writeArray($data);
|
case Zend_Amf_Constants::AMF0_MIXEDARRAY:
|
||||||
break;
|
// Write length of numeric keys as zero.
|
||||||
case Zend_Amf_Constants::AMF0_DATE:
|
$this->_stream->writeLong(0);
|
||||||
$this->writeDate($data);
|
$this->writeObject($data);
|
||||||
break;
|
break;
|
||||||
case Zend_Amf_Constants::AMF0_LONGSTRING:
|
case Zend_Amf_Constants::AMF0_ARRAY:
|
||||||
$this->_stream->writeLongUTF($data);
|
$this->writeArray($data);
|
||||||
break;
|
break;
|
||||||
case Zend_Amf_Constants::AMF0_TYPEDOBJECT:
|
case Zend_Amf_Constants::AMF0_DATE:
|
||||||
$this->writeTypedObject($data);
|
$this->writeDate($data);
|
||||||
break;
|
break;
|
||||||
case Zend_Amf_Constants::AMF0_AMF3:
|
case Zend_Amf_Constants::AMF0_LONGSTRING:
|
||||||
$this->writeAmf3TypeMarker($data);
|
$this->_stream->writeLongUTF($data);
|
||||||
break;
|
break;
|
||||||
default:
|
case Zend_Amf_Constants::AMF0_TYPEDOBJECT:
|
||||||
require_once 'Zend/Amf/Exception.php';
|
$this->writeTypedObject($data);
|
||||||
throw new Zend_Amf_Exception("Unknown Type Marker: " . $markerType);
|
break;
|
||||||
|
case Zend_Amf_Constants::AMF0_AMF3:
|
||||||
|
$this->writeAmf3TypeMarker($data);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
require_once 'Zend/Amf/Exception.php';
|
||||||
|
throw new Zend_Amf_Exception("Unknown Type Marker: " . $markerType);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if(is_resource($data)) {
|
||||||
|
$data = Zend_Amf_Parse_TypeLoader::handleResource($data);
|
||||||
|
}
|
||||||
switch (true) {
|
switch (true) {
|
||||||
case (is_int($data) || is_float($data)):
|
case (is_int($data) || is_float($data)):
|
||||||
$markerType = Zend_Amf_Constants::AMF0_NUMBER;
|
$markerType = Zend_Amf_Constants::AMF0_NUMBER;
|
||||||
break;
|
break;
|
||||||
case (is_bool($data)):
|
case (is_bool($data)):
|
||||||
@ -128,12 +144,19 @@ class Zend_Amf_Parse_Amf0_Serializer extends Zend_Amf_Parse_Serializer
|
|||||||
$markerType = Zend_Amf_Constants::AMF0_NULL;
|
$markerType = Zend_Amf_Constants::AMF0_NULL;
|
||||||
break;
|
break;
|
||||||
case (is_array($data)):
|
case (is_array($data)):
|
||||||
// check if it is a mixed typed array
|
// check if it is an associative array
|
||||||
|
$i = 0;
|
||||||
foreach (array_keys($data) as $key) {
|
foreach (array_keys($data) as $key) {
|
||||||
if (!is_numeric($key)) {
|
// check if it contains non-integer keys
|
||||||
$markerType = Zend_Amf_Constants::AMF0_MIXEDARRAY;
|
if (!is_numeric($key) || intval($key) != $key) {
|
||||||
break;
|
$markerType = Zend_Amf_Constants::AMF0_OBJECT;
|
||||||
}
|
break;
|
||||||
|
// check if it is a sparse indexed array
|
||||||
|
} else if ($key != $i) {
|
||||||
|
$markerType = Zend_Amf_Constants::AMF0_MIXEDARRAY;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$i++;
|
||||||
}
|
}
|
||||||
// Dealing with a standard numeric array
|
// Dealing with a standard numeric array
|
||||||
if(!$markerType){
|
if(!$markerType){
|
||||||
@ -150,6 +173,33 @@ class Zend_Amf_Parse_Amf0_Serializer extends Zend_Amf_Parse_Serializer
|
|||||||
}
|
}
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the given object is in the reference table, write the reference if it exists,
|
||||||
|
* otherwise add the object to the reference table
|
||||||
|
*
|
||||||
|
* @param mixed $object object to check for reference
|
||||||
|
* @param $markerType AMF type of the object to write
|
||||||
|
* @return Boolean true, if the reference was written, false otherwise
|
||||||
|
*/
|
||||||
|
protected function writeObjectReference($object, $markerType){
|
||||||
|
if( $markerType == Zend_Amf_Constants::AMF0_OBJECT ||
|
||||||
|
$markerType == Zend_Amf_Constants::AMF0_MIXEDARRAY ||
|
||||||
|
$markerType == Zend_Amf_Constants::AMF0_ARRAY ||
|
||||||
|
$markerType == Zend_Amf_Constants::AMF0_TYPEDOBJECT ) {
|
||||||
|
|
||||||
|
$ref = array_search($object, $this->_referenceObjects,true);
|
||||||
|
//handle object reference
|
||||||
|
if($ref !== false){
|
||||||
|
$this->writeTypeMarker($ref,Zend_Amf_Constants::AMF0_REFERENCE);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->_referenceObjects[] = $object;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write a php array with string or mixed keys.
|
* Write a php array with string or mixed keys.
|
||||||
@ -161,6 +211,8 @@ class Zend_Amf_Parse_Amf0_Serializer extends Zend_Amf_Parse_Serializer
|
|||||||
{
|
{
|
||||||
// Loop each element and write the name of the property.
|
// Loop each element and write the name of the property.
|
||||||
foreach ($object as $key => $value) {
|
foreach ($object as $key => $value) {
|
||||||
|
// skip variables starting with an _ provate transient
|
||||||
|
if( $key[0] == "_") continue;
|
||||||
$this->_stream->writeUTF($key);
|
$this->_stream->writeUTF($key);
|
||||||
$this->writeTypeMarker($value);
|
$this->writeTypeMarker($value);
|
||||||
}
|
}
|
||||||
@ -270,14 +322,18 @@ class Zend_Amf_Parse_Amf0_Serializer extends Zend_Amf_Parse_Serializer
|
|||||||
// Check to see if the user has defined an explicit Action Script type.
|
// Check to see if the user has defined an explicit Action Script type.
|
||||||
case isset($object->_explicitType):
|
case isset($object->_explicitType):
|
||||||
$className = $object->_explicitType;
|
$className = $object->_explicitType;
|
||||||
unset($object->_explicitType);
|
|
||||||
break;
|
break;
|
||||||
// Check if user has defined a method for accessing the Action Script type
|
// Check if user has defined a method for accessing the Action Script type
|
||||||
case method_exists($object, 'getASClassName'):
|
case method_exists($object, 'getASClassName'):
|
||||||
$className = $object->getASClassName();
|
$className = $object->getASClassName();
|
||||||
break;
|
break;
|
||||||
// No return class name is set make it a generic object
|
// No return class name is set make it a generic object
|
||||||
|
case ($object instanceof stdClass):
|
||||||
|
$className = '';
|
||||||
|
break;
|
||||||
|
// By default, use object's class name
|
||||||
default:
|
default:
|
||||||
|
$className = get_class($object);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(!$className == '') {
|
if(!$className == '') {
|
||||||
|
@ -1,410 +1,420 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Zend Framework
|
* Zend Framework
|
||||||
*
|
*
|
||||||
* LICENSE
|
* LICENSE
|
||||||
*
|
*
|
||||||
* This source file is subject to the new BSD license that is bundled
|
* This source file is subject to the new BSD license that is bundled
|
||||||
* with this package in the file LICENSE.txt.
|
* with this package in the file LICENSE.txt.
|
||||||
* It is also available through the world-wide-web at this URL:
|
* It is also available through the world-wide-web at this URL:
|
||||||
* http://framework.zend.com/license/new-bsd
|
* http://framework.zend.com/license/new-bsd
|
||||||
* If you did not receive a copy of the license and are unable to
|
* If you did not receive a copy of the license and are unable to
|
||||||
* obtain it through the world-wide-web, please send an email
|
* obtain it through the world-wide-web, please send an email
|
||||||
* to license@zend.com so we can send you a copy immediately.
|
* to license@zend.com so we can send you a copy immediately.
|
||||||
*
|
*
|
||||||
* @category Zend
|
* @category Zend
|
||||||
* @package Zend_Amf
|
* @package Zend_Amf
|
||||||
* @subpackage Parse_Amf3
|
* @subpackage Parse_Amf3
|
||||||
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
|
* @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||||||
* @license http://framework.zend.com/license/new-bsd New BSD License
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** Zend_Amf_Parse_Deserializer */
|
/** Zend_Amf_Parse_Deserializer */
|
||||||
require_once 'Zend/Amf/Parse/Deserializer.php';
|
require_once 'Zend/Amf/Parse/Deserializer.php';
|
||||||
|
|
||||||
/** Zend_Amf_Parse_TypeLoader */
|
/** Zend_Amf_Parse_TypeLoader */
|
||||||
require_once 'Zend/Amf/Parse/TypeLoader.php';
|
require_once 'Zend/Amf/Parse/TypeLoader.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read an AMF3 input stream and convert it into PHP data types.
|
* Read an AMF3 input stream and convert it into PHP data types.
|
||||||
*
|
*
|
||||||
* @todo readObject to handle Typed Objects
|
* @todo readObject to handle Typed Objects
|
||||||
* @todo readXMLStrimg to be implemented.
|
* @todo readXMLStrimg to be implemented.
|
||||||
* @todo Class could be implmented as Factory Class with each data type it's own class.
|
* @todo Class could be implmented as Factory Class with each data type it's own class.
|
||||||
* @package Zend_Amf
|
* @package Zend_Amf
|
||||||
* @subpackage Parse_Amf3
|
* @subpackage Parse_Amf3
|
||||||
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
|
* @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||||||
* @license http://framework.zend.com/license/new-bsd New BSD License
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||||
*/
|
*/
|
||||||
class Zend_Amf_Parse_Amf3_Deserializer extends Zend_Amf_Parse_Deserializer
|
class Zend_Amf_Parse_Amf3_Deserializer extends Zend_Amf_Parse_Deserializer
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Total number of objects in the referenceObject array
|
* Total number of objects in the referenceObject array
|
||||||
* @var int
|
* @var int
|
||||||
*/
|
*/
|
||||||
protected $_objectCount;
|
protected $_objectCount;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An array of reference objects per amf body
|
* An array of reference objects per amf body
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $_referenceObjects = array();
|
protected $_referenceObjects = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An array of reference strings per amf body
|
* An array of reference strings per amf body
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $_referenceStrings = array();
|
protected $_referenceStrings = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An array of reference class definitions per body
|
* An array of reference class definitions per body
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $_referenceDefinitions = array();
|
protected $_referenceDefinitions = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read AMF markers and dispatch for deserialization
|
* Read AMF markers and dispatch for deserialization
|
||||||
*
|
*
|
||||||
* Checks for AMF marker types and calls the appropriate methods
|
* Checks for AMF marker types and calls the appropriate methods
|
||||||
* for deserializing those marker types. markers are the data type of
|
* for deserializing those marker types. markers are the data type of
|
||||||
* the following value.
|
* the following value.
|
||||||
*
|
*
|
||||||
* @param integer $typeMarker
|
* @param integer $typeMarker
|
||||||
* @return mixed Whatever the corresponding PHP data type is
|
* @return mixed Whatever the corresponding PHP data type is
|
||||||
* @throws Zend_Amf_Exception for unidentified marker type
|
* @throws Zend_Amf_Exception for unidentified marker type
|
||||||
*/
|
*/
|
||||||
public function readTypeMarker($typeMarker = null)
|
public function readTypeMarker($typeMarker = null)
|
||||||
{
|
{
|
||||||
if(null === $typeMarker) {
|
if(null === $typeMarker) {
|
||||||
$typeMarker = $this->_stream->readByte();
|
$typeMarker = $this->_stream->readByte();
|
||||||
}
|
}
|
||||||
|
|
||||||
switch($typeMarker) {
|
switch($typeMarker) {
|
||||||
case Zend_Amf_Constants::AMF3_UNDEFINED:
|
case Zend_Amf_Constants::AMF3_UNDEFINED:
|
||||||
return null;
|
return null;
|
||||||
case Zend_Amf_Constants::AMF3_NULL:
|
case Zend_Amf_Constants::AMF3_NULL:
|
||||||
return null;
|
return null;
|
||||||
case Zend_Amf_Constants::AMF3_BOOLEAN_FALSE:
|
case Zend_Amf_Constants::AMF3_BOOLEAN_FALSE:
|
||||||
return false;
|
return false;
|
||||||
case Zend_Amf_Constants::AMF3_BOOLEAN_TRUE:
|
case Zend_Amf_Constants::AMF3_BOOLEAN_TRUE:
|
||||||
return true;
|
return true;
|
||||||
case Zend_Amf_Constants::AMF3_INTEGER:
|
case Zend_Amf_Constants::AMF3_INTEGER:
|
||||||
return $this->readInteger();
|
return $this->readInteger();
|
||||||
case Zend_Amf_Constants::AMF3_NUMBER:
|
case Zend_Amf_Constants::AMF3_NUMBER:
|
||||||
return $this->_stream->readDouble();
|
return $this->_stream->readDouble();
|
||||||
case Zend_Amf_Constants::AMF3_STRING:
|
case Zend_Amf_Constants::AMF3_STRING:
|
||||||
return $this->readString();
|
return $this->readString();
|
||||||
case Zend_Amf_Constants::AMF3_DATE:
|
case Zend_Amf_Constants::AMF3_DATE:
|
||||||
return $this->readDate();
|
return $this->readDate();
|
||||||
case Zend_Amf_Constants::AMF3_ARRAY:
|
case Zend_Amf_Constants::AMF3_ARRAY:
|
||||||
return $this->readArray();
|
return $this->readArray();
|
||||||
case Zend_Amf_Constants::AMF3_OBJECT:
|
case Zend_Amf_Constants::AMF3_OBJECT:
|
||||||
return $this->readObject();
|
return $this->readObject();
|
||||||
case Zend_Amf_Constants::AMF3_XML:
|
case Zend_Amf_Constants::AMF3_XML:
|
||||||
case Zend_Amf_Constants::AMF3_XMLSTRING:
|
case Zend_Amf_Constants::AMF3_XMLSTRING:
|
||||||
return $this->readXmlString();
|
return $this->readXmlString();
|
||||||
case Zend_Amf_Constants::AMF3_BYTEARRAY:
|
case Zend_Amf_Constants::AMF3_BYTEARRAY:
|
||||||
return $this->readString();
|
return $this->readString();
|
||||||
default:
|
default:
|
||||||
require_once 'Zend/Amf/Exception.php';
|
require_once 'Zend/Amf/Exception.php';
|
||||||
throw new Zend_Amf_Exception('Unsupported type marker: ' . $typeMarker);
|
throw new Zend_Amf_Exception('Unsupported type marker: ' . $typeMarker);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read and deserialize an integer
|
* Read and deserialize an integer
|
||||||
*
|
*
|
||||||
* AMF 3 represents smaller integers with fewer bytes using the most
|
* AMF 3 represents smaller integers with fewer bytes using the most
|
||||||
* significant bit of each byte. The worst case uses 32-bits
|
* significant bit of each byte. The worst case uses 32-bits
|
||||||
* to represent a 29-bit number, which is what we would have
|
* to represent a 29-bit number, which is what we would have
|
||||||
* done with no compression.
|
* done with no compression.
|
||||||
* - 0x00000000 - 0x0000007F : 0xxxxxxx
|
* - 0x00000000 - 0x0000007F : 0xxxxxxx
|
||||||
* - 0x00000080 - 0x00003FFF : 1xxxxxxx 0xxxxxxx
|
* - 0x00000080 - 0x00003FFF : 1xxxxxxx 0xxxxxxx
|
||||||
* - 0x00004000 - 0x001FFFFF : 1xxxxxxx 1xxxxxxx 0xxxxxxx
|
* - 0x00004000 - 0x001FFFFF : 1xxxxxxx 1xxxxxxx 0xxxxxxx
|
||||||
* - 0x00200000 - 0x3FFFFFFF : 1xxxxxxx 1xxxxxxx 1xxxxxxx xxxxxxxx
|
* - 0x00200000 - 0x3FFFFFFF : 1xxxxxxx 1xxxxxxx 1xxxxxxx xxxxxxxx
|
||||||
* - 0x40000000 - 0xFFFFFFFF : throw range exception
|
* - 0x40000000 - 0xFFFFFFFF : throw range exception
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 0x04 -> integer type code, followed by up to 4 bytes of data.
|
* 0x04 -> integer type code, followed by up to 4 bytes of data.
|
||||||
*
|
*
|
||||||
* @see: Parsing integers on OSFlash {http://osflash.org/amf3/parsing_integers>} for the AMF3 integer data format.
|
* @see: Parsing integers on OSFlash {http://osflash.org/amf3/parsing_integers>} for the AMF3 integer data format.
|
||||||
* @return int|float
|
* @return int|float
|
||||||
*/
|
*/
|
||||||
public function readInteger()
|
public function readInteger()
|
||||||
{
|
{
|
||||||
$count = 1;
|
$count = 1;
|
||||||
$intReference = $this->_stream->readByte();
|
$intReference = $this->_stream->readByte();
|
||||||
$result = 0;
|
$result = 0;
|
||||||
while ((($intReference & 0x80) != 0) && $count < 4) {
|
while ((($intReference & 0x80) != 0) && $count < 4) {
|
||||||
$result <<= 7;
|
$result <<= 7;
|
||||||
$result |= ($intReference & 0x7f);
|
$result |= ($intReference & 0x7f);
|
||||||
$intReference = $this->_stream->readByte();
|
$intReference = $this->_stream->readByte();
|
||||||
$count++;
|
$count++;
|
||||||
}
|
}
|
||||||
if ($count < 4) {
|
if ($count < 4) {
|
||||||
$result <<= 7;
|
$result <<= 7;
|
||||||
$result |= $intReference;
|
$result |= $intReference;
|
||||||
} else {
|
} else {
|
||||||
// Use all 8 bits from the 4th byte
|
// Use all 8 bits from the 4th byte
|
||||||
$result <<= 8;
|
$result <<= 8;
|
||||||
$result |= $intReference;
|
$result |= $intReference;
|
||||||
|
|
||||||
// Check if the integer should be negative
|
// Check if the integer should be negative
|
||||||
if (($result & 0x10000000) != 0) {
|
if (($result & 0x10000000) != 0) {
|
||||||
//and extend the sign bit
|
//and extend the sign bit
|
||||||
$result |= 0xe0000000;
|
$result |= ~0xFFFFFFF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read and deserialize a string
|
* Read and deserialize a string
|
||||||
*
|
*
|
||||||
* Strings can be sent as a reference to a previously
|
* Strings can be sent as a reference to a previously
|
||||||
* occurring String by using an index to the implicit string reference table.
|
* occurring String by using an index to the implicit string reference table.
|
||||||
* Strings are encoding using UTF-8 - however the header may either
|
* Strings are encoding using UTF-8 - however the header may either
|
||||||
* describe a string literal or a string reference.
|
* describe a string literal or a string reference.
|
||||||
*
|
*
|
||||||
* - string = 0×06 string-data
|
* - string = 0x06 string-data
|
||||||
* - string-data = integer-data [ modified-utf-8 ]
|
* - string-data = integer-data [ modified-utf-8 ]
|
||||||
* - modified-utf-8 = *OCTET
|
* - modified-utf-8 = *OCTET
|
||||||
*
|
*
|
||||||
* @return String
|
* @return String
|
||||||
*/
|
*/
|
||||||
public function readString()
|
public function readString()
|
||||||
{
|
{
|
||||||
$stringReference = $this->readInteger();
|
$stringReference = $this->readInteger();
|
||||||
|
|
||||||
//Check if this is a reference string
|
//Check if this is a reference string
|
||||||
if (($stringReference & 0x01) == 0) {
|
if (($stringReference & 0x01) == 0) {
|
||||||
// reference string
|
// reference string
|
||||||
$stringReference = $stringReference >> 1;
|
$stringReference = $stringReference >> 1;
|
||||||
if ($stringReference >= count($this->_referenceStrings)) {
|
if ($stringReference >= count($this->_referenceStrings)) {
|
||||||
require_once 'Zend/Amf/Exception.php';
|
require_once 'Zend/Amf/Exception.php';
|
||||||
throw new Zend_Amf_Exception('Undefined string reference: ' . $stringReference);
|
throw new Zend_Amf_Exception('Undefined string reference: ' . $stringReference);
|
||||||
}
|
}
|
||||||
// reference string found
|
// reference string found
|
||||||
return $this->_referenceStrings[$stringReference];
|
return $this->_referenceStrings[$stringReference];
|
||||||
}
|
}
|
||||||
|
|
||||||
$length = $stringReference >> 1;
|
$length = $stringReference >> 1;
|
||||||
if ($length) {
|
if ($length) {
|
||||||
$string = $this->_stream->readBytes($length);
|
$string = $this->_stream->readBytes($length);
|
||||||
$this->_referenceStrings[] = $string;
|
$this->_referenceStrings[] = $string;
|
||||||
} else {
|
} else {
|
||||||
$string = "";
|
$string = "";
|
||||||
}
|
}
|
||||||
return $string;
|
return $string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read and deserialize a date
|
* Read and deserialize a date
|
||||||
*
|
*
|
||||||
* Data is the number of milliseconds elapsed since the epoch
|
* Data is the number of milliseconds elapsed since the epoch
|
||||||
* of midnight, 1st Jan 1970 in the UTC time zone.
|
* of midnight, 1st Jan 1970 in the UTC time zone.
|
||||||
* Local time zone information is not sent to flash.
|
* Local time zone information is not sent to flash.
|
||||||
*
|
*
|
||||||
* - date = 0×08 integer-data [ number-data ]
|
* - date = 0x08 integer-data [ number-data ]
|
||||||
*
|
*
|
||||||
* @return Zend_Date
|
* @return Zend_Date
|
||||||
*/
|
*/
|
||||||
public function readDate()
|
public function readDate()
|
||||||
{
|
{
|
||||||
$dateReference = $this->readInteger();
|
$dateReference = $this->readInteger();
|
||||||
if (($dateReference & 0x01) == 0) {
|
if (($dateReference & 0x01) == 0) {
|
||||||
$dateReference = $dateReference >> 1;
|
$dateReference = $dateReference >> 1;
|
||||||
if ($dateReference>=count($this->_referenceObjects)) {
|
if ($dateReference>=count($this->_referenceObjects)) {
|
||||||
require_once 'Zend/Amf/Exception.php';
|
require_once 'Zend/Amf/Exception.php';
|
||||||
throw new Zend_Amf_Exception('Undefined date reference: ' . $dateReference);
|
throw new Zend_Amf_Exception('Undefined date reference: ' . $dateReference);
|
||||||
}
|
}
|
||||||
return $this->_referenceObjects[$dateReference];
|
return $this->_referenceObjects[$dateReference];
|
||||||
}
|
}
|
||||||
|
|
||||||
$timestamp = floor($this->_stream->readDouble() / 1000);
|
$timestamp = floor($this->_stream->readDouble() / 1000);
|
||||||
|
|
||||||
require_once 'Zend/Date.php';
|
require_once 'Zend/Date.php';
|
||||||
$dateTime = new Zend_Date((int) $timestamp);
|
$dateTime = new Zend_Date((int) $timestamp);
|
||||||
$this->_referenceObjects[] = $dateTime;
|
$this->_referenceObjects[] = $dateTime;
|
||||||
return $dateTime;
|
return $dateTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read amf array to PHP array
|
* Read amf array to PHP array
|
||||||
*
|
*
|
||||||
* - array = 0×09 integer-data ( [ 1OCTET *amf3-data ] | [OCTET *amf3-data 1] | [ OCTET *amf-data ] )
|
* - array = 0x09 integer-data ( [ 1OCTET *amf3-data ] | [OCTET *amf3-data 1] | [ OCTET *amf-data ] )
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function readArray()
|
public function readArray()
|
||||||
{
|
{
|
||||||
$arrayReference = $this->readInteger();
|
$arrayReference = $this->readInteger();
|
||||||
if (($arrayReference & 0x01)==0){
|
if (($arrayReference & 0x01)==0){
|
||||||
$arrayReference = $arrayReference >> 1;
|
$arrayReference = $arrayReference >> 1;
|
||||||
if ($arrayReference>=count($this->_referenceObjects)) {
|
if ($arrayReference>=count($this->_referenceObjects)) {
|
||||||
require_once 'Zend/Amf/Exception.php';
|
require_once 'Zend/Amf/Exception.php';
|
||||||
throw new Zend_Amf_Exception('Unknow array reference: ' . $arrayReference);
|
throw new Zend_Amf_Exception('Unknow array reference: ' . $arrayReference);
|
||||||
}
|
}
|
||||||
return $this->_referenceObjects[$arrayReference];
|
return $this->_referenceObjects[$arrayReference];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a holder for the array in the reference list
|
// Create a holder for the array in the reference list
|
||||||
$data = array();
|
$data = array();
|
||||||
$this->_referenceObjects[] &= $data;
|
$this->_referenceObjects[] =& $data;
|
||||||
$key = $this->readString();
|
$key = $this->readString();
|
||||||
|
|
||||||
// Iterating for string based keys.
|
// Iterating for string based keys.
|
||||||
while ($key != '') {
|
while ($key != '') {
|
||||||
$data[$key] = $this->readTypeMarker();
|
$data[$key] = $this->readTypeMarker();
|
||||||
$key = $this->readString();
|
$key = $this->readString();
|
||||||
}
|
}
|
||||||
|
|
||||||
$arrayReference = $arrayReference >>1;
|
$arrayReference = $arrayReference >>1;
|
||||||
|
|
||||||
//We have a dense array
|
//We have a dense array
|
||||||
for ($i=0; $i < $arrayReference; $i++) {
|
for ($i=0; $i < $arrayReference; $i++) {
|
||||||
$data[] = $this->readTypeMarker();
|
$data[] = $this->readTypeMarker();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read an object from the AMF stream and convert it into a PHP object
|
* Read an object from the AMF stream and convert it into a PHP object
|
||||||
*
|
*
|
||||||
* @todo Rather than using an array of traitsInfo create Zend_Amf_Value_TraitsInfo
|
* @todo Rather than using an array of traitsInfo create Zend_Amf_Value_TraitsInfo
|
||||||
* @return object
|
* @return object|array
|
||||||
*/
|
*/
|
||||||
public function readObject()
|
public function readObject()
|
||||||
{
|
{
|
||||||
$traitsInfo = $this->readInteger();
|
$traitsInfo = $this->readInteger();
|
||||||
$storedObject = ($traitsInfo & 0x01)==0;
|
$storedObject = ($traitsInfo & 0x01)==0;
|
||||||
$traitsInfo = $traitsInfo >> 1;
|
$traitsInfo = $traitsInfo >> 1;
|
||||||
|
|
||||||
// Check if the Object is in the stored Objects reference table
|
// Check if the Object is in the stored Objects reference table
|
||||||
if ($storedObject) {
|
if ($storedObject) {
|
||||||
$ref = $traitsInfo;
|
$ref = $traitsInfo;
|
||||||
if (!isset($this->_referenceObjects[$ref])) {
|
if (!isset($this->_referenceObjects[$ref])) {
|
||||||
require_once 'Zend/Amf/Exception.php';
|
require_once 'Zend/Amf/Exception.php';
|
||||||
throw new Zend_Amf_Exception('Unknown Object reference: ' . $ref);
|
throw new Zend_Amf_Exception('Unknown Object reference: ' . $ref);
|
||||||
}
|
}
|
||||||
$returnObject = $this->_referenceObjects[$ref];
|
$returnObject = $this->_referenceObjects[$ref];
|
||||||
} else {
|
} else {
|
||||||
// Check if the Object is in the stored Definistions reference table
|
// Check if the Object is in the stored Definistions reference table
|
||||||
$storedClass = ($traitsInfo & 0x01) == 0;
|
$storedClass = ($traitsInfo & 0x01) == 0;
|
||||||
$traitsInfo = $traitsInfo >> 1;
|
$traitsInfo = $traitsInfo >> 1;
|
||||||
if ($storedClass) {
|
if ($storedClass) {
|
||||||
$ref = $traitsInfo;
|
$ref = $traitsInfo;
|
||||||
if (!isset($this->_referenceDefinitions[$ref])) {
|
if (!isset($this->_referenceDefinitions[$ref])) {
|
||||||
require_once 'Zend/Amf/Exception.php';
|
require_once 'Zend/Amf/Exception.php';
|
||||||
throw new Zend_Amf_Exception('Unknows Definition reference: '. $ref);
|
throw new Zend_Amf_Exception('Unknows Definition reference: '. $ref);
|
||||||
}
|
}
|
||||||
// Populate the reference attributes
|
// Populate the reference attributes
|
||||||
$className = $this->_referenceDefinitions[$ref]['className'];
|
$className = $this->_referenceDefinitions[$ref]['className'];
|
||||||
$encoding = $this->_referenceDefinitions[$ref]['encoding'];
|
$encoding = $this->_referenceDefinitions[$ref]['encoding'];
|
||||||
$propertyNames = $this->_referenceDefinitions[$ref]['propertyNames'];
|
$propertyNames = $this->_referenceDefinitions[$ref]['propertyNames'];
|
||||||
} else {
|
} else {
|
||||||
// The class was not in the reference tables. Start reading rawdata to build traits.
|
// The class was not in the reference tables. Start reading rawdata to build traits.
|
||||||
// Create a traits table. Zend_Amf_Value_TraitsInfo would be ideal
|
// Create a traits table. Zend_Amf_Value_TraitsInfo would be ideal
|
||||||
$className = $this->readString();
|
$className = $this->readString();
|
||||||
$encoding = $traitsInfo & 0x03;
|
$encoding = $traitsInfo & 0x03;
|
||||||
$propertyNames = array();
|
$propertyNames = array();
|
||||||
$traitsInfo = $traitsInfo >> 2;
|
$traitsInfo = $traitsInfo >> 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We now have the object traits defined in variables. Time to go to work:
|
// We now have the object traits defined in variables. Time to go to work:
|
||||||
if (!$className) {
|
if (!$className) {
|
||||||
// No class name generic object
|
// No class name generic object
|
||||||
$returnObject = new stdClass();
|
$returnObject = new stdClass();
|
||||||
} else {
|
} else {
|
||||||
// Defined object
|
// Defined object
|
||||||
// Typed object lookup agsinst registered classname maps
|
// Typed object lookup agsinst registered classname maps
|
||||||
if ($loader = Zend_Amf_Parse_TypeLoader::loadType($className)) {
|
if ($loader = Zend_Amf_Parse_TypeLoader::loadType($className)) {
|
||||||
$returnObject = new $loader();
|
$returnObject = new $loader();
|
||||||
} else {
|
} else {
|
||||||
//user defined typed object
|
//user defined typed object
|
||||||
require_once 'Zend/Amf/Exception.php';
|
require_once 'Zend/Amf/Exception.php';
|
||||||
throw new Zend_Amf_Exception('Typed object not found: '. $className . ' ');
|
throw new Zend_Amf_Exception('Typed object not found: '. $className . ' ');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the Object ot the reference table
|
// Add the Object ot the reference table
|
||||||
$this->_referenceObjects[] = $returnObject;
|
$this->_referenceObjects[] = $returnObject;
|
||||||
|
|
||||||
// Check encoding types for additional processing.
|
$properties = array(); // clear value
|
||||||
switch ($encoding) {
|
// Check encoding types for additional processing.
|
||||||
case (Zend_Amf_Constants::ET_EXTERNAL):
|
switch ($encoding) {
|
||||||
// Externalizable object such as {ArrayCollection} and {ObjectProxy}
|
case (Zend_Amf_Constants::ET_EXTERNAL):
|
||||||
if (!$storedClass) {
|
// Externalizable object such as {ArrayCollection} and {ObjectProxy}
|
||||||
$this->_referenceDefinitions[] = array(
|
if (!$storedClass) {
|
||||||
'className' => $className,
|
$this->_referenceDefinitions[] = array(
|
||||||
'encoding' => $encoding,
|
'className' => $className,
|
||||||
'propertyNames' => $propertyNames,
|
'encoding' => $encoding,
|
||||||
);
|
'propertyNames' => $propertyNames,
|
||||||
}
|
);
|
||||||
$returnObject->externalizedData = $this->readTypeMarker();
|
}
|
||||||
break;
|
$returnObject->externalizedData = $this->readTypeMarker();
|
||||||
case (Zend_Amf_Constants::ET_DYNAMIC):
|
break;
|
||||||
// used for Name-value encoding
|
case (Zend_Amf_Constants::ET_DYNAMIC):
|
||||||
if (!$storedClass) {
|
// used for Name-value encoding
|
||||||
$this->_referenceDefinitions[] = array(
|
if (!$storedClass) {
|
||||||
'className' => $className,
|
$this->_referenceDefinitions[] = array(
|
||||||
'encoding' => $encoding,
|
'className' => $className,
|
||||||
'propertyNames' => $propertyNames,
|
'encoding' => $encoding,
|
||||||
);
|
'propertyNames' => $propertyNames,
|
||||||
}
|
);
|
||||||
// not a refrence object read name value properties from byte stream
|
}
|
||||||
$properties = array(); // clear value
|
// not a refrence object read name value properties from byte stream
|
||||||
do {
|
do {
|
||||||
$property = $this->readString();
|
$property = $this->readString();
|
||||||
if ($property != "") {
|
if ($property != "") {
|
||||||
$propertyNames[] = $property;
|
$propertyNames[] = $property;
|
||||||
$properties[$property] = $this->readTypeMarker();
|
$properties[$property] = $this->readTypeMarker();
|
||||||
}
|
}
|
||||||
} while ($property !="");
|
} while ($property !="");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// basic property list object.
|
// basic property list object.
|
||||||
if (!$storedClass) {
|
if (!$storedClass) {
|
||||||
$count = $traitsInfo; // Number of properties in the list
|
$count = $traitsInfo; // Number of properties in the list
|
||||||
for($i=0; $i< $count; $i++) {
|
for($i=0; $i< $count; $i++) {
|
||||||
$propertyNames[] = $this->readString();
|
$propertyNames[] = $this->readString();
|
||||||
}
|
}
|
||||||
// Add a refrence to the class.
|
// Add a refrence to the class.
|
||||||
$this->_referenceDefinitions[] = array(
|
$this->_referenceDefinitions[] = array(
|
||||||
'className' => $className,
|
'className' => $className,
|
||||||
'encoding' => $encoding,
|
'encoding' => $encoding,
|
||||||
'propertyNames' => $propertyNames,
|
'propertyNames' => $propertyNames,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
$properties = array(); // clear value
|
foreach ($propertyNames as $property) {
|
||||||
foreach ($propertyNames as $property) {
|
$properties[$property] = $this->readTypeMarker();
|
||||||
$properties[$property] = $this->readTypeMarker();
|
}
|
||||||
}
|
break;
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
|
// Add properties back to the return object.
|
||||||
// Add properties back to the return object.
|
foreach($properties as $key=>$value) {
|
||||||
foreach($properties as $key=>$value) {
|
if($key) {
|
||||||
if($key) {
|
$returnObject->$key = $value;
|
||||||
$returnObject->$key = $value;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
return $returnObject;
|
}
|
||||||
}
|
|
||||||
|
if($returnObject instanceof Zend_Amf_Value_Messaging_ArrayCollection) {
|
||||||
/**
|
if(isset($returnObject->externalizedData)) {
|
||||||
* Convert XML to SimpleXml
|
$returnObject = $returnObject->externalizedData;
|
||||||
* If user wants DomDocument they can use dom_import_simplexml
|
} else {
|
||||||
*
|
$returnObject = get_object_vars($returnObject);
|
||||||
* @return SimpleXml Object
|
}
|
||||||
*/
|
}
|
||||||
public function readXmlString()
|
|
||||||
{
|
return $returnObject;
|
||||||
$xmlReference = $this->readInteger();
|
}
|
||||||
$length = $xmlReference >> 1;
|
|
||||||
$string = $this->_stream->readBytes($length);
|
/**
|
||||||
return simplexml_load_string($string);
|
* Convert XML to SimpleXml
|
||||||
}
|
* If user wants DomDocument they can use dom_import_simplexml
|
||||||
}
|
*
|
||||||
|
* @return SimpleXml Object
|
||||||
|
*/
|
||||||
|
public function readXmlString()
|
||||||
|
{
|
||||||
|
$xmlReference = $this->readInteger();
|
||||||
|
$length = $xmlReference >> 1;
|
||||||
|
$string = $this->_stream->readBytes($length);
|
||||||
|
return simplexml_load_string($string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
* @category Zend
|
* @category Zend
|
||||||
* @package Zend_Amf
|
* @package Zend_Amf
|
||||||
* @subpackage Parse_Amf3
|
* @subpackage Parse_Amf3
|
||||||
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
|
* @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||||||
* @license http://framework.zend.com/license/new-bsd New BSD License
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -30,11 +30,29 @@ require_once 'Zend/Amf/Parse/TypeLoader.php';
|
|||||||
*
|
*
|
||||||
* @package Zend_Amf
|
* @package Zend_Amf
|
||||||
* @subpackage Parse_Amf3
|
* @subpackage Parse_Amf3
|
||||||
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
|
* @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||||||
* @license http://framework.zend.com/license/new-bsd New BSD License
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||||
*/
|
*/
|
||||||
class Zend_Amf_Parse_Amf3_Serializer extends Zend_Amf_Parse_Serializer
|
class Zend_Amf_Parse_Amf3_Serializer extends Zend_Amf_Parse_Serializer
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* An array of reference objects per amf body
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $_referenceObjects = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array of reference strings per amf body
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $_referenceStrings = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array of reference class definitions, indexed by classname
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $_referenceDefinitions = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serialize PHP types to AMF3 and write to stream
|
* Serialize PHP types to AMF3 and write to stream
|
||||||
*
|
*
|
||||||
@ -78,7 +96,10 @@ class Zend_Amf_Parse_Amf3_Serializer extends Zend_Amf_Parse_Serializer
|
|||||||
$this->writeObject($data);
|
$this->writeObject($data);
|
||||||
break;
|
break;
|
||||||
case Zend_Amf_Constants::AMF3_BYTEARRAY:
|
case Zend_Amf_Constants::AMF3_BYTEARRAY:
|
||||||
$this->writeString($data);
|
$this->writeByteArray($data);
|
||||||
|
break;
|
||||||
|
case Zend_Amf_Constants::AMF3_XMLSTRING;
|
||||||
|
$this->writeXml($data);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
require_once 'Zend/Amf/Exception.php';
|
require_once 'Zend/Amf/Exception.php';
|
||||||
@ -86,8 +107,11 @@ class Zend_Amf_Parse_Amf3_Serializer extends Zend_Amf_Parse_Serializer
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Detect Type Marker
|
// Detect Type Marker
|
||||||
|
if(is_resource($data)) {
|
||||||
|
$data = Zend_Amf_Parse_TypeLoader::handleResource($data);
|
||||||
|
}
|
||||||
switch (true) {
|
switch (true) {
|
||||||
case (null === $data):
|
case (null === $data):
|
||||||
$markerType = Zend_Amf_Constants::AMF3_NULL;
|
$markerType = Zend_Amf_Constants::AMF3_NULL;
|
||||||
break;
|
break;
|
||||||
case (is_bool($data)):
|
case (is_bool($data)):
|
||||||
@ -119,6 +143,8 @@ class Zend_Amf_Parse_Amf3_Serializer extends Zend_Amf_Parse_Serializer
|
|||||||
$markerType = Zend_Amf_Constants::AMF3_DATE;
|
$markerType = Zend_Amf_Constants::AMF3_DATE;
|
||||||
} else if ($data instanceof Zend_Amf_Value_ByteArray) {
|
} else if ($data instanceof Zend_Amf_Value_ByteArray) {
|
||||||
$markerType = Zend_Amf_Constants::AMF3_BYTEARRAY;
|
$markerType = Zend_Amf_Constants::AMF3_BYTEARRAY;
|
||||||
|
} else if (($data instanceof DOMDocument) || ($data instanceof SimpleXMLElement)) {
|
||||||
|
$markerType = Zend_Amf_Constants::AMF3_XMLSTRING;
|
||||||
} else {
|
} else {
|
||||||
$markerType = Zend_Amf_Constants::AMF3_OBJECT;
|
$markerType = Zend_Amf_Constants::AMF3_OBJECT;
|
||||||
}
|
}
|
||||||
@ -163,6 +189,21 @@ class Zend_Amf_Parse_Amf3_Serializer extends Zend_Amf_Parse_Serializer
|
|||||||
$this->_stream->writeByte($int & 0xff);
|
$this->_stream->writeByte($int & 0xff);
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send string to output stream, without trying to reference it.
|
||||||
|
* The string is prepended with strlen($string) << 1 | 0x01
|
||||||
|
*
|
||||||
|
* @param string $string
|
||||||
|
* @return Zend_Amf_Parse_Amf3_Serializer
|
||||||
|
*/
|
||||||
|
protected function writeBinaryString($string){
|
||||||
|
$ref = strlen($string) << 1 | 0x01;
|
||||||
|
$this->writeInteger($ref);
|
||||||
|
$this->_stream->writeBytes($string);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send string to output stream
|
* Send string to output stream
|
||||||
@ -172,9 +213,74 @@ class Zend_Amf_Parse_Amf3_Serializer extends Zend_Amf_Parse_Serializer
|
|||||||
*/
|
*/
|
||||||
public function writeString($string)
|
public function writeString($string)
|
||||||
{
|
{
|
||||||
$ref = strlen($string) << 1 | 0x01;
|
$len = strlen($string);
|
||||||
$this->writeInteger($ref);
|
if(!$len){
|
||||||
$this->_stream->writeBytes($string);
|
$this->writeInteger(0x01);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ref = array_search($string, $this->_referenceStrings, true);
|
||||||
|
if($ref === false){
|
||||||
|
$this->_referenceStrings[] = $string;
|
||||||
|
$this->writeBinaryString($string);
|
||||||
|
} else {
|
||||||
|
$ref <<= 1;
|
||||||
|
$this->writeInteger($ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send ByteArray to output stream
|
||||||
|
*
|
||||||
|
* @param string|Zend_Amf_Value_ByteArray $data
|
||||||
|
* @return Zend_Amf_Parse_Amf3_Serializer
|
||||||
|
*/
|
||||||
|
public function writeByteArray($data){
|
||||||
|
if($this->writeObjectReference($data)){
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(is_string($data)) {
|
||||||
|
//nothing to do
|
||||||
|
} else if ($data instanceof Zend_Amf_Value_ByteArray) {
|
||||||
|
$data = $data->getData();
|
||||||
|
} else {
|
||||||
|
require_once 'Zend/Amf/Exception.php';
|
||||||
|
throw new Zend_Amf_Exception('Invalid ByteArray specified; must be a string or Zend_Amf_Value_ByteArray');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->writeBinaryString($data);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send xml to output stream
|
||||||
|
*
|
||||||
|
* @param DOMDocument|SimpleXMLElement $xml
|
||||||
|
* @return Zend_Amf_Parse_Amf3_Serializer
|
||||||
|
*/
|
||||||
|
public function writeXml($xml)
|
||||||
|
{
|
||||||
|
if($this->writeObjectReference($xml)){
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(is_string($xml)) {
|
||||||
|
//nothing to do
|
||||||
|
} else if ($xml instanceof DOMDocument) {
|
||||||
|
$xml = $xml->saveXml();
|
||||||
|
} else if ($xml instanceof SimpleXMLElement) {
|
||||||
|
$xml = $xml->asXML();
|
||||||
|
} else {
|
||||||
|
require_once 'Zend/Amf/Exception.php';
|
||||||
|
throw new Zend_Amf_Exception('Invalid xml specified; must be a DOMDocument or SimpleXMLElement');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->writeBinaryString($xml);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,6 +292,10 @@ class Zend_Amf_Parse_Amf3_Serializer extends Zend_Amf_Parse_Serializer
|
|||||||
*/
|
*/
|
||||||
public function writeDate($date)
|
public function writeDate($date)
|
||||||
{
|
{
|
||||||
|
if($this->writeObjectReference($date)){
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
if ($date instanceof DateTime) {
|
if ($date instanceof DateTime) {
|
||||||
$dateString = $date->format('U') * 1000;
|
$dateString = $date->format('U') * 1000;
|
||||||
} elseif ($date instanceof Zend_Date) {
|
} elseif ($date instanceof Zend_Date) {
|
||||||
@ -209,6 +319,10 @@ class Zend_Amf_Parse_Amf3_Serializer extends Zend_Amf_Parse_Serializer
|
|||||||
*/
|
*/
|
||||||
public function writeArray(array $array)
|
public function writeArray(array $array)
|
||||||
{
|
{
|
||||||
|
if($this->writeObjectReference($array)){
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
// have to seperate mixed from numberic keys.
|
// have to seperate mixed from numberic keys.
|
||||||
$numeric = array();
|
$numeric = array();
|
||||||
$string = array();
|
$string = array();
|
||||||
@ -238,6 +352,25 @@ class Zend_Amf_Parse_Amf3_Serializer extends Zend_Amf_Parse_Serializer
|
|||||||
}
|
}
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the given object is in the reference table, write the reference if it exists,
|
||||||
|
* otherwise add the object to the reference table
|
||||||
|
*
|
||||||
|
* @param mixed $object object to check for reference
|
||||||
|
* @return Boolean true, if the reference was written, false otherwise
|
||||||
|
*/
|
||||||
|
protected function writeObjectReference($object){
|
||||||
|
$ref = array_search($object, $this->_referenceObjects,true);
|
||||||
|
//quickly handle object references
|
||||||
|
if($ref !== false){
|
||||||
|
$ref <<= 1;
|
||||||
|
$this->writeInteger($ref);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
$this->_referenceObjects[] = $object;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write object to ouput stream
|
* Write object to ouput stream
|
||||||
@ -247,7 +380,10 @@ class Zend_Amf_Parse_Amf3_Serializer extends Zend_Amf_Parse_Serializer
|
|||||||
*/
|
*/
|
||||||
public function writeObject($object)
|
public function writeObject($object)
|
||||||
{
|
{
|
||||||
$encoding = Zend_Amf_Constants::ET_PROPLIST;
|
if($this->writeObjectReference($object)){
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
$className = '';
|
$className = '';
|
||||||
|
|
||||||
//Check to see if the object is a typed object and we need to change
|
//Check to see if the object is a typed object and we need to change
|
||||||
@ -259,7 +395,6 @@ class Zend_Amf_Parse_Amf3_Serializer extends Zend_Amf_Parse_Serializer
|
|||||||
// Check to see if the user has defined an explicit Action Script type.
|
// Check to see if the user has defined an explicit Action Script type.
|
||||||
case isset($object->_explicitType):
|
case isset($object->_explicitType):
|
||||||
$className = $object->_explicitType;
|
$className = $object->_explicitType;
|
||||||
unset($object->_explicitType);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Check if user has defined a method for accessing the Action Script type
|
// Check if user has defined a method for accessing the Action Script type
|
||||||
@ -268,36 +403,87 @@ class Zend_Amf_Parse_Amf3_Serializer extends Zend_Amf_Parse_Serializer
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
// No return class name is set make it a generic object
|
// No return class name is set make it a generic object
|
||||||
|
case ($object instanceof stdClass):
|
||||||
|
$className = '';
|
||||||
|
break;
|
||||||
|
|
||||||
|
// By default, use object's class name
|
||||||
default:
|
default:
|
||||||
|
$className = get_class($object);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
$traitsInfo = Zend_Amf_Constants::AMF3_OBJECT_ENCODING;
|
$writeTraits = true;
|
||||||
$traitsInfo |= $encoding << 2;
|
|
||||||
|
//check to see, if we have a corresponding definition
|
||||||
|
if(array_key_exists($className, $this->_referenceDefinitions)){
|
||||||
|
$traitsInfo = $this->_referenceDefinitions[$className]['id'];
|
||||||
|
$encoding = $this->_referenceDefinitions[$className]['encoding'];
|
||||||
|
$propertyNames = $this->_referenceDefinitions[$className]['propertyNames'];
|
||||||
|
|
||||||
|
$traitsInfo = ($traitsInfo << 2) | 0x01;
|
||||||
|
|
||||||
|
$writeTraits = false;
|
||||||
|
} else {
|
||||||
|
$propertyNames = array();
|
||||||
|
|
||||||
|
if($className == ''){
|
||||||
|
//if there is no className, we interpret the class as dynamic without any sealed members
|
||||||
|
$encoding = Zend_Amf_Constants::ET_DYNAMIC;
|
||||||
|
} else {
|
||||||
|
$encoding = Zend_Amf_Constants::ET_PROPLIST;
|
||||||
|
|
||||||
|
foreach($object as $key => $value) {
|
||||||
|
if( $key[0] != "_") {
|
||||||
|
$propertyNames[] = $key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->_referenceDefinitions[$className] = array(
|
||||||
|
'id' => count($this->_referenceDefinitions),
|
||||||
|
'encoding' => $encoding,
|
||||||
|
'propertyNames' => $propertyNames,
|
||||||
|
);
|
||||||
|
|
||||||
|
$traitsInfo = Zend_Amf_Constants::AMF3_OBJECT_ENCODING;
|
||||||
|
$traitsInfo |= $encoding << 2;
|
||||||
|
$traitsInfo |= (count($propertyNames) << 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->writeInteger($traitsInfo);
|
||||||
|
|
||||||
|
if($writeTraits){
|
||||||
|
$this->writeString($className);
|
||||||
|
foreach ($propertyNames as $value) {
|
||||||
|
$this->writeString($value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
switch($encoding) {
|
switch($encoding) {
|
||||||
case Zend_Amf_Constants::ET_PROPLIST:
|
case Zend_Amf_Constants::ET_PROPLIST:
|
||||||
$count = 0;
|
//Write the sealed values to the output stream.
|
||||||
foreach($object as $key => $value) {
|
foreach ($propertyNames as $key) {
|
||||||
$count++;
|
$this->writeTypeMarker($object->$key);
|
||||||
}
|
}
|
||||||
$traitsInfo |= ($count << 4);
|
break;
|
||||||
|
case Zend_Amf_Constants::ET_DYNAMIC:
|
||||||
// Write the object ID
|
//Write the sealed values to the output stream.
|
||||||
$this->writeInteger($traitsInfo);
|
foreach ($propertyNames as $key) {
|
||||||
|
$this->writeTypeMarker($object->$key);
|
||||||
// Write the classname
|
|
||||||
$this->writeString($className);
|
|
||||||
|
|
||||||
// Write the object Key's to the output stream
|
|
||||||
foreach ($object as $key => $value) {
|
|
||||||
$this->writeString($key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Write the object values to the output stream.
|
//Write remaining properties
|
||||||
foreach ($object as $key => $value) {
|
foreach($object as $key => $value){
|
||||||
$this->writeTypeMarker($value);
|
if(!in_array($key,$propertyNames) && $key[0] != "_"){
|
||||||
|
$this->writeString($key);
|
||||||
|
$this->writeTypeMarker($value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Write an empty string to end the dynamic part
|
||||||
|
$this->writeString('');
|
||||||
break;
|
break;
|
||||||
case Zend_Amf_Constants::ET_EXTERNAL:
|
case Zend_Amf_Constants::ET_EXTERNAL:
|
||||||
require_once 'Zend/Amf/Exception.php';
|
require_once 'Zend/Amf/Exception.php';
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
* @category Zend
|
* @category Zend
|
||||||
* @package Zend_Amf
|
* @package Zend_Amf
|
||||||
* @subpackage Parse
|
* @subpackage Parse
|
||||||
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
|
* @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||||||
* @license http://framework.zend.com/license/new-bsd New BSD License
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -29,7 +29,7 @@
|
|||||||
* @see http://opensource.adobe.com/svn/opensource/blazeds/trunk/modules/core/src/java/flex/messaging/io/amf/
|
* @see http://opensource.adobe.com/svn/opensource/blazeds/trunk/modules/core/src/java/flex/messaging/io/amf/
|
||||||
* @package Zend_Amf
|
* @package Zend_Amf
|
||||||
* @subpackage Parse
|
* @subpackage Parse
|
||||||
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
|
* @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||||||
* @license http://framework.zend.com/license/new-bsd New BSD License
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||||
*/
|
*/
|
||||||
abstract class Zend_Amf_Parse_Deserializer
|
abstract class Zend_Amf_Parse_Deserializer
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
* @category Zend
|
* @category Zend
|
||||||
* @package Zend_Amf
|
* @package Zend_Amf
|
||||||
* @subpackage Parse
|
* @subpackage Parse
|
||||||
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
|
* @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||||||
* @license http://framework.zend.com/license/new-bsd New BSD License
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ require_once 'Zend/Amf/Util/BinaryStream.php';
|
|||||||
*
|
*
|
||||||
* @package Zend_Amf
|
* @package Zend_Amf
|
||||||
* @subpackage Parse
|
* @subpackage Parse
|
||||||
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
|
* @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||||||
* @license http://framework.zend.com/license/new-bsd New BSD License
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||||
*/
|
*/
|
||||||
class Zend_Amf_Parse_InputStream extends Zend_Amf_Util_BinaryStream
|
class Zend_Amf_Parse_InputStream extends Zend_Amf_Util_BinaryStream
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
* @category Zend
|
* @category Zend
|
||||||
* @package Zend_Amf
|
* @package Zend_Amf
|
||||||
* @subpackage Parse
|
* @subpackage Parse
|
||||||
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
|
* @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||||||
* @license http://framework.zend.com/license/new-bsd New BSD License
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ require_once 'Zend/Amf/Util/BinaryStream.php';
|
|||||||
* @uses Zend_Amf_Util_BinaryStream
|
* @uses Zend_Amf_Util_BinaryStream
|
||||||
* @package Zend_Amf
|
* @package Zend_Amf
|
||||||
* @subpackage Parse
|
* @subpackage Parse
|
||||||
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
|
* @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||||||
* @license http://framework.zend.com/license/new-bsd New BSD License
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||||
*/
|
*/
|
||||||
class Zend_Amf_Parse_OutputStream extends Zend_Amf_Util_BinaryStream
|
class Zend_Amf_Parse_OutputStream extends Zend_Amf_Util_BinaryStream
|
||||||
|
69
libs/Zend/Amf/Parse/Resource/MysqlResult.php
Executable file
69
libs/Zend/Amf/Parse/Resource/MysqlResult.php
Executable file
@ -0,0 +1,69 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Zend Framework
|
||||||
|
*
|
||||||
|
* LICENSE
|
||||||
|
*
|
||||||
|
* This source file is subject to the new BSD license that is bundled
|
||||||
|
* with this package in the file LICENSE.txt.
|
||||||
|
* It is also available through the world-wide-web at this URL:
|
||||||
|
* http://framework.zend.com/license/new-bsd
|
||||||
|
* If you did not receive a copy of the license and are unable to
|
||||||
|
* obtain it through the world-wide-web, please send an email
|
||||||
|
* to license@zend.com so we can send you a copy immediately.
|
||||||
|
*
|
||||||
|
* @category Zend
|
||||||
|
* @package Zend_Amf
|
||||||
|
* @subpackage Parse
|
||||||
|
* @copyright Copyright (c) 2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||||||
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class will convert mysql result resource to array suitable for passing
|
||||||
|
* to the external entities.
|
||||||
|
*
|
||||||
|
* @package Zend_Amf
|
||||||
|
* @subpackage Parse
|
||||||
|
* @copyright Copyright (c) 2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||||||
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||||
|
*/
|
||||||
|
class Zend_Amf_Parse_Resource_MysqlResult
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var array List of Mysql types with PHP counterparts
|
||||||
|
*
|
||||||
|
* Key => Value is Mysql type (exact string) => PHP type
|
||||||
|
*/
|
||||||
|
static public $fieldTypes = array(
|
||||||
|
"int" => "int",
|
||||||
|
"timestamp" => "int",
|
||||||
|
"year" => "int",
|
||||||
|
"real" => "float",
|
||||||
|
);
|
||||||
|
/**
|
||||||
|
* Parse resource into array
|
||||||
|
*
|
||||||
|
* @param resource $resource
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function parse($resource) {
|
||||||
|
$result = array();
|
||||||
|
$fieldcnt = mysql_num_fields($resource);
|
||||||
|
$fields_transform = array();
|
||||||
|
for($i=0;$i<$fieldcnt;$i++) {
|
||||||
|
$type = mysql_field_type($resource, $i);
|
||||||
|
if(isset(self::$fieldTypes[$type])) {
|
||||||
|
$fields_transform[mysql_field_name($resource, $i)] = self::$fieldTypes[$type];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while($row = mysql_fetch_assoc($resource)) {
|
||||||
|
foreach($fields_transform as $fieldname => $fieldtype) {
|
||||||
|
settype($row[$fieldname], $fieldtype);
|
||||||
|
}
|
||||||
|
$result[] = $row;
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
127
libs/Zend/Amf/Parse/Resource/MysqliResult.php
Normal file
127
libs/Zend/Amf/Parse/Resource/MysqliResult.php
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Zend Framework
|
||||||
|
*
|
||||||
|
* LICENSE
|
||||||
|
*
|
||||||
|
* This source file is subject to the new BSD license that is bundled
|
||||||
|
* with this package in the file LICENSE.txt.
|
||||||
|
* It is also available through the world-wide-web at this URL:
|
||||||
|
* http://framework.zend.com/license/new-bsd
|
||||||
|
* If you did not receive a copy of the license and are unable to
|
||||||
|
* obtain it through the world-wide-web, please send an email
|
||||||
|
* to license@zend.com so we can send you a copy immediately.
|
||||||
|
*
|
||||||
|
* @category Zend
|
||||||
|
* @package Zend_Amf
|
||||||
|
* @subpackage Parse
|
||||||
|
* @copyright Copyright (c) 2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||||||
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class will convert mysql result resource to array suitable for passing
|
||||||
|
* to the external entities.
|
||||||
|
*
|
||||||
|
* @package Zend_Amf
|
||||||
|
* @subpackage Parse
|
||||||
|
* @copyright Copyright (c) 2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||||||
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||||
|
*/
|
||||||
|
class Zend_Amf_Parse_Resource_MysqliResult
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mapping taken from http://forums.mysql.com/read.php?52,255868,255895#msg-255895
|
||||||
|
*/
|
||||||
|
static public $mysqli_type = array(
|
||||||
|
0 => "MYSQLI_TYPE_DECIMAL",
|
||||||
|
1 => "MYSQLI_TYPE_TINYINT",
|
||||||
|
2 => "MYSQLI_TYPE_SMALLINT",
|
||||||
|
3 => "MYSQLI_TYPE_INTEGER",
|
||||||
|
4 => "MYSQLI_TYPE_FLOAT",
|
||||||
|
5 => "MYSQLI_TYPE_DOUBLE",
|
||||||
|
7 => "MYSQLI_TYPE_TIMESTAMP",
|
||||||
|
8 => "MYSQLI_TYPE_BIGINT",
|
||||||
|
9 => "MYSQLI_TYPE_MEDIUMINT",
|
||||||
|
10 => "MYSQLI_TYPE_DATE",
|
||||||
|
11 => "MYSQLI_TYPE_TIME",
|
||||||
|
12 => "MYSQLI_TYPE_DATETIME",
|
||||||
|
13 => "MYSQLI_TYPE_YEAR",
|
||||||
|
14 => "MYSQLI_TYPE_DATE",
|
||||||
|
16 => "MYSQLI_TYPE_BIT",
|
||||||
|
246 => "MYSQLI_TYPE_DECIMAL",
|
||||||
|
247 => "MYSQLI_TYPE_ENUM",
|
||||||
|
248 => "MYSQLI_TYPE_SET",
|
||||||
|
249 => "MYSQLI_TYPE_TINYBLOB",
|
||||||
|
250 => "MYSQLI_TYPE_MEDIUMBLOB",
|
||||||
|
251 => "MYSQLI_TYPE_LONGBLOB",
|
||||||
|
252 => "MYSQLI_TYPE_BLOB",
|
||||||
|
253 => "MYSQLI_TYPE_VARCHAR",
|
||||||
|
254 => "MYSQLI_TYPE_CHAR",
|
||||||
|
255 => "MYSQLI_TYPE_GEOMETRY",
|
||||||
|
);
|
||||||
|
|
||||||
|
// Build an associative array for a type look up
|
||||||
|
static $mysqli_to_php = array(
|
||||||
|
"MYSQLI_TYPE_DECIMAL" => 'float',
|
||||||
|
"MYSQLI_TYPE_NEWDECIMAL" => 'float',
|
||||||
|
"MYSQLI_TYPE_BIT" => 'integer',
|
||||||
|
"MYSQLI_TYPE_TINYINT" => 'integer',
|
||||||
|
"MYSQLI_TYPE_SMALLINT" => 'integer',
|
||||||
|
"MYSQLI_TYPE_MEDIUMINT" => 'integer',
|
||||||
|
"MYSQLI_TYPE_BIGINT" => 'integer',
|
||||||
|
"MYSQLI_TYPE_INTEGER" => 'integer',
|
||||||
|
"MYSQLI_TYPE_FLOAT" => 'float',
|
||||||
|
"MYSQLI_TYPE_DOUBLE" => 'float',
|
||||||
|
"MYSQLI_TYPE_NULL" => 'null',
|
||||||
|
"MYSQLI_TYPE_TIMESTAMP" => 'string',
|
||||||
|
"MYSQLI_TYPE_INT24" => 'integer',
|
||||||
|
"MYSQLI_TYPE_DATE" => 'string',
|
||||||
|
"MYSQLI_TYPE_TIME" => 'string',
|
||||||
|
"MYSQLI_TYPE_DATETIME" => 'string',
|
||||||
|
"MYSQLI_TYPE_YEAR" => 'string',
|
||||||
|
"MYSQLI_TYPE_NEWDATE" => 'string',
|
||||||
|
"MYSQLI_TYPE_ENUM" => 'string',
|
||||||
|
"MYSQLI_TYPE_SET" => 'string',
|
||||||
|
"MYSQLI_TYPE_TINYBLOB" => 'object',
|
||||||
|
"MYSQLI_TYPE_MEDIUMBLOB" => 'object',
|
||||||
|
"MYSQLI_TYPE_LONGBLOB" => 'object',
|
||||||
|
"MYSQLI_TYPE_BLOB" => 'object',
|
||||||
|
"MYSQLI_TYPE_CHAR" => 'string',
|
||||||
|
"MYSQLI_TYPE_VARCHAR" => 'string',
|
||||||
|
"MYSQLI_TYPE_GEOMETRY" => 'object',
|
||||||
|
"MYSQLI_TYPE_BIT" => 'integer',
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse resource into array
|
||||||
|
*
|
||||||
|
* @param resource $resource
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function parse($resource) {
|
||||||
|
|
||||||
|
$result = array();
|
||||||
|
$fieldcnt = mysqli_num_fields($resource);
|
||||||
|
|
||||||
|
|
||||||
|
$fields_transform = array();
|
||||||
|
|
||||||
|
for($i=0;$i<$fieldcnt;$i++) {
|
||||||
|
$finfo = mysqli_fetch_field_direct($resource, $i);
|
||||||
|
|
||||||
|
if(isset(self::$mysqli_type[$finfo->type])) {
|
||||||
|
$fields_transform[$finfo->name] = self::$mysqli_to_php[self::$mysqli_type[$finfo->type]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while($row = mysqli_fetch_assoc($resource)) {
|
||||||
|
foreach($fields_transform as $fieldname => $fieldtype) {
|
||||||
|
settype($row[$fieldname], $fieldtype);
|
||||||
|
}
|
||||||
|
$result[] = $row;
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
41
libs/Zend/Amf/Parse/Resource/Stream.php
Executable file
41
libs/Zend/Amf/Parse/Resource/Stream.php
Executable file
@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Zend Framework
|
||||||
|
*
|
||||||
|
* LICENSE
|
||||||
|
*
|
||||||
|
* This source file is subject to the new BSD license that is bundled
|
||||||
|
* with this package in the file LICENSE.txt.
|
||||||
|
* It is also available through the world-wide-web at this URL:
|
||||||
|
* http://framework.zend.com/license/new-bsd
|
||||||
|
* If you did not receive a copy of the license and are unable to
|
||||||
|
* obtain it through the world-wide-web, please send an email
|
||||||
|
* to license@zend.com so we can send you a copy immediately.
|
||||||
|
*
|
||||||
|
* @category Zend
|
||||||
|
* @package Zend_Amf
|
||||||
|
* @subpackage Parse
|
||||||
|
* @copyright Copyright (c) 2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||||||
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class will convert stream resource to string by just reading it
|
||||||
|
*
|
||||||
|
* @package Zend_Amf
|
||||||
|
* @subpackage Parse
|
||||||
|
* @copyright Copyright (c) 2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||||||
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||||
|
*/
|
||||||
|
class Zend_Amf_Parse_Resource_Stream
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Parse resource into string
|
||||||
|
*
|
||||||
|
* @param resource $resource Stream resource
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function parse($resource) {
|
||||||
|
return stream_get_contents($resource);
|
||||||
|
}
|
||||||
|
}
|
@ -15,7 +15,7 @@
|
|||||||
* @category Zend
|
* @category Zend
|
||||||
* @package Zend_Amf
|
* @package Zend_Amf
|
||||||
* @subpackage Parse
|
* @subpackage Parse
|
||||||
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
|
* @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||||||
* @license http://framework.zend.com/license/new-bsd New BSD License
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -24,7 +24,7 @@
|
|||||||
*
|
*
|
||||||
* @package Zend_Amf
|
* @package Zend_Amf
|
||||||
* @subpackage Parse
|
* @subpackage Parse
|
||||||
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
|
* @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||||||
* @license http://framework.zend.com/license/new-bsd New BSD License
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||||
*/
|
*/
|
||||||
abstract class Zend_Amf_Parse_Serializer
|
abstract class Zend_Amf_Parse_Serializer
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
* @category Zend
|
* @category Zend
|
||||||
* @package Zend_Amf
|
* @package Zend_Amf
|
||||||
* @subpackage Parse
|
* @subpackage Parse
|
||||||
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
|
* @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||||||
* @license http://framework.zend.com/license/new-bsd New BSD License
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ require_once 'Zend/Amf/Value/Messaging/RemotingMessage.php';
|
|||||||
* @todo PHP 5.3 can drastically change this class w/ namespace and the new call_user_func w/ namespace
|
* @todo PHP 5.3 can drastically change this class w/ namespace and the new call_user_func w/ namespace
|
||||||
* @package Zend_Amf
|
* @package Zend_Amf
|
||||||
* @subpackage Parse
|
* @subpackage Parse
|
||||||
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
|
* @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||||||
* @license http://framework.zend.com/license/new-bsd New BSD License
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||||
*/
|
*/
|
||||||
final class Zend_Amf_Parse_TypeLoader
|
final class Zend_Amf_Parse_TypeLoader
|
||||||
@ -50,6 +50,7 @@ final class Zend_Amf_Parse_TypeLoader
|
|||||||
'flex.messaging.messages.CommandMessage' => 'Zend_Amf_Value_Messaging_CommandMessage',
|
'flex.messaging.messages.CommandMessage' => 'Zend_Amf_Value_Messaging_CommandMessage',
|
||||||
'flex.messaging.messages.ErrorMessage' => 'Zend_Amf_Value_Messaging_ErrorMessage',
|
'flex.messaging.messages.ErrorMessage' => 'Zend_Amf_Value_Messaging_ErrorMessage',
|
||||||
'flex.messaging.messages.RemotingMessage' => 'Zend_Amf_Value_Messaging_RemotingMessage',
|
'flex.messaging.messages.RemotingMessage' => 'Zend_Amf_Value_Messaging_RemotingMessage',
|
||||||
|
'flex.messaging.io.ArrayCollection' => 'Zend_Amf_Value_Messaging_ArrayCollection',
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -61,7 +62,14 @@ final class Zend_Amf_Parse_TypeLoader
|
|||||||
'flex.messaging.messages.CommandMessage' => 'Zend_Amf_Value_Messaging_CommandMessage',
|
'flex.messaging.messages.CommandMessage' => 'Zend_Amf_Value_Messaging_CommandMessage',
|
||||||
'flex.messaging.messages.ErrorMessage' => 'Zend_Amf_Value_Messaging_ErrorMessage',
|
'flex.messaging.messages.ErrorMessage' => 'Zend_Amf_Value_Messaging_ErrorMessage',
|
||||||
'flex.messaging.messages.RemotingMessage' => 'Zend_Amf_Value_Messaging_RemotingMessage',
|
'flex.messaging.messages.RemotingMessage' => 'Zend_Amf_Value_Messaging_RemotingMessage',
|
||||||
|
'flex.messaging.io.ArrayCollection' => 'Zend_Amf_Value_Messaging_ArrayCollection',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Zend_Loader_PluginLoader_Interface
|
||||||
|
*/
|
||||||
|
protected static $_resourceLoader = null;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load the mapped class type into a callback.
|
* Load the mapped class type into a callback.
|
||||||
@ -71,14 +79,13 @@ final class Zend_Amf_Parse_TypeLoader
|
|||||||
*/
|
*/
|
||||||
public static function loadType($className)
|
public static function loadType($className)
|
||||||
{
|
{
|
||||||
$class = false;
|
|
||||||
$callBack = false;
|
|
||||||
$class = self::getMappedClassName($className);
|
$class = self::getMappedClassName($className);
|
||||||
if (!class_exists($class)) {
|
if(!$class) {
|
||||||
require_once 'Zend/Amf/Exception.php';
|
$class = str_replace('.', '_', $className);
|
||||||
throw new Zend_Amf_Exception($className .' mapped class '. $class . ' is not defined');
|
}
|
||||||
|
if (!class_exists($class)) {
|
||||||
|
return "stdClass";
|
||||||
}
|
}
|
||||||
|
|
||||||
return $class;
|
return $class;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,4 +137,79 @@ final class Zend_Amf_Parse_TypeLoader
|
|||||||
{
|
{
|
||||||
self::$classMap = self::$_defaultClassMap;
|
self::$classMap = self::$_defaultClassMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set loader for resource type handlers
|
||||||
|
*
|
||||||
|
* @param Zend_Loader_PluginLoader_Interface $loader
|
||||||
|
*/
|
||||||
|
public static function setResourceLoader(Zend_Loader_PluginLoader_Interface $loader)
|
||||||
|
{
|
||||||
|
self::$_resourceLoader = $loader;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add directory to the list of places where to look for resource handlers
|
||||||
|
*
|
||||||
|
* @param string $prefix
|
||||||
|
* @param string $dir
|
||||||
|
*/
|
||||||
|
public static function addResourceDirectory($prefix, $dir)
|
||||||
|
{
|
||||||
|
if(self::$_resourceLoader) {
|
||||||
|
self::$_resourceLoader->addPrefixPath($prefix, $dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get plugin class that handles this resource
|
||||||
|
*
|
||||||
|
* @param resource $resource Resource type
|
||||||
|
* @return string Class name
|
||||||
|
*/
|
||||||
|
public static function getResourceParser($resource)
|
||||||
|
{
|
||||||
|
if(self::$_resourceLoader) {
|
||||||
|
$type = preg_replace("/[^A-Za-z0-9_]/", " ", get_resource_type($resource));
|
||||||
|
$type = str_replace(" ","", ucwords($type));
|
||||||
|
return self::$_resourceLoader->load($type);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert resource to a serializable object
|
||||||
|
*
|
||||||
|
* @param resource $resource
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public static function handleResource($resource)
|
||||||
|
{
|
||||||
|
if(!self::$_resourceLoader) {
|
||||||
|
require_once 'Zend/Amf/Exception.php';
|
||||||
|
throw new Zend_Amf_Exception('Unable to handle resources - resource plugin loader not set');
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
while(is_resource($resource)) {
|
||||||
|
$resclass = self::getResourceParser($resource);
|
||||||
|
if(!$resclass) {
|
||||||
|
require_once 'Zend/Amf/Exception.php';
|
||||||
|
throw new Zend_Amf_Exception('Can not serialize resource type: '. get_resource_type($resource));
|
||||||
|
}
|
||||||
|
$parser = new $resclass();
|
||||||
|
if(is_callable(array($parser, 'parse'))) {
|
||||||
|
$resource = $parser->parse($resource);
|
||||||
|
} else {
|
||||||
|
require_once 'Zend/Amf/Exception.php';
|
||||||
|
throw new Zend_Amf_Exception("Could not call parse() method on class $resclass");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $resource;
|
||||||
|
} catch(Zend_Amf_Exception $e) {
|
||||||
|
throw $e;
|
||||||
|
} catch(Exception $e) {
|
||||||
|
require_once 'Zend/Amf/Exception.php';
|
||||||
|
throw new Zend_Amf_Exception('Can not serialize resource type: '. get_resource_type($resource));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user