<?php
function id_init(&$a) {
logger('id: ' . print_r($_REQUEST,true));
/**
* This example shows several things:
* - How a setup interface should look like.
* - How to use a mysql table for authentication
* - How to store associations in mysql table, instead of php sessions.
* - How to store realm authorizations.
* - How to send AX/SREG parameters.
* For the example to work, you need to create the necessary tables:
CREATE TABLE Users (
id INT NOT NULL auto_increment PRIMARY KEY,
login VARCHAR(32) NOT NULL,
password CHAR(40) NOT NULL,
firstName VARCHAR(32) NOT NULL,
lastName VARCHAR(32) NOT NULL
);
CREATE TABLE AllowedSites (
user INT NOT NULL,
realm TEXT NOT NULL,
attributes TEXT NOT NULL,
INDEX(user)
);
CREATE TABLE Associations (
id INT NOT NULL PRIMARY KEY,
data TEXT NOT NULL
);
*
* This is only an example. Don't use it in your code as-is.
* It has several security flaws, which you shouldn't copy (like storing plaintext login and password in forms).
*
* This setup could be very easily flooded with many associations,
* since non-private ones aren't automatically deleted.
* You could prevent this by storing a date of association and removing old ones,
* or by setting $this->dh = false;
* However, the latter one would disable stateful mode, unless connecting via HTTPS.
*/
require 'library/openid/provider/provider.php';
function getUserData($handle=null)
{
if(! local_channel()) {
notice( t('Permission denied.') . EOL);
get_app()->page['content'] = login();
return false;
}
// logger('handle: ' . $handle);
if($handle) {
$r = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_address = '%s' limit 1",
dbesc($handle)
);
}
else {
$r = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_id = %d",
intval(local_channel())
);
}
if(! r)
return false;
$x = q("select * from account where account_id = %d limit 1",
intval($r[0]['channel_account_id'])
);
if($x)
$r[0]['email'] = $x[0]['account_email'];
$p = q("select * from profile where is_default = 1 and uid = %d limit 1",
intval($r[0]['channel_account_id'])
);
$gender = '';
if($p[0]['gender'] == t('Male'))
$gender = 'M';
if($p[0]['gender'] == t('Female'))
$gender = 'F';
$r[0]['firstName'] = ((strpos($r[0]['channel_name'],' ')) ? substr($r[0]['channel_name'],0,strpos($r[0]['channel_name'],' ')) : $r[0]['channel_name']);
$r[0]['lastName'] = ((strpos($r[0]['channel_name'],' ')) ? substr($r[0]['channel_name'],strpos($r[0]['channel_name'],' ')+1) : '');
$r[0]['namePerson'] = $r[0]['channel_name'];
$r[0]['pphoto'] = $r[0]['xchan_photo_l'];
$r[0]['pphoto16'] = z_root() . '/photo/profile/16/' . $r[0]['channel_id'] . '.jpg';
$r[0]['pphoto32'] = z_root() . '/photo/profile/32/' . $r[0]['channel_id'] . '.jpg';
$r[0]['pphoto48'] = z_root() . '/photo/profile/48/' . $r[0]['channel_id'] . '.jpg';
$r[0]['pphoto64'] = z_root() . '/photo/profile/64/' . $r[0]['channel_id'] . '.jpg';
$r[0]['pphoto80'] = z_root() . '/photo/profile/80/' . $r[0]['channel_id'] . '.jpg';
$r[0]['pphoto128'] = z_root() . '/photo/profile/128/' . $r[0]['channel_id'] . '.jpg';
$r[0]['timezone'] = $r[0]['channel_timezone'];
$r[0]['url'] = $r[0]['xchan_url'];
$r[0]['language'] = (($x[0]['account_language']) ? $x[0]['account_language'] : 'en');
$r[0]['birthyear'] = ((intval(substr($p[0]['dob'],0,4))) ? intval(substr($p[0]['dob'],0,4)) : '');
$r[0]['birthmonth'] = ((intval(substr($p[0]['dob'],5,2))) ? intval(substr($p[0]['dob'],5,2)) : '');
$r[0]['birthday'] = ((intval(substr($p[0]['dob'],8,2))) ? intval(substr($p[0]['dob'],8,2)) : '');
$r[0]['birthdate'] = (($r[0]['birthyear'] && $r[0]['birthmonth'] && $r[0]['birthday']) ? $p[0]['dob'] : '');
$r[0]['gender'] = $gender;
return $r[0];
/*
if(isset($_POST['login'],$_POST['password'])) {
$login = mysql_real_escape_string($_POST['login']);
$password = sha1($_POST['password']);
$q = mysql_query("SELECT * FROM Users WHERE login = '$login' AND password = '$password'");
if($data = mysql_fetch_assoc($q)) {
return $data;
}
if($handle) {
echo 'Wrong login/password.';
}
}
if($handle) {
?>
<form action="" method="post">
<input type="hidden" name="openid.assoc_handle" value="<?php echo $handle?>">
Login: <input type="text" name="login"><br>
Password: <input type="password" name="password"><br>
<button>Submit</button>
</form>
<?php
die();
}
*/
}
function translate_regs() {
// This exists to get around scoping rules
$attrMap = array(
'namePerson/first' => t('First Name'),
'namePerson/last' => t('Last Name'),
'namePerson/friendly' => t('Nickname'),
'namePerson' => t('Full Name'),
'contact/internet/email' => t('Email'),
'contact/email' => t('Email'),
'media/image/aspect11' => t('Profile Photo'),
'media/image' => t('Profile Photo'),
'media/image/default' => t('Profile Photo'),
'media/image/16x16' => t('Profile Photo 16px'),
'media/image/32x32' => t('Profile Photo 32px'),
'media/image/48x48' => t('Profile Photo 48px'),
'media/image/64x64' => t('Profile Photo 64px'),
'media/image/80x80' => t('Profile Photo 80px'),
'media/image/128x128' => t('Profile Photo 128px'),
'timezone' => t('Timezone'),
'contact/web/default' => t('Homepage URL'),
'language/pref' => t('Language'),
'birthDate/birthYear' => t('Birth Year'),
'birthDate/birthMonth' => t('Birth Month'),
'birthDate/birthday' => t('Birth Day'),
'birthDate' => t('Birthdate'),
'gender' => t('Gender'),
);
return $attrMap;
}
class MysqlProvider extends LightOpenIDProvider
{
// See http://openid.net/specs/openid-attribute-properties-list-1_0-01.html
// This list contains a few variations of these attributes to maintain
// compatibility with legacy clients
private $attrMap = array(
'namePerson/first' => 'First Name',
'namePerson/last' => 'Last Name',
'namePerson/friendly' => 'Nickname',
'namePerson' => 'Full Name',
'contact/internet/email' => 'Email',
'contact/email' => 'Email',
'media/image/aspect11' => 'Profile Photo',
'media/image' => 'Profile Photo',
'media/image/default' => 'Profile Photo',
'media/image/16x16' => 'Profile Photo 16px',
'media/image/32x32' => 'Profile Photo 32px',
'media/image/48x48' => 'Profile Photo 48px',
'media/image/64x64' => 'Profile Photo 64px',
'media/image/80x80' => 'Profile Photo 80px',
'media/image/128x128' => 'Profile Photo 128px',
'timezone' => 'Timezone',
'contact/web/default' => 'Homepage URL',
'language/pref' => 'Language',
'birthDate/birthYear' => 'Birth Year',
'birthDate/birthMonth' => 'Birth Month',
'birthDate/birthday' => 'Birth Day',
'birthDate' => 'Birthdate',
'gender' => 'Gender',
);
private $attrFieldMap = array(
'namePerson/first' => 'firstName',
'namePerson/last' => 'lastName',
'namePerson/friendly' => 'channel_address',
'namePerson' => 'namePerson',
'contact/internet/email' => 'email',
'contact/email' => 'email',
'media/image/aspect11' => 'pphoto',
'media/image' => 'pphoto',
'media/image/default' => 'pphoto',
'media/image/16x16' => 'pphoto16',
'media/image/32x32' => 'pphoto32',
'media/image/48x48' => 'pphoto48',
'media/image/64x64' => 'pphoto64',
'media/image/80x80' => 'pphoto80',
'media/image/128x128' => 'pphoto128',
'timezone' => 'timezone',
'contact/web/default' => 'url',
'language/pref' => 'language',
'birthDate/birthYear' => 'birthyear',
'birthDate/birthMonth' => 'birthmonth',
'birthDate/birthday' => 'birthday',
'birthDate' => 'birthdate',
'gender' => 'gender',
);
function setup($identity, $realm, $assoc_handle, $attributes)
{
// logger('identity: ' . $identity);
// logger('realm: ' . $realm);
// logger('assoc_handle: ' . $assoc_handle);
// logger('attributes: ' . print_r($attributes,true));
$data = getUserData($assoc_handle);
$o .= '<form action="" method="post">'
. '<input type="hidden" name="openid.assoc_handle" value="' . $assoc_handle . '">'
. '<input type="hidden" name="login" value="' . $_POST['login'] .'">'
. '<input type="hidden" name="password" value="' . $_POST['password'] .'">'
. "<b>$realm</b> wishes to authenticate you.";
if($attributes['required'] || $attributes['optional']) {
$o .= " It also requests following information (required fields marked with *):"
. '<ul>';
foreach($attributes['required'] as $attr) {
if(isset($this->attrMap[$attr])) {
$o .= '<li>'
. '<input type="checkbox" name="attributes[' . $attr . ']"> '
. $this->attrMap[$attr] . ' <span class="required">*</span></li>';
}
}
foreach($attributes['optional'] as $attr) {
if(isset($this->attrMap[$attr])) {
$o .= '<li>'
. '<input type="checkbox" name="attributes[' . $attr . ']"> '
. $this->attrMap[$attr] . '</li>';
}
}
$o .= '</ul>';
}
$o .= '<br>'
. '<button name="once">Allow once</button> '
. '<button name="always">Always allow</button> '
. '<button name="cancel">cancel</button> '
. '</form>';
get_app()->page['content'] .= $o;
}
function checkid($realm, &$attributes)
{
logger('checkid: ' . $realm);
logger('checkid attrs: ' . print_r($attributes,true));
if(isset($_POST['cancel'])) {
$this->cancel();
}
$data = getUserData();
if(! $data) {
return false;
}
logger('checkid: checkpoint1');
$q = get_pconfig(local_channel(),'openid',$realm);
$attrs = array();
if($q) {
$attrs = $q;
} elseif(isset($_POST['attributes'])) {
$attrs = array_keys($_POST['attributes']);
} elseif(!isset($_POST['once']) && !isset($_POST['always'])) {
return false;
}
$attributes = array();
foreach($attrs as $attr) {
if(isset($this->attrFieldMap[$attr])) {
$attributes[$attr] = $data[$this->attrFieldMap[$attr]];
}
}
if(isset($_POST['always'])) {
set_pconfig(local_channel(),'openid',$realm,array_keys($attributes));
}
return z_root() . '/id/' . $data['channel_address'];
}
function assoc_handle()
{
$channel = get_app()->get_channel();
return z_root() . '/id/' . $channel['channel_address'];
}
function setAssoc($handle, $data)
{
logger('setAssoc');
$channel = channelx_by_nick(basename($handle));
if($channel)
set_pconfig($channel['channel_id'],'openid','associate',$data);
}
function getAssoc($handle)
{
logger('getAssoc: ' . $handle);
$channel = channelx_by_nick(basename($handle));
if($channel)
return get_pconfig($channel['channel_id'],'openid','associate');
return false;
}
function delAssoc($handle)
{
logger('delAssoc');
$channel = channelx_by_nick(basename($handle));
if($channel)
return del_pconfig($channel['channel_id'],'openid','associate');
}
}
$op = new MysqlProvider;
$op->server();
}