-
-
Save alfredwesterveld/8db49baec4e0deb03e4f to your computer and use it in GitHub Desktop.
lightopenid stripped
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class LightOpenID{ public $returnUrl,$required=array(),$optional=array(),$verify_peer=null,$capath=null,$cainfo=null; private $identity,$claimed_id; protected $server,$version,$trustRoot,$aliases,$identifier_select=false,$ax=false,$sreg=false,$data;static protected $ax_to_sreg=array('namePerson/friendly'=>'nickname','contact/email'=>'email','namePerson'=>'fullname','birthDate'=>'dob','person/gender'=>'gender','contact/postalCode/home'=>'postcode','contact/country/home'=>'country','pref/language'=>'language','pref/timezone'=>'timezone',);function __construct(){$this->trustRoot=(!empty($_SERVER['HTTPS'])?'https':'http').'://'.$_SERVER['HTTP_HOST'];$uri=rtrim(preg_replace('#((?<=\?)|&)openid\.[^&]+#','',$_SERVER['REQUEST_URI']),'?');$this->returnUrl=$this->trustRoot.$uri;$this->data=$_POST+$_GET;if(!function_exists('curl_init')&&!in_array('https',stream_get_wrappers())){ throw new ErrorException('You must have either https wrappers or curl enabled.');}}function __set($name,$value){switch($name){case 'identity':if(strlen($value=trim((String)$value))){if(preg_match('#^xri:/*#i',$value,$m)){$value=substr($value,strlen($m[0]));}elseif(!preg_match('/^(?:[=@+\$!\(]|https?:)/i',$value)){$value="http://$value";}if(preg_match('#^https?://[^/]+$#i',$value,$m)){$value.='/';}}$this->$name=$this->claimed_id=$value;break;case 'trustRoot':case 'realm':$this->trustRoot=trim($value);}}function __get($name){switch($name){case 'identity':return $this->claimed_id;case 'trustRoot':case 'realm':return $this->trustRoot;case 'mode':return empty($this->data['openid_mode'])?null:$this->data['openid_mode'];}} protected function request_curl($url,$method='GET',$params=array()){$params=http_build_query($params,'','&');$curl=curl_init($url.($method=='GET'&&$params?'?'.$params:''));curl_setopt($curl,CURLOPT_FOLLOWLOCATION,true);curl_setopt($curl,CURLOPT_HEADER,false);curl_setopt($curl,CURLOPT_SSL_VERIFYPEER,false);curl_setopt($curl,CURLOPT_RETURNTRANSFER,true);curl_setopt($curl,CURLOPT_HTTPHEADER,array('Accept: application/xrds+xml, */*'));if($this->verify_peer!==null){curl_setopt($curl,CURLOPT_SSL_VERIFYPEER,$this->verify_peer);if($this->capath){curl_setopt($curl,CURLOPT_CAPATH,$this->capath);}if($this->cainfo){curl_setopt($curl,CURLOPT_CAINFO,$this->cainfo);}}if($method=='POST'){curl_setopt($curl,CURLOPT_POST,true);curl_setopt($curl,CURLOPT_POSTFIELDS,$params);}elseif($method=='HEAD'){curl_setopt($curl,CURLOPT_HEADER,true);curl_setopt($curl,CURLOPT_NOBODY,true);}else {curl_setopt($curl,CURLOPT_HTTPGET,true);}$response=curl_exec($curl);if($method=='HEAD'){$headers=array();foreach(explode("\n",$response) as $header){$pos=strpos($header,':');$name=strtolower(trim(substr($header,0,$pos)));$headers[$name]=trim(substr($header,$pos+1));}$effective_url=curl_getinfo($curl,CURLINFO_EFFECTIVE_URL);if($effective_url!=$url){$this->identity=$this->claimed_id=$effective_url;}return $headers;}if(curl_errno($curl)){ throw new ErrorException(curl_error($curl),curl_errno($curl));}return $response;} protected function request($url,$method='GET',$params=array()){if(function_exists('curl_init')&&!ini_get('safe_mode')&&!ini_get('open_basedir')){return $this->request_curl($url,$method,$params);}} protected function build_url($url,$parts){if(isset($url['query'],$parts['query'])){$parts['query']=$url['query'].'&'.$parts['query'];}$url=$parts+$url;$url=$url['scheme'].'://'.(empty($url['username'])?'':(empty($url['password'])?"{$url['username']}@":"{$url['username']}:{$url['password']}@")).$url['host'].(empty($url['port'])?'':":{$url['port']}").(empty($url['path'])?'':$url['path']).(empty($url['query'])?'':"?{$url['query']}").(empty($url['fragment'])?'':"#{$url['fragment']}");return $url;} protected function htmlTag($content,$tag,$attrName,$attrValue,$valueName){preg_match_all("#<{$tag}[^>]*$attrName=['\"].*?$attrValue.*?['\"][^>]*$valueName=['\"](.+?)['\"][^>]*/?>#i",$content,$matches1);preg_match_all("#<{$tag}[^>]*$valueName=['\"](.+?)['\"][^>]*$attrName=['\"].*?$attrValue.*?['\"][^>]*/?>#i",$content,$matches2);$result=array_merge($matches1[1],$matches2[1]);return empty($result)?false:$result[0];}function discover($url){if(!$url) throw new ErrorException('No identity supplied.');if(!preg_match('#^https?:#',$url)){$url="https://xri.net/$url";}$originalUrl=$url;$yadis=true;for($i=0;$i<5;$i++){if($yadis){$headers=$this->request($url,'HEAD');$next=false;if(isset($headers['x-xrds-location'])){$url=$this->build_url(parse_url($url),parse_url(trim($headers['x-xrds-location'])));$next=true;}if(isset($headers['content-type'])&&(strpos($headers['content-type'],'application/xrds+xml')!==false||strpos($headers['content-type'],'text/xml')!==false)){$content=$this->request($url,'GET');preg_match_all('#<Service.*?>(.*?)</Service>#s',$content,$m);foreach($m[1] as $content){$content=' '.$content;$ns=preg_quote('http://specs.openid.net/auth/2.0/');if(preg_match('#<Type>\s*'.$ns.'(server|signon)\s*</Type>#s',$content,$type)){if($type[1]=='server')$this->identifier_select=true;preg_match('#<URI.*?>(.*)</URI>#',$content,$server);preg_match('#<(Local|Canonical)ID>(.*)</\1ID>#',$content,$delegate);if(empty($server)){return false;}$this->ax=(bool)strpos($content,'<Type>http://openid.net/srv/ax/1.0</Type>');$this->sreg=strpos($content,'<Type>http://openid.net/sreg/1.0</Type>')||strpos($content,'<Type>http://openid.net/extensions/sreg/1.1</Type>');$server=$server[1];if(isset($delegate[2]))$this->identity=trim($delegate[2]);$this->version=2;$this->server=$server;return $server;}$ns=preg_quote('http://openid.net/signon/1.1');if(preg_match('#<Type>\s*'.$ns.'\s*</Type>#s',$content)){preg_match('#<URI.*?>(.*)</URI>#',$content,$server);preg_match('#<.*?Delegate>(.*)</.*?Delegate>#',$content,$delegate);if(empty($server)){return false;}$this->sreg=strpos($content,'<Type>http://openid.net/sreg/1.0</Type>')||strpos($content,'<Type>http://openid.net/extensions/sreg/1.1</Type>');$server=$server[1];if(isset($delegate[1]))$this->identity=$delegate[1];$this->version=1;$this->server=$server;return $server;}}$next=true;$yadis=false;$url=$originalUrl;$content=null;break;}if($next)continue;$content=$this->request($url,'GET');$location=$this->htmlTag($content,'meta','http-equiv','X-XRDS-Location','content');if($location){$url=$this->build_url(parse_url($url),parse_url($location));continue;}}if(!$content)$content=$this->request($url,'GET');$server=$this->htmlTag($content,'link','rel','openid2.provider','href');$delegate=$this->htmlTag($content,'link','rel','openid2.local_id','href');$this->version=2;if(!$server){$server=$this->htmlTag($content,'link','rel','openid.server','href');$delegate=$this->htmlTag($content,'link','rel','openid.delegate','href');$this->version=1;}if($server){if($delegate){$this->identity=$delegate;}$this->server=$server;return $server;} throw new ErrorException('No servers found!');} throw new ErrorException('Endless redirection!');} protected function axParams(){$params=array();if($this->required||$this->optional){$params['openid.ns.ax']='http://openid.net/srv/ax/1.0';$params['openid.ax.mode']='fetch_request';$this->aliases=array();$counts=array();$required=array();$optional=array();foreach(array('required','optional') as $type){foreach($this->$type as $alias=>$field){if(is_int($alias))$alias=strtr($field,'/','_');$this->aliases[$alias]='http://axschema.org/'.$field;if(empty($counts[$alias]))$counts[$alias]=0;$counts[$alias]+=1;${$type}[]=$alias;}}foreach($this->aliases as $alias=>$ns){$params['openid.ax.type.'.$alias]=$ns;}foreach($counts as $alias=>$count){if($count==1)continue;$params['openid.ax.count.'.$alias]=$count;}if($required){$params['openid.ax.required']=implode(',',$required);}if($optional){$params['openid.ax.if_available']=implode(',',$optional);}}return $params;} protected function authUrl_v1(){$returnUrl=$this->returnUrl;if($this->identity!=$this->claimed_id){$returnUrl.=(strpos($returnUrl,'?')?'&':'?').'openid.claimed_id='.$this->claimed_id;}$params=array('openid.return_to'=>$returnUrl,'openid.mode'=>'checkid_setup','openid.identity'=>$this->identity,'openid.trust_root'=>$this->trustRoot,)+$this->sregParams();return $this->build_url(parse_url($this->server),array('query'=>http_build_query($params,'','&')));} protected function authUrl_v2($identifier_select){$params=array('openid.ns'=>'http://specs.openid.net/auth/2.0','openid.mode'=>'checkid_setup','openid.return_to'=>$this->returnUrl,'openid.realm'=>$this->trustRoot,);if($this->ax){$params+=$this->axParams();}if($this->sreg){$params+=$this->sregParams();}if(!$this->ax&&!$this->sreg){$params+=$this->axParams()+$this->sregParams();}if($identifier_select){$params['openid.identity']=$params['openid.claimed_id']='http://specs.openid.net/auth/2.0/identifier_select';}else {$params['openid.identity']=$this->identity;$params['openid.claimed_id']=$this->claimed_id;}return $this->build_url(parse_url($this->server),array('query'=>http_build_query($params,'','&')));}function authUrl($identifier_select=null){if(!$this->server)$this->discover($this->identity);if($this->version==2){if($identifier_select===null){return $this->authUrl_v2($this->identifier_select);}return $this->authUrl_v2($identifier_select);}return $this->authUrl_v1();}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class LightOpenID | |
{ | |
public $returnUrl | |
, $required = array() | |
, $optional = array() | |
, $verify_peer = null | |
, $capath = null | |
, $cainfo = null; | |
private $identity, $claimed_id; | |
protected $server, $version, $trustRoot, $aliases, $identifier_select = false | |
, $ax = false, $sreg = false, $data; | |
static protected $ax_to_sreg = array( | |
'namePerson/friendly' => 'nickname', | |
'contact/email' => 'email', | |
'namePerson' => 'fullname', | |
'birthDate' => 'dob', | |
'person/gender' => 'gender', | |
'contact/postalCode/home' => 'postcode', | |
'contact/country/home' => 'country', | |
'pref/language' => 'language', | |
'pref/timezone' => 'timezone', | |
); | |
function __construct() | |
{ | |
$this->trustRoot = (!empty($_SERVER['HTTPS']) ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST']; | |
$uri = rtrim(preg_replace('#((?<=\?)|&)openid\.[^&]+#', '', $_SERVER['REQUEST_URI']), '?'); | |
$this->returnUrl = $this->trustRoot . $uri; | |
$this->data = $_POST + $_GET; | |
if(!function_exists('curl_init') && !in_array('https', stream_get_wrappers())) { | |
throw new ErrorException('You must have either https wrappers or curl enabled.'); | |
} | |
} | |
function __set($name, $value) | |
{ | |
switch ($name) { | |
case 'identity': | |
if (strlen($value = trim((String) $value))) { | |
if (preg_match('#^xri:/*#i', $value, $m)) { | |
$value = substr($value, strlen($m[0])); | |
} elseif (!preg_match('/^(?:[=@+\$!\(]|https?:)/i', $value)) { | |
$value = "http://$value"; | |
} | |
if (preg_match('#^https?://[^/]+$#i', $value, $m)) { | |
$value .= '/'; | |
} | |
} | |
$this->$name = $this->claimed_id = $value; | |
break; | |
case 'trustRoot': | |
case 'realm': | |
$this->trustRoot = trim($value); | |
} | |
} | |
function __get($name) | |
{ | |
switch ($name) { | |
case 'identity': | |
return $this->claimed_id; | |
case 'trustRoot': | |
case 'realm': | |
return $this->trustRoot; | |
case 'mode': | |
return empty($this->data['openid_mode']) ? null : $this->data['openid_mode']; | |
} | |
} | |
protected function request_curl($url, $method='GET', $params=array()) | |
{ | |
$params = http_build_query($params, '', '&'); | |
$curl = curl_init($url . ($method == 'GET' && $params ? '?' . $params : '')); | |
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); | |
curl_setopt($curl, CURLOPT_HEADER, false); | |
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); | |
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); | |
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Accept: application/xrds+xml, */*')); | |
if($this->verify_peer !== null) { | |
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $this->verify_peer); | |
if($this->capath) { | |
curl_setopt($curl, CURLOPT_CAPATH, $this->capath); | |
} | |
if($this->cainfo) { | |
curl_setopt($curl, CURLOPT_CAINFO, $this->cainfo); | |
} | |
} | |
if ($method == 'POST') { | |
curl_setopt($curl, CURLOPT_POST, true); | |
curl_setopt($curl, CURLOPT_POSTFIELDS, $params); | |
} elseif ($method == 'HEAD') { | |
curl_setopt($curl, CURLOPT_HEADER, true); | |
curl_setopt($curl, CURLOPT_NOBODY, true); | |
} else { | |
curl_setopt($curl, CURLOPT_HTTPGET, true); | |
} | |
$response = curl_exec($curl); | |
if($method == 'HEAD') { | |
$headers = array(); | |
foreach(explode("\n", $response) as $header) { | |
$pos = strpos($header,':'); | |
$name = strtolower(trim(substr($header, 0, $pos))); | |
$headers[$name] = trim(substr($header, $pos+1)); | |
} | |
$effective_url = curl_getinfo($curl, CURLINFO_EFFECTIVE_URL); | |
if($effective_url != $url) { | |
$this->identity = $this->claimed_id = $effective_url; | |
} | |
return $headers; | |
} | |
if (curl_errno($curl)) { | |
throw new ErrorException(curl_error($curl), curl_errno($curl)); | |
} | |
return $response; | |
} | |
protected function request($url, $method='GET', $params=array()) | |
{ | |
if(function_exists('curl_init') && !ini_get('safe_mode') && !ini_get('open_basedir')) { | |
return $this->request_curl($url, $method, $params); | |
} | |
} | |
protected function build_url($url, $parts) | |
{ | |
if (isset($url['query'], $parts['query'])) { | |
$parts['query'] = $url['query'] . '&' . $parts['query']; | |
} | |
$url = $parts + $url; | |
$url = $url['scheme'] . '://' | |
. (empty($url['username'])?'' | |
:(empty($url['password'])? "{$url['username']}@" | |
:"{$url['username']}:{$url['password']}@")) | |
. $url['host'] | |
. (empty($url['port'])?'':":{$url['port']}") | |
. (empty($url['path'])?'':$url['path']) | |
. (empty($url['query'])?'':"?{$url['query']}") | |
. (empty($url['fragment'])?'':"#{$url['fragment']}"); | |
return $url; | |
} | |
protected function htmlTag($content, $tag, $attrName, $attrValue, $valueName) | |
{ | |
preg_match_all("#<{$tag}[^>]*$attrName=['\"].*?$attrValue.*?['\"][^>]*$valueName=['\"](.+?)['\"][^>]*/?>#i", $content, $matches1); | |
preg_match_all("#<{$tag}[^>]*$valueName=['\"](.+?)['\"][^>]*$attrName=['\"].*?$attrValue.*?['\"][^>]*/?>#i", $content, $matches2); | |
$result = array_merge($matches1[1], $matches2[1]); | |
return empty($result)?false:$result[0]; | |
} | |
function discover($url) | |
{ | |
if (!$url) throw new ErrorException('No identity supplied.'); | |
if (!preg_match('#^https?:#', $url)) { | |
$url = "https://xri.net/$url"; | |
} | |
$originalUrl = $url; | |
$yadis = true; | |
for ($i = 0; $i < 5; $i ++) { | |
if ($yadis) { | |
$headers = $this->request($url, 'HEAD'); | |
$next = false; | |
if (isset($headers['x-xrds-location'])) { | |
$url = $this->build_url(parse_url($url), parse_url(trim($headers['x-xrds-location']))); | |
$next = true; | |
} | |
if (isset($headers['content-type']) | |
&& (strpos($headers['content-type'], 'application/xrds+xml') !== false | |
|| strpos($headers['content-type'], 'text/xml') !== false) | |
) { | |
$content = $this->request($url, 'GET'); | |
preg_match_all('#<Service.*?>(.*?)</Service>#s', $content, $m); | |
foreach($m[1] as $content) { | |
$content = ' ' . $content; | |
$ns = preg_quote('http://specs.openid.net/auth/2.0/'); | |
if(preg_match('#<Type>\s*'.$ns.'(server|signon)\s*</Type>#s', $content, $type)) { | |
if ($type[1] == 'server') $this->identifier_select = true; | |
preg_match('#<URI.*?>(.*)</URI>#', $content, $server); | |
preg_match('#<(Local|Canonical)ID>(.*)</\1ID>#', $content, $delegate); | |
if (empty($server)) { | |
return false; | |
} | |
$this->ax = (bool) strpos($content, '<Type>http://openid.net/srv/ax/1.0</Type>'); | |
$this->sreg = strpos($content, '<Type>http://openid.net/sreg/1.0</Type>') | |
|| strpos($content, '<Type>http://openid.net/extensions/sreg/1.1</Type>'); | |
$server = $server[1]; | |
if (isset($delegate[2])) $this->identity = trim($delegate[2]); | |
$this->version = 2; | |
$this->server = $server; | |
return $server; | |
} | |
$ns = preg_quote('http://openid.net/signon/1.1'); | |
if (preg_match('#<Type>\s*'.$ns.'\s*</Type>#s', $content)) { | |
preg_match('#<URI.*?>(.*)</URI>#', $content, $server); | |
preg_match('#<.*?Delegate>(.*)</.*?Delegate>#', $content, $delegate); | |
if (empty($server)) { | |
return false; | |
} | |
$this->sreg = strpos($content, '<Type>http://openid.net/sreg/1.0</Type>') | |
|| strpos($content, '<Type>http://openid.net/extensions/sreg/1.1</Type>'); | |
$server = $server[1]; | |
if (isset($delegate[1])) $this->identity = $delegate[1]; | |
$this->version = 1; | |
$this->server = $server; | |
return $server; | |
} | |
} | |
$next = true; | |
$yadis = false; | |
$url = $originalUrl; | |
$content = null; | |
break; | |
} | |
if ($next) continue; | |
$content = $this->request($url, 'GET'); | |
$location = $this->htmlTag($content, 'meta', 'http-equiv', 'X-XRDS-Location', 'content'); | |
if ($location) { | |
$url = $this->build_url(parse_url($url), parse_url($location)); | |
continue; | |
} | |
} | |
if (!$content) $content = $this->request($url, 'GET'); | |
$server = $this->htmlTag($content, 'link', 'rel', 'openid2.provider', 'href'); | |
$delegate = $this->htmlTag($content, 'link', 'rel', 'openid2.local_id', 'href'); | |
$this->version = 2; | |
if (!$server) { | |
$server = $this->htmlTag($content, 'link', 'rel', 'openid.server', 'href'); | |
$delegate = $this->htmlTag($content, 'link', 'rel', 'openid.delegate', 'href'); | |
$this->version = 1; | |
} | |
if ($server) { | |
if ($delegate) { | |
$this->identity = $delegate; | |
} | |
$this->server = $server; | |
return $server; | |
} | |
throw new ErrorException('No servers found!'); | |
} | |
throw new ErrorException('Endless redirection!'); | |
} | |
protected function axParams() | |
{ | |
$params = array(); | |
if ($this->required || $this->optional) { | |
$params['openid.ns.ax'] = 'http://openid.net/srv/ax/1.0'; | |
$params['openid.ax.mode'] = 'fetch_request'; | |
$this->aliases = array(); | |
$counts = array(); | |
$required = array(); | |
$optional = array(); | |
foreach (array('required','optional') as $type) { | |
foreach ($this->$type as $alias => $field) { | |
if (is_int($alias)) $alias = strtr($field, '/', '_'); | |
$this->aliases[$alias] = 'http://axschema.org/' . $field; | |
if (empty($counts[$alias])) $counts[$alias] = 0; | |
$counts[$alias] += 1; | |
${$type}[] = $alias; | |
} | |
} | |
foreach ($this->aliases as $alias => $ns) { | |
$params['openid.ax.type.' . $alias] = $ns; | |
} | |
foreach ($counts as $alias => $count) { | |
if ($count == 1) continue; | |
$params['openid.ax.count.' . $alias] = $count; | |
} | |
if($required) { | |
$params['openid.ax.required'] = implode(',', $required); | |
} | |
if($optional) { | |
$params['openid.ax.if_available'] = implode(',', $optional); | |
} | |
} | |
return $params; | |
} | |
protected function authUrl_v1() | |
{ | |
$returnUrl = $this->returnUrl; | |
if($this->identity != $this->claimed_id) { | |
$returnUrl .= (strpos($returnUrl, '?') ? '&' : '?') . 'openid.claimed_id=' . $this->claimed_id; | |
} | |
$params = array( | |
'openid.return_to' => $returnUrl, | |
'openid.mode' => 'checkid_setup', | |
'openid.identity' => $this->identity, | |
'openid.trust_root' => $this->trustRoot, | |
) + $this->sregParams(); | |
return $this->build_url(parse_url($this->server) | |
, array('query' => http_build_query($params, '', '&'))); | |
} | |
protected function authUrl_v2($identifier_select) | |
{ | |
$params = array( | |
'openid.ns' => 'http://specs.openid.net/auth/2.0', | |
'openid.mode' => 'checkid_setup', | |
'openid.return_to' => $this->returnUrl, | |
'openid.realm' => $this->trustRoot, | |
); | |
if ($this->ax) { | |
$params += $this->axParams(); | |
} | |
if ($this->sreg) { | |
$params += $this->sregParams(); | |
} | |
if (!$this->ax && !$this->sreg) { | |
$params += $this->axParams() + $this->sregParams(); | |
} | |
if ($identifier_select) { | |
$params['openid.identity'] = $params['openid.claimed_id'] | |
= 'http://specs.openid.net/auth/2.0/identifier_select'; | |
} else { | |
$params['openid.identity'] = $this->identity; | |
$params['openid.claimed_id'] = $this->claimed_id; | |
} | |
return $this->build_url(parse_url($this->server) | |
, array('query' => http_build_query($params, '', '&'))); | |
} | |
function authUrl($identifier_select = null) | |
{ | |
if (!$this->server) $this->discover($this->identity); | |
if ($this->version == 2) { | |
if ($identifier_select === null) { | |
return $this->authUrl_v2($this->identifier_select); | |
} | |
return $this->authUrl_v2($identifier_select); | |
} | |
return $this->authUrl_v1(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class LightOpenID | |
{ | |
public $returnUrl | |
, $required = array() | |
, $optional = array() | |
, $verify_peer = null | |
, $capath = null | |
, $cainfo = null; | |
private $identity, $claimed_id; | |
protected $server, $version, $trustRoot, $aliases, $identifier_select = false | |
, $ax = false, $sreg = false, $data; | |
static protected $ax_to_sreg = array( | |
'namePerson/friendly' => 'nickname', | |
'contact/email' => 'email', | |
'namePerson' => 'fullname', | |
'birthDate' => 'dob', | |
'person/gender' => 'gender', | |
'contact/postalCode/home' => 'postcode', | |
'contact/country/home' => 'country', | |
'pref/language' => 'language', | |
'pref/timezone' => 'timezone', | |
); | |
function __construct() | |
{ | |
$this->trustRoot = (!empty($_SERVER['HTTPS']) ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST']; | |
$uri = rtrim(preg_replace('#((?<=\?)|&)openid\.[^&]+#', '', $_SERVER['REQUEST_URI']), '?'); | |
$this->returnUrl = $this->trustRoot . $uri; | |
$this->data = $_POST + $_GET; | |
if(!function_exists('curl_init') && !in_array('https', stream_get_wrappers())) { | |
throw new ErrorException('You must have either https wrappers or curl enabled.'); | |
} | |
} | |
function __set($name, $value) | |
{ | |
switch ($name) { | |
case 'identity': | |
if (strlen($value = trim((String) $value))) { | |
if (preg_match('#^xri:/*#i', $value, $m)) { | |
$value = substr($value, strlen($m[0])); | |
} elseif (!preg_match('/^(?:[=@+\$!\(]|https?:)/i', $value)) { | |
$value = "http://$value"; | |
} | |
if (preg_match('#^https?://[^/]+$#i', $value, $m)) { | |
$value .= '/'; | |
} | |
} | |
$this->$name = $this->claimed_id = $value; | |
break; | |
case 'trustRoot': | |
case 'realm': | |
$this->trustRoot = trim($value); | |
} | |
} | |
function __get($name) | |
{ | |
switch ($name) { | |
case 'identity': | |
return $this->claimed_id; | |
case 'trustRoot': | |
case 'realm': | |
return $this->trustRoot; | |
case 'mode': | |
return empty($this->data['openid_mode']) ? null : $this->data['openid_mode']; | |
} | |
} | |
protected function request_curl($url, $method='GET', $params=array()) | |
{ | |
$params = http_build_query($params, '', '&'); | |
$curl = curl_init($url . ($method == 'GET' && $params ? '?' . $params : '')); | |
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); | |
curl_setopt($curl, CURLOPT_HEADER, false); | |
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); | |
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); | |
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Accept: application/xrds+xml, */*')); | |
if($this->verify_peer !== null) { | |
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $this->verify_peer); | |
if($this->capath) { | |
curl_setopt($curl, CURLOPT_CAPATH, $this->capath); | |
} | |
if($this->cainfo) { | |
curl_setopt($curl, CURLOPT_CAINFO, $this->cainfo); | |
} | |
} | |
if ($method == 'POST') { | |
curl_setopt($curl, CURLOPT_POST, true); | |
curl_setopt($curl, CURLOPT_POSTFIELDS, $params); | |
} elseif ($method == 'HEAD') { | |
curl_setopt($curl, CURLOPT_HEADER, true); | |
curl_setopt($curl, CURLOPT_NOBODY, true); | |
} else { | |
curl_setopt($curl, CURLOPT_HTTPGET, true); | |
} | |
$response = curl_exec($curl); | |
if($method == 'HEAD') { | |
$headers = array(); | |
foreach(explode("\n", $response) as $header) { | |
$pos = strpos($header,':'); | |
$name = strtolower(trim(substr($header, 0, $pos))); | |
$headers[$name] = trim(substr($header, $pos+1)); | |
} | |
$effective_url = curl_getinfo($curl, CURLINFO_EFFECTIVE_URL); | |
if($effective_url != $url) { | |
$this->identity = $this->claimed_id = $effective_url; | |
} | |
return $headers; | |
} | |
if (curl_errno($curl)) { | |
throw new ErrorException(curl_error($curl), curl_errno($curl)); | |
} | |
return $response; | |
} | |
protected function request($url, $method='GET', $params=array()) | |
{ | |
if(function_exists('curl_init') && !ini_get('safe_mode') && !ini_get('open_basedir')) { | |
return $this->request_curl($url, $method, $params); | |
} | |
} | |
protected function build_url($url, $parts) | |
{ | |
if (isset($url['query'], $parts['query'])) { | |
$parts['query'] = $url['query'] . '&' . $parts['query']; | |
} | |
$url = $parts + $url; | |
$url = $url['scheme'] . '://' | |
. (empty($url['username'])?'' | |
:(empty($url['password'])? "{$url['username']}@" | |
:"{$url['username']}:{$url['password']}@")) | |
. $url['host'] | |
. (empty($url['port'])?'':":{$url['port']}") | |
. (empty($url['path'])?'':$url['path']) | |
. (empty($url['query'])?'':"?{$url['query']}") | |
. (empty($url['fragment'])?'':"#{$url['fragment']}"); | |
return $url; | |
} | |
protected function htmlTag($content, $tag, $attrName, $attrValue, $valueName) | |
{ | |
preg_match_all("#<{$tag}[^>]*$attrName=['\"].*?$attrValue.*?['\"][^>]*$valueName=['\"](.+?)['\"][^>]*/?>#i", $content, $matches1); | |
preg_match_all("#<{$tag}[^>]*$valueName=['\"](.+?)['\"][^>]*$attrName=['\"].*?$attrValue.*?['\"][^>]*/?>#i", $content, $matches2); | |
$result = array_merge($matches1[1], $matches2[1]); | |
return empty($result)?false:$result[0]; | |
} | |
function discover($url) | |
{ | |
if (!$url) throw new ErrorException('No identity supplied.'); | |
if (!preg_match('#^https?:#', $url)) { | |
$url = "https://xri.net/$url"; | |
} | |
$originalUrl = $url; | |
$yadis = true; | |
for ($i = 0; $i < 5; $i ++) { | |
if ($yadis) { | |
$headers = $this->request($url, 'HEAD'); | |
$next = false; | |
if (isset($headers['x-xrds-location'])) { | |
$url = $this->build_url(parse_url($url), parse_url(trim($headers['x-xrds-location']))); | |
$next = true; | |
} | |
if (isset($headers['content-type']) | |
&& (strpos($headers['content-type'], 'application/xrds+xml') !== false | |
|| strpos($headers['content-type'], 'text/xml') !== false) | |
) { | |
$content = $this->request($url, 'GET'); | |
preg_match_all('#<Service.*?>(.*?)</Service>#s', $content, $m); | |
foreach($m[1] as $content) { | |
$content = ' ' . $content; | |
$ns = preg_quote('http://specs.openid.net/auth/2.0/'); | |
if(preg_match('#<Type>\s*'.$ns.'(server|signon)\s*</Type>#s', $content, $type)) { | |
if ($type[1] == 'server') $this->identifier_select = true; | |
preg_match('#<URI.*?>(.*)</URI>#', $content, $server); | |
preg_match('#<(Local|Canonical)ID>(.*)</\1ID>#', $content, $delegate); | |
if (empty($server)) { | |
return false; | |
} | |
$this->ax = (bool) strpos($content, '<Type>http://openid.net/srv/ax/1.0</Type>'); | |
$this->sreg = strpos($content, '<Type>http://openid.net/sreg/1.0</Type>') | |
|| strpos($content, '<Type>http://openid.net/extensions/sreg/1.1</Type>'); | |
$server = $server[1]; | |
if (isset($delegate[2])) $this->identity = trim($delegate[2]); | |
$this->version = 2; | |
$this->server = $server; | |
return $server; | |
} | |
$ns = preg_quote('http://openid.net/signon/1.1'); | |
if (preg_match('#<Type>\s*'.$ns.'\s*</Type>#s', $content)) { | |
preg_match('#<URI.*?>(.*)</URI>#', $content, $server); | |
preg_match('#<.*?Delegate>(.*)</.*?Delegate>#', $content, $delegate); | |
if (empty($server)) { | |
return false; | |
} | |
$this->sreg = strpos($content, '<Type>http://openid.net/sreg/1.0</Type>') | |
|| strpos($content, '<Type>http://openid.net/extensions/sreg/1.1</Type>'); | |
$server = $server[1]; | |
if (isset($delegate[1])) $this->identity = $delegate[1]; | |
$this->version = 1; | |
$this->server = $server; | |
return $server; | |
} | |
} | |
$next = true; | |
$yadis = false; | |
$url = $originalUrl; | |
$content = null; | |
break; | |
} | |
if ($next) continue; | |
$content = $this->request($url, 'GET'); | |
$location = $this->htmlTag($content, 'meta', 'http-equiv', 'X-XRDS-Location', 'content'); | |
if ($location) { | |
$url = $this->build_url(parse_url($url), parse_url($location)); | |
continue; | |
} | |
} | |
if (!$content) $content = $this->request($url, 'GET'); | |
$server = $this->htmlTag($content, 'link', 'rel', 'openid2.provider', 'href'); | |
$delegate = $this->htmlTag($content, 'link', 'rel', 'openid2.local_id', 'href'); | |
$this->version = 2; | |
if (!$server) { | |
$server = $this->htmlTag($content, 'link', 'rel', 'openid.server', 'href'); | |
$delegate = $this->htmlTag($content, 'link', 'rel', 'openid.delegate', 'href'); | |
$this->version = 1; | |
} | |
if ($server) { | |
if ($delegate) { | |
$this->identity = $delegate; | |
} | |
$this->server = $server; | |
return $server; | |
} | |
throw new ErrorException('No servers found!'); | |
} | |
throw new ErrorException('Endless redirection!'); | |
} | |
protected function axParams() | |
{ | |
$params = array(); | |
if ($this->required || $this->optional) { | |
$params['openid.ns.ax'] = 'http://openid.net/srv/ax/1.0'; | |
$params['openid.ax.mode'] = 'fetch_request'; | |
$this->aliases = array(); | |
$counts = array(); | |
$required = array(); | |
$optional = array(); | |
foreach (array('required','optional') as $type) { | |
foreach ($this->$type as $alias => $field) { | |
if (is_int($alias)) $alias = strtr($field, '/', '_'); | |
$this->aliases[$alias] = 'http://axschema.org/' . $field; | |
if (empty($counts[$alias])) $counts[$alias] = 0; | |
$counts[$alias] += 1; | |
${$type}[] = $alias; | |
} | |
} | |
foreach ($this->aliases as $alias => $ns) { | |
$params['openid.ax.type.' . $alias] = $ns; | |
} | |
foreach ($counts as $alias => $count) { | |
if ($count == 1) continue; | |
$params['openid.ax.count.' . $alias] = $count; | |
} | |
if($required) { | |
$params['openid.ax.required'] = implode(',', $required); | |
} | |
if($optional) { | |
$params['openid.ax.if_available'] = implode(',', $optional); | |
} | |
} | |
return $params; | |
} | |
protected function authUrl_v1() | |
{ | |
$returnUrl = $this->returnUrl; | |
if($this->identity != $this->claimed_id) { | |
$returnUrl .= (strpos($returnUrl, '?') ? '&' : '?') . 'openid.claimed_id=' . $this->claimed_id; | |
} | |
$params = array( | |
'openid.return_to' => $returnUrl, | |
'openid.mode' => 'checkid_setup', | |
'openid.identity' => $this->identity, | |
'openid.trust_root' => $this->trustRoot, | |
) + $this->sregParams(); | |
return $this->build_url(parse_url($this->server) | |
, array('query' => http_build_query($params, '', '&'))); | |
} | |
protected function authUrl_v2($identifier_select) | |
{ | |
$params = array( | |
'openid.ns' => 'http://specs.openid.net/auth/2.0', | |
'openid.mode' => 'checkid_setup', | |
'openid.return_to' => $this->returnUrl, | |
'openid.realm' => $this->trustRoot, | |
); | |
if ($this->ax) { | |
$params += $this->axParams(); | |
} | |
if ($this->sreg) { | |
$params += $this->sregParams(); | |
} | |
if (!$this->ax && !$this->sreg) { | |
$params += $this->axParams() + $this->sregParams(); | |
} | |
if ($identifier_select) { | |
$params['openid.identity'] = $params['openid.claimed_id'] | |
= 'http://specs.openid.net/auth/2.0/identifier_select'; | |
} else { | |
$params['openid.identity'] = $this->identity; | |
$params['openid.claimed_id'] = $this->claimed_id; | |
} | |
return $this->build_url(parse_url($this->server) | |
, array('query' => http_build_query($params, '', '&'))); | |
} | |
function authUrl($identifier_select = null) | |
{ | |
if (!$this->server) $this->discover($this->identity); | |
if ($this->version == 2) { | |
if ($identifier_select === null) { | |
return $this->authUrl_v2($this->identifier_select); | |
} | |
return $this->authUrl_v2($identifier_select); | |
} | |
return $this->authUrl_v1(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment