Overview

Namespaces

  • cli_db
    • propel
      • map
      • om
  • cli_import
  • LoggedPDO
  • None
  • PHP
  • webservices
    • cart
    • combisearch
    • details
      • annotations
        • feature
    • graphs
      • barplot
      • genome
    • listing
    • queue

Classes

  • Console_CommandLine_Action_ExtendedHelp
  • LightOpenID
  • Log_firebugJSON
  • WebService

Interfaces

  • CLI_Command

Functions

  • acquire_database
  • cli_error_handler
  • connect_queue_db
  • create_job
  • display_feature
  • display_feature_by_id
  • display_isoform_by_id
  • display_unigene_by_id
  • download
  • execute_command
  • execute_job
  • execute_query_dir
  • get_db_connection
  • get_job_results
  • get_program_databases
  • myErrorHandler
  • pdo_connect
  • report_results_cleanup
  • requestVal
  • smarty_function_call_webservice
  • smarty_function_dbxreflink
  • smarty_function_interprolink
  • smarty_function_publink
  • smarty_modifier_clean_id
  • split_fasta
  • unzip
  • Overview
  • Namespace
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * This class provides a simple interface for OpenID (1.1 and 2.0) authentication.
  4:  * Supports Yadis discovery.
  5:  * The authentication process is stateless/dumb.
  6:  *
  7:  * Usage:
  8:  * Sign-on with OpenID is a two step process:
  9:  * Step one is authentication with the provider:
 10:  * <code>
 11:  * $openid = new LightOpenID('my-host.example.org');
 12:  * $openid->identity = 'ID supplied by user';
 13:  * header('Location: ' . $openid->authUrl());
 14:  * </code>
 15:  * The provider then sends various parameters via GET, one of them is openid_mode.
 16:  * Step two is verification:
 17:  * <code>
 18:  * $openid = new LightOpenID('my-host.example.org');
 19:  * if ($openid->mode) {
 20:  *     echo $openid->validate() ? 'Logged in.' : 'Failed';
 21:  * }
 22:  * </code>
 23:  *
 24:  * Change the 'my-host.example.org' to your domain name. Do NOT use $_SERVER['HTTP_HOST']
 25:  * for that, unless you know what you are doing.
 26:  *
 27:  * Optionally, you can set $returnUrl and $realm (or $trustRoot, which is an alias).
 28:  * The default values for those are:
 29:  * $openid->realm     = (!empty($_SERVER['HTTPS']) ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST'];
 30:  * $openid->returnUrl = $openid->realm . $_SERVER['REQUEST_URI'];
 31:  * If you don't know their meaning, refer to any openid tutorial, or specification. Or just guess.
 32:  *
 33:  * AX and SREG extensions are supported.
 34:  * To use them, specify $openid->required and/or $openid->optional before calling $openid->authUrl().
 35:  * These are arrays, with values being AX schema paths (the 'path' part of the URL).
 36:  * For example:
 37:  *   $openid->required = array('namePerson/friendly', 'contact/email');
 38:  *   $openid->optional = array('namePerson/first');
 39:  * If the server supports only SREG or OpenID 1.1, these are automaticaly
 40:  * mapped to SREG names, so that user doesn't have to know anything about the server.
 41:  *
 42:  * To get the values, use $openid->getAttributes().
 43:  *
 44:  *
 45:  * The library requires PHP >= 5.1.2 with curl or http/https stream wrappers enabled.
 46:  * @author Mewp
 47:  * @copyright Copyright (c) 2010, Mewp
 48:  * @license http://www.opensource.org/licenses/mit-license.php MIT
 49:  */
 50: class LightOpenID
 51: {
 52:     public $returnUrl
 53:          , $required = array()
 54:          , $optional = array()
 55:          , $verify_peer = null
 56:          , $capath = null
 57:          , $cainfo = null
 58:          , $data;
 59:     private $identity, $claimed_id;
 60:     protected $server, $version, $trustRoot, $aliases, $identifier_select = false
 61:             , $ax = false, $sreg = false, $setup_url = null, $headers = array();
 62:     static protected $ax_to_sreg = array(
 63:         'namePerson/friendly'     => 'nickname',
 64:         'contact/email'           => 'email',
 65:         'namePerson'              => 'fullname',
 66:         'birthDate'               => 'dob',
 67:         'person/gender'           => 'gender',
 68:         'contact/postalCode/home' => 'postcode',
 69:         'contact/country/home'    => 'country',
 70:         'pref/language'           => 'language',
 71:         'pref/timezone'           => 'timezone',
 72:         );
 73: 
 74:     function __construct($host)
 75:     {
 76:         $this->trustRoot = (strpos($host, '://') ? $host : 'http://' . $host);
 77:         if ((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off')
 78:             || (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])
 79:             && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')
 80:         ) {
 81:             $this->trustRoot = (strpos($host, '://') ? $host : 'https://' . $host);
 82:         }
 83: 
 84:         if(($host_end = strpos($this->trustRoot, '/', 8)) !== false) {
 85:             $this->trustRoot = substr($this->trustRoot, 0, $host_end);
 86:         }
 87: 
 88:         $uri = rtrim(preg_replace('#((?<=\?)|&)openid\.[^&]+#', '', $_SERVER['REQUEST_URI']), '?');
 89:         $this->returnUrl = $this->trustRoot . $uri;
 90: 
 91:         $this->data = ($_SERVER['REQUEST_METHOD'] === 'POST') ? $_POST : $_GET;
 92: 
 93:         if(!function_exists('curl_init') && !in_array('https', stream_get_wrappers())) {
 94:             throw new ErrorException('You must have either https wrappers or curl enabled.');
 95:         }
 96:     }
 97: 
 98:     function __set($name, $value)
 99:     {
100:         switch ($name) {
101:         case 'identity':
102:             if (strlen($value = trim((String) $value))) {
103:                 if (preg_match('#^xri:/*#i', $value, $m)) {
104:                     $value = substr($value, strlen($m[0]));
105:                 } elseif (!preg_match('/^(?:[=@+\$!\(]|https?:)/i', $value)) {
106:                     $value = "http://$value";
107:                 }
108:                 if (preg_match('#^https?://[^/]+$#i', $value, $m)) {
109:                     $value .= '/';
110:                 }
111:             }
112:             $this->$name = $this->claimed_id = $value;
113:             break;
114:         case 'trustRoot':
115:         case 'realm':
116:             $this->trustRoot = trim($value);
117:         }
118:     }
119: 
120:     function __get($name)
121:     {
122:         switch ($name) {
123:         case 'identity':
124:             # We return claimed_id instead of identity,
125:             # because the developer should see the claimed identifier,
126:             # i.e. what he set as identity, not the op-local identifier (which is what we verify)
127:             return $this->claimed_id;
128:         case 'trustRoot':
129:         case 'realm':
130:             return $this->trustRoot;
131:         case 'mode':
132:             return empty($this->data['openid_mode']) ? null : $this->data['openid_mode'];
133:         }
134:     }
135: 
136:     /**
137:      * Checks if the server specified in the url exists.
138:      *
139:      * @param $url url to check
140:      * @return true, if the server exists; false otherwise
141:      */
142:     function hostExists($url)
143:     {
144:         if (strpos($url, '/') === false) {
145:             $server = $url;
146:         } else {
147:             $server = @parse_url($url, PHP_URL_HOST);
148:         }
149: 
150:         if (!$server) {
151:             return false;
152:         }
153: 
154:         return !!gethostbynamel($server);
155:     }
156: 
157:     protected function request_curl($url, $method='GET', $params=array(), $update_claimed_id)
158:     {
159:         $params = http_build_query($params, '', '&');
160:         $curl = curl_init($url . ($method == 'GET' && $params ? '?' . $params : ''));
161:         curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
162:         curl_setopt($curl, CURLOPT_HEADER, false);
163:         curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
164:         curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
165:         curl_setopt($curl, CURLOPT_HTTPHEADER, array('Accept: application/xrds+xml, */*'));
166: 
167:         if($this->verify_peer !== null) {
168:             curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $this->verify_peer);
169:             if($this->capath) {
170:                 curl_setopt($curl, CURLOPT_CAPATH, $this->capath);
171:             }
172: 
173:             if($this->cainfo) {
174:                 curl_setopt($curl, CURLOPT_CAINFO, $this->cainfo);
175:             }
176:         }
177: 
178:         if ($method == 'POST') {
179:             curl_setopt($curl, CURLOPT_POST, true);
180:             curl_setopt($curl, CURLOPT_POSTFIELDS, $params);
181:         } elseif ($method == 'HEAD') {
182:             curl_setopt($curl, CURLOPT_HEADER, true);
183:             curl_setopt($curl, CURLOPT_NOBODY, true);
184:         } else {
185:             curl_setopt($curl, CURLOPT_HEADER, true);
186:             curl_setopt($curl, CURLOPT_HTTPGET, true);
187:         }
188:         $response = curl_exec($curl);
189: 
190:         if($method == 'HEAD' && curl_getinfo($curl, CURLINFO_HTTP_CODE) == 405) {
191:             curl_setopt($curl, CURLOPT_HTTPGET, true);
192:             $response = curl_exec($curl);
193:             $response = substr($response, 0, strpos($response, "\r\n\r\n"));
194:         }
195: 
196:         if($method == 'HEAD' || $method == 'GET') {
197:             $header_response = $response;
198: 
199:             # If it's a GET request, we want to only parse the header part.
200:             if($method == 'GET') {
201:                 $header_response = substr($response, 0, strpos($response, "\r\n\r\n"));
202:             }
203: 
204:             $headers = array();
205:             foreach(explode("\n", $header_response) as $header) {
206:                 $pos = strpos($header,':');
207:                 if ($pos !== false) {
208:                     $name = strtolower(trim(substr($header, 0, $pos)));
209:                     $headers[$name] = trim(substr($header, $pos+1));
210:                 }
211:             }
212: 
213:             if($update_claimed_id) {
214:                 # Updating claimed_id in case of redirections.
215:                 $effective_url = curl_getinfo($curl, CURLINFO_EFFECTIVE_URL);
216:                 if($effective_url != $url) {
217:                     $this->identity = $this->claimed_id = $effective_url;
218:                 }
219:             }
220: 
221:             if($method == 'HEAD') {
222:                 return $headers;
223:             } else {
224:                 $this->headers = $headers;
225:             }
226:         }
227: 
228:         if (curl_errno($curl)) {
229:             throw new ErrorException(curl_error($curl), curl_errno($curl));
230:         }
231: 
232:         return $response;
233:     }
234: 
235:     protected function parse_header_array($array, $update_claimed_id)
236:     {
237:         $headers = array();
238:         foreach($array as $header) {
239:             $pos = strpos($header,':');
240:             if ($pos !== false) {
241:                 $name = strtolower(trim(substr($header, 0, $pos)));
242:                 $headers[$name] = trim(substr($header, $pos+1));
243: 
244:                 # Following possible redirections. The point is just to have
245:                 # claimed_id change with them, because the redirections
246:                 # are followed automatically.
247:                 # We ignore redirections with relative paths.
248:                 # If any known provider uses them, file a bug report.
249:                 if($name == 'location' && $update_claimed_id) {
250:                     if(strpos($headers[$name], 'http') === 0) {
251:                         $this->identity = $this->claimed_id = $headers[$name];
252:                     } elseif($headers[$name][0] == '/') {
253:                         $parsed_url = parse_url($this->claimed_id);
254:                         $this->identity =
255:                         $this->claimed_id = $parsed_url['scheme'] . '://'
256:                                           . $parsed_url['host']
257:                                           . $headers[$name];
258:                     }
259:                 }
260:             }
261:         }
262:         return $headers;
263:     }
264: 
265:     protected function request_streams($url, $method='GET', $params=array(), $update_claimed_id)
266:     {
267:         if(!$this->hostExists($url)) {
268:             throw new ErrorException("Could not connect to $url.", 404);
269:         }
270: 
271:         $params = http_build_query($params, '', '&');
272:         switch($method) {
273:         case 'GET':
274:             $opts = array(
275:                 'http' => array(
276:                     'method' => 'GET',
277:                     'header' => 'Accept: application/xrds+xml, */*',
278:                     'ignore_errors' => true,
279:                 ), 'ssl' => array(
280:                     'CN_match' => parse_url($url, PHP_URL_HOST),
281:                 ),
282:             );
283:             $url = $url . ($params ? '?' . $params : '');
284:             break;
285:         case 'POST':
286:             $opts = array(
287:                 'http' => array(
288:                     'method' => 'POST',
289:                     'header'  => 'Content-type: application/x-www-form-urlencoded',
290:                     'content' => $params,
291:                     'ignore_errors' => true,
292:                 ), 'ssl' => array(
293:                     'CN_match' => parse_url($url, PHP_URL_HOST),
294:                 ),
295:             );
296:             break;
297:         case 'HEAD':
298:             # We want to send a HEAD request,
299:             # but since get_headers doesn't accept $context parameter,
300:             # we have to change the defaults.
301:             $default = stream_context_get_options(stream_context_get_default());
302:             stream_context_get_default(
303:                 array(
304:                     'http' => array(
305:                         'method' => 'HEAD',
306:                         'header' => 'Accept: application/xrds+xml, */*',
307:                         'ignore_errors' => true,
308:                     ), 'ssl' => array(
309:                         'CN_match' => parse_url($url, PHP_URL_HOST),
310:                     ),
311:                 )
312:             );
313: 
314:             $url = $url . ($params ? '?' . $params : '');
315:             $headers = get_headers ($url);
316:             if(!$headers) {
317:                 return array();
318:             }
319: 
320:             if(intval(substr($headers[0], strlen('HTTP/1.1 '))) == 405) {
321:                 # The server doesn't support HEAD, so let's emulate it with
322:                 # a GET.
323:                 $args = func_get_args();
324:                 $args[1] = 'GET';
325:                 call_user_func_array(array($this, 'request_streams'), $args);
326:                 return $this->headers;
327:             }
328: 
329:             $headers = $this->parse_header_array($headers, $update_claimed_id);
330: 
331:             # And restore them.
332:             stream_context_get_default($default);
333:             return $headers;
334:         }
335: 
336:         if($this->verify_peer) {
337:             $opts['ssl'] += array(
338:                 'verify_peer' => true,
339:                 'capath'      => $this->capath,
340:                 'cafile'      => $this->cainfo,
341:             );
342:         }
343: 
344:         $context = stream_context_create ($opts);
345:         $data = file_get_contents($url, false, $context);
346:         # This is a hack for providers who don't support HEAD requests.
347:         # It just creates the headers array for the last request in $this->headers.
348:         if(isset($http_response_header)) {
349:             $this->headers = $this->parse_header_array($http_response_header, $update_claimed_id);
350:         }
351: 
352:         return file_get_contents($url, false, $context);
353:     }
354: 
355:     protected function request($url, $method='GET', $params=array(), $update_claimed_id=false)
356:     {
357:         if (function_exists('curl_init')
358:             && (!in_array('https', stream_get_wrappers()) || !ini_get('safe_mode') && !ini_get('open_basedir'))
359:         ) {
360:             return $this->request_curl($url, $method, $params, $update_claimed_id);
361:         }
362:         return $this->request_streams($url, $method, $params, $update_claimed_id);
363:     }
364: 
365:     protected function build_url($url, $parts)
366:     {
367:         if (isset($url['query'], $parts['query'])) {
368:             $parts['query'] = $url['query'] . '&' . $parts['query'];
369:         }
370: 
371:         $url = $parts + $url;
372:         $url = $url['scheme'] . '://'
373:              . (empty($url['username'])?''
374:                  :(empty($url['password'])? "{$url['username']}@"
375:                  :"{$url['username']}:{$url['password']}@"))
376:              . $url['host']
377:              . (empty($url['port'])?'':":{$url['port']}")
378:              . (empty($url['path'])?'':$url['path'])
379:              . (empty($url['query'])?'':"?{$url['query']}")
380:              . (empty($url['fragment'])?'':"#{$url['fragment']}");
381:         return $url;
382:     }
383: 
384:     /**
385:      * Helper function used to scan for <meta>/<link> tags and extract information
386:      * from them
387:      */
388:     protected function htmlTag($content, $tag, $attrName, $attrValue, $valueName)
389:     {
390:         preg_match_all("#<{$tag}[^>]*$attrName=['\"].*?$attrValue.*?['\"][^>]*$valueName=['\"](.+?)['\"][^>]*/?>#i", $content, $matches1);
391:         preg_match_all("#<{$tag}[^>]*$valueName=['\"](.+?)['\"][^>]*$attrName=['\"].*?$attrValue.*?['\"][^>]*/?>#i", $content, $matches2);
392: 
393:         $result = array_merge($matches1[1], $matches2[1]);
394:         return empty($result)?false:$result[0];
395:     }
396: 
397:     /**
398:      * Performs Yadis and HTML discovery. Normally not used.
399:      * @param $url Identity URL.
400:      * @return String OP Endpoint (i.e. OpenID provider address).
401:      * @throws ErrorException
402:      */
403:     function discover($url)
404:     {
405:         if (!$url) throw new ErrorException('No identity supplied.');
406:         # Use xri.net proxy to resolve i-name identities
407:         if (!preg_match('#^https?:#', $url)) {
408:             $url = "https://xri.net/$url";
409:         }
410: 
411:         # We save the original url in case of Yadis discovery failure.
412:         # It can happen when we'll be lead to an XRDS document
413:         # which does not have any OpenID2 services.
414:         $originalUrl = $url;
415: 
416:         # A flag to disable yadis discovery in case of failure in headers.
417:         $yadis = true;
418: 
419:         # We'll jump a maximum of 5 times, to avoid endless redirections.
420:         for ($i = 0; $i < 5; $i ++) {
421:             if ($yadis) {
422:                 $headers = $this->request($url, 'HEAD', array(), true);
423: 
424:                 $next = false;
425:                 if (isset($headers['x-xrds-location'])) {
426:                     $url = $this->build_url(parse_url($url), parse_url(trim($headers['x-xrds-location'])));
427:                     $next = true;
428:                 }
429: 
430:                 if (isset($headers['content-type'])
431:                     && (strpos($headers['content-type'], 'application/xrds+xml') !== false
432:                         || strpos($headers['content-type'], 'text/xml') !== false)
433:                 ) {
434:                     # Apparently, some providers return XRDS documents as text/html.
435:                     # While it is against the spec, allowing this here shouldn't break
436:                     # compatibility with anything.
437:                     # ---
438:                     # Found an XRDS document, now let's find the server, and optionally delegate.
439:                     $content = $this->request($url, 'GET');
440: 
441:                     preg_match_all('#<Service.*?>(.*?)</Service>#s', $content, $m);
442:                     foreach($m[1] as $content) {
443:                         $content = ' ' . $content; # The space is added, so that strpos doesn't return 0.
444: 
445:                         # OpenID 2
446:                         $ns = preg_quote('http://specs.openid.net/auth/2.0/', '#');
447:                         if(preg_match('#<Type>\s*'.$ns.'(server|signon)\s*</Type>#s', $content, $type)) {
448:                             if ($type[1] == 'server') $this->identifier_select = true;
449: 
450:                             preg_match('#<URI.*?>(.*)</URI>#', $content, $server);
451:                             preg_match('#<(Local|Canonical)ID>(.*)</\1ID>#', $content, $delegate);
452:                             if (empty($server)) {
453:                                 return false;
454:                             }
455:                             # Does the server advertise support for either AX or SREG?
456:                             $this->ax   = (bool) strpos($content, '<Type>http://openid.net/srv/ax/1.0</Type>');
457:                             $this->sreg = strpos($content, '<Type>http://openid.net/sreg/1.0</Type>')
458:                                        || strpos($content, '<Type>http://openid.net/extensions/sreg/1.1</Type>');
459: 
460:                             $server = $server[1];
461:                             if (isset($delegate[2])) $this->identity = trim($delegate[2]);
462:                             $this->version = 2;
463: 
464:                             $this->server = $server;
465:                             return $server;
466:                         }
467: 
468:                         # OpenID 1.1
469:                         $ns = preg_quote('http://openid.net/signon/1.1', '#');
470:                         if (preg_match('#<Type>\s*'.$ns.'\s*</Type>#s', $content)) {
471: 
472:                             preg_match('#<URI.*?>(.*)</URI>#', $content, $server);
473:                             preg_match('#<.*?Delegate>(.*)</.*?Delegate>#', $content, $delegate);
474:                             if (empty($server)) {
475:                                 return false;
476:                             }
477:                             # AX can be used only with OpenID 2.0, so checking only SREG
478:                             $this->sreg = strpos($content, '<Type>http://openid.net/sreg/1.0</Type>')
479:                                        || strpos($content, '<Type>http://openid.net/extensions/sreg/1.1</Type>');
480: 
481:                             $server = $server[1];
482:                             if (isset($delegate[1])) $this->identity = $delegate[1];
483:                             $this->version = 1;
484: 
485:                             $this->server = $server;
486:                             return $server;
487:                         }
488:                     }
489: 
490:                     $next = true;
491:                     $yadis = false;
492:                     $url = $originalUrl;
493:                     $content = null;
494:                     break;
495:                 }
496:                 if ($next) continue;
497: 
498:                 # There are no relevant information in headers, so we search the body.
499:                 $content = $this->request($url, 'GET', array(), true);
500: 
501:                 if (isset($this->headers['x-xrds-location'])) {
502:                     $url = $this->build_url(parse_url($url), parse_url(trim($this->headers['x-xrds-location'])));
503:                     continue;
504:                 }
505: 
506:                 $location = $this->htmlTag($content, 'meta', 'http-equiv', 'X-XRDS-Location', 'content');
507:                 if ($location) {
508:                     $url = $this->build_url(parse_url($url), parse_url($location));
509:                     continue;
510:                 }
511:             }
512: 
513:             if (!$content) $content = $this->request($url, 'GET');
514: 
515:             # At this point, the YADIS Discovery has failed, so we'll switch
516:             # to openid2 HTML discovery, then fallback to openid 1.1 discovery.
517:             $server   = $this->htmlTag($content, 'link', 'rel', 'openid2.provider', 'href');
518:             $delegate = $this->htmlTag($content, 'link', 'rel', 'openid2.local_id', 'href');
519:             $this->version = 2;
520: 
521:             if (!$server) {
522:                 # The same with openid 1.1
523:                 $server   = $this->htmlTag($content, 'link', 'rel', 'openid.server', 'href');
524:                 $delegate = $this->htmlTag($content, 'link', 'rel', 'openid.delegate', 'href');
525:                 $this->version = 1;
526:             }
527: 
528:             if ($server) {
529:                 # We found an OpenID2 OP Endpoint
530:                 if ($delegate) {
531:                     # We have also found an OP-Local ID.
532:                     $this->identity = $delegate;
533:                 }
534:                 $this->server = $server;
535:                 return $server;
536:             }
537: 
538:             throw new ErrorException("No OpenID Server found at $url", 404);
539:         }
540:         throw new ErrorException('Endless redirection!', 500);
541:     }
542: 
543:     protected function sregParams()
544:     {
545:         $params = array();
546:         # We always use SREG 1.1, even if the server is advertising only support for 1.0.
547:         # That's because it's fully backwards compatibile with 1.0, and some providers
548:         # advertise 1.0 even if they accept only 1.1. One such provider is myopenid.com
549:         $params['openid.ns.sreg'] = 'http://openid.net/extensions/sreg/1.1';
550:         if ($this->required) {
551:             $params['openid.sreg.required'] = array();
552:             foreach ($this->required as $required) {
553:                 if (!isset(self::$ax_to_sreg[$required])) continue;
554:                 $params['openid.sreg.required'][] = self::$ax_to_sreg[$required];
555:             }
556:             $params['openid.sreg.required'] = implode(',', $params['openid.sreg.required']);
557:         }
558: 
559:         if ($this->optional) {
560:             $params['openid.sreg.optional'] = array();
561:             foreach ($this->optional as $optional) {
562:                 if (!isset(self::$ax_to_sreg[$optional])) continue;
563:                 $params['openid.sreg.optional'][] = self::$ax_to_sreg[$optional];
564:             }
565:             $params['openid.sreg.optional'] = implode(',', $params['openid.sreg.optional']);
566:         }
567:         return $params;
568:     }
569: 
570:     protected function axParams()
571:     {
572:         $params = array();
573:         if ($this->required || $this->optional) {
574:             $params['openid.ns.ax'] = 'http://openid.net/srv/ax/1.0';
575:             $params['openid.ax.mode'] = 'fetch_request';
576:             $this->aliases  = array();
577:             $counts   = array();
578:             $required = array();
579:             $optional = array();
580:             foreach (array('required','optional') as $type) {
581:                 foreach ($this->$type as $alias => $field) {
582:                     if (is_int($alias)) $alias = strtr($field, '/', '_');
583:                     $this->aliases[$alias] = 'http://axschema.org/' . $field;
584:                     if (empty($counts[$alias])) $counts[$alias] = 0;
585:                     $counts[$alias] += 1;
586:                     ${$type}[] = $alias;
587:                 }
588:             }
589:             foreach ($this->aliases as $alias => $ns) {
590:                 $params['openid.ax.type.' . $alias] = $ns;
591:             }
592:             foreach ($counts as $alias => $count) {
593:                 if ($count == 1) continue;
594:                 $params['openid.ax.count.' . $alias] = $count;
595:             }
596: 
597:             # Don't send empty ax.requied and ax.if_available.
598:             # Google and possibly other providers refuse to support ax when one of these is empty.
599:             if($required) {
600:                 $params['openid.ax.required'] = implode(',', $required);
601:             }
602:             if($optional) {
603:                 $params['openid.ax.if_available'] = implode(',', $optional);
604:             }
605:         }
606:         return $params;
607:     }
608: 
609:     protected function authUrl_v1($immediate)
610:     {
611:         $returnUrl = $this->returnUrl;
612:         # If we have an openid.delegate that is different from our claimed id,
613:         # we need to somehow preserve the claimed id between requests.
614:         # The simplest way is to just send it along with the return_to url.
615:         if($this->identity != $this->claimed_id) {
616:             $returnUrl .= (strpos($returnUrl, '?') ? '&' : '?') . 'openid.claimed_id=' . $this->claimed_id;
617:         }
618: 
619:         $params = array(
620:             'openid.return_to'  => $returnUrl,
621:             'openid.mode'       => $immediate ? 'checkid_immediate' : 'checkid_setup',
622:             'openid.identity'   => $this->identity,
623:             'openid.trust_root' => $this->trustRoot,
624:             ) + $this->sregParams();
625: 
626:         return $this->build_url(parse_url($this->server)
627:                                , array('query' => http_build_query($params, '', '&')));
628:     }
629: 
630:     protected function authUrl_v2($immediate)
631:     {
632:         $params = array(
633:             'openid.ns'          => 'http://specs.openid.net/auth/2.0',
634:             'openid.mode'        => $immediate ? 'checkid_immediate' : 'checkid_setup',
635:             'openid.return_to'   => $this->returnUrl,
636:             'openid.realm'       => $this->trustRoot,
637:         );
638:         if ($this->ax) {
639:             $params += $this->axParams();
640:         }
641:         if ($this->sreg) {
642:             $params += $this->sregParams();
643:         }
644:         if (!$this->ax && !$this->sreg) {
645:             # If OP doesn't advertise either SREG, nor AX, let's send them both
646:             # in worst case we don't get anything in return.
647:             $params += $this->axParams() + $this->sregParams();
648:         }
649: 
650:         if ($this->identifier_select) {
651:             $params['openid.identity'] = $params['openid.claimed_id']
652:                  = 'http://specs.openid.net/auth/2.0/identifier_select';
653:         } else {
654:             $params['openid.identity'] = $this->identity;
655:             $params['openid.claimed_id'] = $this->claimed_id;
656:         }
657: 
658:         return $this->build_url(parse_url($this->server)
659:                                , array('query' => http_build_query($params, '', '&')));
660:     }
661: 
662:     /**
663:      * Returns authentication url. Usually, you want to redirect your user to it.
664:      * @return String The authentication url.
665:      * @param String $select_identifier Whether to request OP to select identity for an user in OpenID 2. Does not affect OpenID 1.
666:      * @throws ErrorException
667:      */
668:     function authUrl($immediate = false)
669:     {
670:         if ($this->setup_url && !$immediate) return $this->setup_url;
671:         if (!$this->server) $this->discover($this->identity);
672: 
673:         if ($this->version == 2) {
674:             return $this->authUrl_v2($immediate);
675:         }
676:         return $this->authUrl_v1($immediate);
677:     }
678: 
679:     /**
680:      * Performs OpenID verification with the OP.
681:      * @return Bool Whether the verification was successful.
682:      * @throws ErrorException
683:      */
684:     function validate()
685:     {
686:         # If the request was using immediate mode, a failure may be reported
687:         # by presenting user_setup_url (for 1.1) or reporting
688:         # mode 'setup_needed' (for 2.0). Also catching all modes other than
689:         # id_res, in order to avoid throwing errors.
690:         if(isset($this->data['openid_user_setup_url'])) {
691:             $this->setup_url = $this->data['openid_user_setup_url'];
692:             return false;
693:         }
694:         if($this->mode != 'id_res') {
695:             return false;
696:         }
697: 
698:         $this->claimed_id = isset($this->data['openid_claimed_id'])?$this->data['openid_claimed_id']:$this->data['openid_identity'];
699:         $params = array(
700:             'openid.assoc_handle' => $this->data['openid_assoc_handle'],
701:             'openid.signed'       => $this->data['openid_signed'],
702:             'openid.sig'          => $this->data['openid_sig'],
703:             );
704: 
705:         if (isset($this->data['openid_ns'])) {
706:             # We're dealing with an OpenID 2.0 server, so let's set an ns
707:             # Even though we should know location of the endpoint,
708:             # we still need to verify it by discovery, so $server is not set here
709:             $params['openid.ns'] = 'http://specs.openid.net/auth/2.0';
710:         } elseif (isset($this->data['openid_claimed_id'])
711:             && $this->data['openid_claimed_id'] != $this->data['openid_identity']
712:         ) {
713:             # If it's an OpenID 1 provider, and we've got claimed_id,
714:             # we have to append it to the returnUrl, like authUrl_v1 does.
715:             $this->returnUrl .= (strpos($this->returnUrl, '?') ? '&' : '?')
716:                              .  'openid.claimed_id=' . $this->claimed_id;
717:         }
718: 
719:         if ($this->data['openid_return_to'] != $this->returnUrl) {
720:             # The return_to url must match the url of current request.
721:             # I'm assuing that noone will set the returnUrl to something that doesn't make sense.
722:             return false;
723:         }
724: 
725:         $server = $this->discover($this->claimed_id);
726: 
727:         foreach (explode(',', $this->data['openid_signed']) as $item) {
728:             # Checking whether magic_quotes_gpc is turned on, because
729:             # the function may fail if it is. For example, when fetching
730:             # AX namePerson, it might containg an apostrophe, which will be escaped.
731:             # In such case, validation would fail, since we'd send different data than OP
732:             # wants to verify. stripslashes() should solve that problem, but we can't
733:             # use it when magic_quotes is off.
734:             $value = $this->data['openid_' . str_replace('.','_',$item)];
735:             $params['openid.' . $item] = function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc() ? stripslashes($value) : $value;
736: 
737:         }
738: 
739:         $params['openid.mode'] = 'check_authentication';
740: 
741:         $response = $this->request($server, 'POST', $params);
742: 
743:         return preg_match('/is_valid\s*:\s*true/i', $response);
744:     }
745: 
746:     protected function getAxAttributes()
747:     {
748:         $alias = null;
749:         if (isset($this->data['openid_ns_ax'])
750:             && $this->data['openid_ns_ax'] != 'http://openid.net/srv/ax/1.0'
751:         ) { # It's the most likely case, so we'll check it before
752:             $alias = 'ax';
753:         } else {
754:             # 'ax' prefix is either undefined, or points to another extension,
755:             # so we search for another prefix
756:             foreach ($this->data as $key => $val) {
757:                 if (substr($key, 0, strlen('openid_ns_')) == 'openid_ns_'
758:                     && $val == 'http://openid.net/srv/ax/1.0'
759:                 ) {
760:                     $alias = substr($key, strlen('openid_ns_'));
761:                     break;
762:                 }
763:             }
764:         }
765:         if (!$alias) {
766:             # An alias for AX schema has not been found,
767:             # so there is no AX data in the OP's response
768:             return array();
769:         }
770: 
771:         $attributes = array();
772:         foreach (explode(',', $this->data['openid_signed']) as $key) {
773:             $keyMatch = $alias . '.value.';
774:             if (substr($key, 0, strlen($keyMatch)) != $keyMatch) {
775:                 continue;
776:             }
777:             $key = substr($key, strlen($keyMatch));
778:             if (!isset($this->data['openid_' . $alias . '_type_' . $key])) {
779:                 # OP is breaking the spec by returning a field without
780:                 # associated ns. This shouldn't happen, but it's better
781:                 # to check, than cause an E_NOTICE.
782:                 continue;
783:             }
784:             $value = $this->data['openid_' . $alias . '_value_' . $key];
785:             $key = substr($this->data['openid_' . $alias . '_type_' . $key],
786:                           strlen('http://axschema.org/'));
787: 
788:             $attributes[$key] = $value;
789:         }
790:         return $attributes;
791:     }
792: 
793:     protected function getSregAttributes()
794:     {
795:         $attributes = array();
796:         $sreg_to_ax = array_flip(self::$ax_to_sreg);
797:         foreach (explode(',', $this->data['openid_signed']) as $key) {
798:             $keyMatch = 'sreg.';
799:             if (substr($key, 0, strlen($keyMatch)) != $keyMatch) {
800:                 continue;
801:             }
802:             $key = substr($key, strlen($keyMatch));
803:             if (!isset($sreg_to_ax[$key])) {
804:                 # The field name isn't part of the SREG spec, so we ignore it.
805:                 continue;
806:             }
807:             $attributes[$sreg_to_ax[$key]] = $this->data['openid_sreg_' . $key];
808:         }
809:         return $attributes;
810:     }
811: 
812:     /**
813:      * Gets AX/SREG attributes provided by OP. should be used only after successful validaton.
814:      * Note that it does not guarantee that any of the required/optional parameters will be present,
815:      * or that there will be no other attributes besides those specified.
816:      * In other words. OP may provide whatever information it wants to.
817:      *     * SREG names will be mapped to AX names.
818:      *     * @return Array Array of attributes with keys being the AX schema names, e.g. 'contact/email'
819:      * @see http://www.axschema.org/types/
820:      */
821:     function getAttributes()
822:     {
823:         if (isset($this->data['openid_ns'])
824:             && $this->data['openid_ns'] == 'http://specs.openid.net/auth/2.0'
825:         ) { # OpenID 2.0
826:             # We search for both AX and SREG attributes, with AX taking precedence.
827:             return $this->getAxAttributes() + $this->getSregAttributes();
828:         }
829:         return $this->getSregAttributes();
830:     }
831: }
832: 
tbro API documentation generated by ApiGen 2.8.0