This is purely a test user interface. If this had been an actual user interface,
126 | you wouldn't be wondering what the hell is going on, what is "my domain",
127 | who am I, and why do I exist.
128 |
This is only a test.
129 |
Enter your personal web address, click Sign In, and see what happens.
It is likely there are still errors and any issues should be reported on the
146 | GitHub Project Page. This code is written by
147 | @themattharris and @t. It
148 | uses a modified OAuth PHP library.
149 |
150 |
151 |
152 |
195 |
196 |
197 |
--------------------------------------------------------------------------------
/lib/relmeauth.php:
--------------------------------------------------------------------------------
1 | $v) {
8 | unset($process[$key][$k]);
9 | if (is_array($v)) {
10 | $process[$key][stripslashes($k)] = $v;
11 | $process[] = &$process[$key][stripslashes($k)];
12 | } else {
13 | $process[$key][stripslashes($k)] = stripslashes($v);
14 | }
15 | }
16 | }
17 | unset($process);
18 | }
19 |
20 | ob_start(); require_once dirname(__FILE__) . '/cassis/cassis.js'; ob_end_clean();
21 | require dirname(__FILE__) . '/tmhOAuth/tmhOAuth.php';
22 | require dirname(__FILE__) . '/config.php';
23 |
24 | class relmeauth {
25 | function __construct() {
26 | session_start();
27 | $this->tmhOAuth = new tmhOAuth(array());
28 | }
29 |
30 | function is_loggedin() {
31 | // TODO: should have a timestamp expiry in here.
32 | return (isset($_SESSION['relmeauth']['name']));
33 | }
34 |
35 | function create_from_session() {
36 | global $providers;
37 |
38 | $config = $providers[$_SESSION['relmeauth']['provider']];
39 |
40 | // create tmhOAuth from session info
41 | $this->tmhOAuth = new tmhOAuth(array(
42 | 'consumer_key' => $config['keys']['consumer_key'],
43 | 'consumer_secret' => $config['keys']['consumer_secret'],
44 | 'user_token' => $_SESSION['relmeauth']['access']['oauth_token'],
45 | 'user_secret' => $_SESSION['relmeauth']['access']['oauth_token_secret']
46 | ));
47 | }
48 |
49 | function main($user_url, $askwrite) {
50 | // first try to authenticate directly with the URL given
51 | if ($this->is_provider($user_url)) {
52 | $_SESSION['relmeauth']['direct'] = true;
53 | if ($this->authenticate_url($user_url, $askwrite)) {
54 | return true; // bail once something claims to authenticate
55 | }
56 | unset($_SESSION['relmeauth']['direct']);
57 | }
58 |
59 | // get the rel-me URLs from the given site
60 | $source_rels = $this->discover($user_url);
61 |
62 | if ($source_rels==false || count($source_rels) == 0) {
63 | return false; // no rel-me links found, bail
64 | }
65 |
66 | // separate them into external and same domain
67 | $external_rels = array();
68 | $local_rels = array();
69 | $user_site = parse_url($user_url);
70 |
71 | foreach ($source_rels as $source_rel => $details) :
72 | $provider = parse_url($source_rel);
73 | if ($provider['host'] == $user_site['host']) {
74 | $local_rels[$source_rel] = $details;
75 | } else {
76 | $external_rels[$source_rel] = $details;
77 | }
78 | endforeach; // source_rels
79 |
80 | // see if any of the external rel-me URLs reciprocate - check rels in order
81 | // and then try authing it. needs to maintain more session state to resume.
82 | foreach ($external_rels as $external_rel => $details):
83 | // only bother to confirm rel-me etc. if we know how to auth the dest.
84 | if ($this->is_provider($external_rel) &&
85 | $this->confirm_rel($user_url, $external_rel)) {
86 | // We could keep this as a URL we actually try to auth, for debugging
87 | if ($this->authenticate_url($external_rel, $askwrite)) {
88 | return true; // bail once something claims to authenticate
89 | }
90 | }
91 | endforeach; // external_rels
92 |
93 | $source_rels = array_merge($local_rels, $external_rels);
94 | $source2_tried = array();
95 |
96 | // no external_rels, or none of them reciprocated or authed. try next level.
97 | foreach ($source_rels as $source_rel => $details) :
98 | // try rel-me-authing $source_rel,
99 | // and test its respective external $source2_urls
100 | // to match against $source_rel OR $user_url.
101 |
102 | $source_rel_confirmed =
103 | strpos($source_rel, $user_url)===0 ||
104 | $this->confirm_rel($user_url, $source_rel);
105 | // if $source_rel is a confirmed rel-me itself,
106 | // then we'll allow for 2nd level to confirm to it
107 |
108 | // then check its external_rels
109 | $source2_rels = $this->discover($source_rel);
110 | if ($source2_rels!=false) {
111 | foreach ($source2_rels as $source2_rel => $details) :
112 | $provider = parse_url($source2_rel);
113 | if ($provider['host'] != $user_site['host'] &&
114 | $this->is_provider($source2_rel))
115 | {
116 | $source2_tried[$source2_rel] = $details;
117 | if ((!$source_rel_confirmed &&
118 | $this->confirm_rel($user_url, $source2_rel)) ||
119 | ($source_rel_confirmed &&
120 | $this->confirms_rel($user_url, $source_rel, $source2_rel)))
121 | {
122 | // could keep this as a URL we actually try to auth, for debugging
123 | if ($source_rel_confirmed) {
124 | $_SESSION['relmeauth']['url2'] = $source_rel;
125 | }
126 | if ($this->authenticate_url($source2_rel, $askwrite)) {
127 | // this exits if it succeeds. next statement unnecessary.
128 | return true; // bail once something claims to authenticate
129 | }
130 | $_SESSION['relmeauth']['url2'] = '';
131 | }
132 | }
133 | endforeach; // source_rels
134 | }
135 |
136 | // if successful, should have returned true, which can be returned
137 | endforeach; // source_rels
138 |
139 | /*
140 | //debugging
141 | $debugurls = $this->discover('http://twitter.com/kevinmarks/');
142 |
143 | //end debugging
144 | */
145 |
146 | // otherwise, no URLs worked.
147 | $source_rels = implode(', ', array_keys($source_rels)) .
148 | ($source2_tried && count($source2_tried)>=0 ? ', ' .
149 | implode(', ', array_keys($source2_tried)) : '')
150 | /*
151 | .
152 | ($debugurls && count($debugurls)>=0 ? '. debug: ' .
153 | implode(', ', array_keys($debugurls)) : '')
154 | */
155 | ;
156 |
157 | $this->error('None of your providers are supported. Tried ' . $source_rels . '.');
158 |
159 | return false;
160 |
161 | /*
162 | // old code that first confirmed all rel-me links, and then tried as a batch
163 | // see if any of the relmes match back - we check the rels in the order
164 | // they are listed in the HTML
165 | $confirmed_rels = $this->confirm_rels($user_url, $source_rels);
166 | if ($confirmed_rels != false) {
167 | return $this->authenticate($confirmed_rels);
168 | } else {
169 | // error message will have already been set
170 | return false;
171 | }
172 | */
173 | }
174 |
175 | function request($keys, $method, $url, $params=array(), $useauth=true) {
176 | $this->tmhOAuth = new tmhOAuth(array());
177 |
178 | $this->tmhOAuth->config['consumer_key'] = $keys['consumer_key'];
179 | $this->tmhOAuth->config['consumer_secret'] = $keys['consumer_secret'];
180 | $this->tmhOAuth->config['user_token'] = @$keys['user_token'];
181 | $this->tmhOAuth->config['user_secret'] = @$keys['user_secret'];
182 | $code = $this->tmhOAuth->request(
183 | $method,
184 | $url,
185 | $params,
186 | $useauth
187 | );
188 |
189 | return ( $code == 200 );
190 | }
191 |
192 |
193 | /**
194 | * check to see if we know how to OAuth a URL
195 | *
196 | * @return whether or not it's a provider we know how to deal with
197 | * @author Tantek Çelik
198 | */
199 | function is_provider($confirmed_rel) {
200 | global $providers;
201 |
202 | $provider = parse_url($confirmed_rel);
203 | if (array_key_exists($provider['host'], $providers)) {
204 | return true;
205 | }
206 | if (strpos($provider['host'], 'www.')===0) {
207 | $provider['host'] = substr($provider['host'],4);
208 | if (array_key_exists($provider['host'], $providers) &&
209 | $providers[$provider['host']]['ltrimdomain'] == 'www.')
210 | {
211 | return true;
212 | }
213 | }
214 | return false;
215 | }
216 |
217 | /**
218 | * Wrapper for the OAuth authentication process for a URL
219 | *
220 | * @return false if authentication failed
221 | * @author Matt Harris and Tantek Çelik
222 | */
223 | function authenticate_url($confirmed_rel, $askwrite) {
224 | global $providers;
225 |
226 | if (!$this->is_provider($confirmed_rel))
227 | return false;
228 |
229 | $provider = parse_url($confirmed_rel);
230 | $config = $providers[ $provider['host'] ];
231 | $ok = $this->request(
232 | $config['keys'],
233 | 'GET',
234 | $config['urls']['request'],
235 | array(
236 | 'oauth_callback' => $this->here(),
237 | 'x_auth_access_type' => ($askwrite ? 'write' : 'read'), // http://dev.twitter.com/doc/post/oauth/request_token
238 | )
239 | );
240 |
241 | if ($ok) {
242 | // need these later
243 | $relpath = $provider['path'];
244 | $user = $this->tmhOAuth->extract_params($this->tmhOAuth->response['response']);
245 |
246 | $_SESSION['relmeauth']['provider'] = $provider['host'];
247 | $_SESSION['relmeauth']['secret'] = $user['oauth_token_secret'];
248 | $_SESSION['relmeauth']['token'] = $user['oauth_token'];
249 | $url = ($askwrite ? $config['urls']['authorize']
250 | : $config['urls']['authenticate']) . '?'
251 | . "oauth_token={$user['oauth_token']}";
252 | $this->redirect($url);
253 | return true;
254 | } else {
255 | $this->error("There was a problem communicating with {$provider['host']}. Error {$this->tmhOAuth->response['code']}. Please try later.");
256 | }
257 |
258 | return false;
259 | }
260 |
261 | /**
262 | * Wrapper for the OAuth authentication process
263 | *
264 | * @return false upon failure
265 | * @author Matt Harris and Tantek Çelik
266 | */
267 | function authenticate($confirmed_rels) {
268 | global $providers;
269 |
270 | foreach ($confirmed_rels as $host => $details) :
271 | if (authenticate_url($host))
272 | return true;
273 | endforeach; // confirmed_rels
274 |
275 | $this->error('None of your providers are supported. Tried ' . implode(', ', array_keys($confirmed_rels)) . '.');
276 | return false;
277 | }
278 |
279 | function complete_oauth( $verifier ) {
280 | global $providers;
281 |
282 | if ( ! array_key_exists($_SESSION['relmeauth']['provider'], $providers) ) {
283 | $this->error('None of your providers are supported, or you might have cookies disabled. Make sure your browser preferences are set to accept cookies and try again.');
284 | return false;
285 | }
286 |
287 | $config = $providers[$_SESSION['relmeauth']['provider']];
288 | $ok = $this->request(
289 | array_merge(
290 | $config['keys'],
291 | array(
292 | 'user_token' => $_SESSION['relmeauth']['token'],
293 | 'user_secret' => $_SESSION['relmeauth']['secret']
294 | )
295 | ),
296 | 'GET',
297 | $config['urls']['access'],
298 | array(
299 | 'oauth_verifier' => $verifier
300 | )
301 | );
302 | unset($_SESSION['relmeauth']['token']);
303 | unset($_SESSION['relmeauth']['secret']);
304 |
305 | if ($ok) {
306 | // get the users token and secret
307 | $_SESSION['relmeauth']['access'] = $this->tmhOAuth->extract_params($this->tmhOAuth->response['response']);
308 |
309 | // FIXME: validate this is the user who requested.
310 | // At the moment if I use another users URL that rel=me to Twitter for example, it
311 | // will work for me - because all we do is go 'oh Twitter, sure, login there and you're good to go
312 | // the rel=me bit doesn't get confirmed it belongs to the user
313 | $this->verify( $config );
314 | $this->redirect();
315 | }
316 | $this->error("There was a problem authenticating with {$provider['host']}. Error {$this->tmhOAuth->response['code']}. Please try later.");
317 | return false;
318 | }
319 |
320 | function verify( &$config ) {
321 | global $providers;
322 | $config = $providers[$_SESSION['relmeauth']['provider']];
323 |
324 | $ok = $this->request(
325 | array_merge(
326 | $config['keys'],
327 | array(
328 | 'user_token' => $_SESSION['relmeauth']['access']['oauth_token'],
329 | 'user_secret' => $_SESSION['relmeauth']['access']['oauth_token_secret']
330 | )
331 | ),
332 | 'GET',
333 | $config['urls']['verify']
334 | );
335 |
336 | $creds = json_decode($this->tmhOAuth->response['response'], true);
337 |
338 | $given = self::normalise_url($_SESSION['relmeauth']['url']);
339 | $found = self::normalise_url(self::expand_tco($creds[ $config['verify']['url'] ]));
340 |
341 | $_SESSION['relmeauth']['debug']['verify']['given'] = $given;
342 | $_SESSION['relmeauth']['debug']['verify']['found'] = $found;
343 |
344 | if ( $given != $found &&
345 | array_key_exists('url2', $_SESSION['relmeauth']))
346 | {
347 | $given = self::normalise_url($_SESSION['relmeauth']['url2']);
348 | }
349 |
350 | if ( $given == $found ||
351 | ($this->is_provider($given) && $_SESSION['relmeauth']['direct']))
352 | {
353 | $_SESSION['relmeauth']['name'] = $creds[ $config['verify']['name'] ];
354 | return true;
355 | } else {
356 | // destroy everything
357 | $provider = $_SESSION['relmeauth']['provider'];
358 | // unset($_SESSION['relmeauth']);
359 | $this->error("That isn't you! If it really is you, try signing out of {$provider}. Entered $given (". @$_SESSION['relmeauth']['url2'] . "), found $found.");
360 | return false;
361 | }
362 | }
363 |
364 | function error($message) {
365 | if ( ! isset( $_SESSION['relmeauth']['error'] ) ) {
366 | $_SESSION['relmeauth']['error'] = $message;
367 | } else {
368 | $_SESSION['relmeauth']['error'] .= ' ' . $message;
369 | }
370 | }
371 |
372 | /**
373 | * Print the last error message if there is one.
374 | *
375 | * @return void
376 | * @author Matt Harris
377 | */
378 | function printError() {
379 | if ( isset( $_SESSION['relmeauth']['error'] ) ) {
380 | echo '
' .
381 | $_SESSION['relmeauth']['error'] . '
';
382 | unset($_SESSION['relmeauth']['error']);
383 | }
384 | }
385 |
386 | /**
387 | * Check one rel=me URLs obtained from the users URL and see
388 | * if it contains a rel=me which equals this user URL.
389 | *
390 | * @return true if URL rel-me reciprocation confirmed else false
391 | * @author Matt Harris and Tantek Çelik
392 | */
393 | function confirm_rel($user_url, $source_rel) {
394 | $othermes = $this->discover($source_rel, false);
395 | $_SESSION['relmeauth']['debug']['source_rels'][$source_rel] = $othermes;
396 | if (is_array( $othermes)) {
397 | $othermes = array_map(array('relmeauth', 'normalise_url'), $othermes);
398 | $user_url = self::normalise_url($user_url);
399 |
400 | if (in_array($user_url, $othermes)) {
401 | $_SESSION['relmeauth']['debug']['matched'][] = $source_rel;
402 | return true;
403 | }
404 | }
405 | return false;
406 | }
407 |
408 | /**
409 | * Check one rel=me URLs obtained from the users URL and see
410 | * if it contains a rel=me which equals this user URL.
411 | *
412 | * @return true if URL rel-me reciprocation confirmed else false
413 | * @author Matt Harris and Tantek Çelik
414 | * Should really abstract confirms_rel() confirm_rel() and replace both
415 | */
416 | function confirms_rel($user_url, $local_url, $source_rel) {
417 | $othermes = $this->discover( $source_rel, false );
418 | $_SESSION['relmeauth']['debug']['source_rels'][$source_rel] = $othermes;
419 | if ( is_array( $othermes ) ) {
420 | $othermes = array_map(array('relmeauth', 'normalise_url'), $othermes);
421 | $user_url = self::normalise_url($user_url);
422 | $local_url = self::normalise_url($local_url);
423 |
424 | if (in_array($user_url, $othermes) ||
425 | in_array($local_url, $othermes)) {
426 | $_SESSION['relmeauth']['debug']['matched'][] = $source_rel;
427 | return true;
428 | }
429 | }
430 | return false;
431 | }
432 |
433 |
434 | /**
435 | * Go through the rel=me URLs obtained from the users URL and see
436 | * if any of those sites contain a rel=me which equals this user URL.
437 | *
438 | * @return URLs that have confirmed rel-me links back to user_url or false
439 | * @author Matt Harris and Tantek Çelik
440 | */
441 | function confirm_rels($user_url, $source_rels) {
442 | if (!is_array($source_rels)) {
443 | $this->error('No rels found.');
444 | return false;
445 | }
446 |
447 | $confirmed_rels = array();
448 | foreach ( $source_rels as $url => $text ) {
449 | if (confirm_rel($user_url, $url)) {
450 | $confirmed_rels[$url] = $text;
451 | }
452 | }
453 | if (count($confirmed_rels)>0) {
454 | return $confirmed_rels;
455 | }
456 | $this->error('No rels matched. Tried ' . implode(', ', array_keys($this->source_rels)));
457 | return false;
458 | }
459 |
460 | /**
461 | * Does the job of discovering rel="me" urls
462 | *
463 | * @return array of rel="me" urls for the given source URL
464 | * @author Matt Harris
465 | */
466 | function discover($source_url, $titles=true) {
467 | global $providers;
468 |
469 | $this->tmhOAuth->request('GET', $source_url, array(), false);
470 | if ($this->tmhOAuth->response['code'] != 200) {
471 | $this->error('Was expecting a 200 and instead got a '
472 | . $this->tmhOAuth->response['code']);
473 | error_log('got an unexpected response from ' . $source_url . ', '
474 | . json_encode($this->tmhOAuth->response));
475 | return false;
476 | }
477 |
478 | libxml_use_internal_errors(true); // silence HTML parser warnings
479 | $doc = new DOMDocument();
480 | if ( ! $doc->loadHTML($this->tmhOAuth->response['response']) ) {
481 | error_log('could not parse '.$source_url);
482 | $this->error('Looks like I can\'t do anything with ' . $source_url);
483 | return false;
484 | }
485 |
486 | $xpath = new DOMXPath($doc);
487 | $relmes = $xpath->query(xphasrel('me'));
488 | $base = self::real_url(
489 | self::html_base_href($xpath), $source_url
490 | );
491 |
492 | // get anything?
493 | if ( empty($relmes) ) {
494 | error_log('No rel-me tags found for ' . $source_url);
495 | return false;
496 | }
497 |
498 | // clean up the relmes
499 | $urls = array();
500 | foreach ($relmes as $rel) {
501 | $title = (string) $rel->getAttribute('title');
502 | $url = (string) $rel->getAttribute('href');
503 | $url = self::real_url($base, $url);
504 | if (empty($url))
505 | continue;
506 | $url = self::expand_tco($url);
507 |
508 | // trim extra trailing stuff from external profile URLs
509 | // workaround for providers failing to properly 301 to the shortest URL
510 | $provider = parse_url($url);
511 | if (array_key_exists($provider['host'], $providers))
512 | {
513 | $config = $providers[ $provider['host']];
514 | if (array_key_exists('rtrimprofile', $config)) {
515 | $url = rtrim($url,$config['rtrimprofile']);
516 | }
517 | }
518 |
519 | $title = empty($title) ? $url : $title;
520 | if ( $titles ) {
521 | $urls[ $url ] = $title;
522 | } else {
523 | $urls[] = $url;
524 | }
525 | }
526 | return $urls;
527 | }
528 |
529 | /**
530 | * Works out the base URL for the page for use when calculating relative and
531 | * absolute URLs. This function looks for the base element in the head of
532 | * the document and if found uses that as the html base href.
533 | *
534 | * @param string $simple_xml_element the SimpleXML representing the obtained HTML
535 | * @return the new base URL if found or empty string otherwise
536 | * @author Tantek Çelik
537 | */
538 | function html_base_href($xpath) {
539 | if ( ! $xpath)
540 | return '';
541 |
542 | $base_elements = $xpath->query('//head//base[@href]');
543 | return ( $base_elements && ( $base_elements->length > 0 ) ) ?
544 | $base_elements->item(0)->getAttribute('href') :
545 | '';
546 | }
547 |
548 | /**
549 | * Calculates the normalised URL for a given URL and base href. Absolute and
550 | * relative URLs are supported as well as full URIs.
551 | *
552 | * @param string $base the base href
553 | * @param string $url the URL to be normalised
554 | * @return void
555 | * @author Matt Harris and Tantek Çelik
556 | */
557 | function real_url($base, $url) {
558 | // has a protcol, and therefore assumed domain
559 | if (preg_matches('/^[\w-]+:/', $url)) {
560 | /*
561 | $parsed = parse_url($url);
562 | if ($parsed['path']==='') { // fix-up domain only URLs with a path
563 | $url .= '/';
564 | }
565 | */
566 | return $url;
567 | }
568 |
569 | // absolute URL
570 | if ( $url[0] == '/' ) {
571 | $url_bits = parse_url($base);
572 | $host = $url_bits['scheme'] . '://' . $url_bits['host'];
573 | return $host . $url;
574 | }
575 |
576 | // inspect base, check we have the directory
577 | $path = substr($base, 0, strrpos($base, '/')) . '/';
578 | // relative URL
579 |
580 | // explode the url with relatives in it
581 | $url = explode('/', $path.$url);
582 |
583 | // remove the domain as we can't go higher than that
584 | $base = $url[0].'//'.$url[2].'/';
585 | array_splice($url, 0, 3);
586 |
587 | // process each folder
588 | // for every .. remove the previous non .. in the array
589 | $keys = array_keys($url, '..');
590 | foreach( $keys as $idx => $dir ) {
591 | // work out the new offset for ..
592 | $offset = $dir - ($idx * 2 + 1);
593 |
594 | if ($offset < 0 && $url[0] == '..') {
595 | array_splice($url, 0, 1);
596 | } elseif ( $offset < 0 ) {
597 | // need to know where the new .. are
598 | return self::real_url($base, implode('/', $url));
599 | } else {
600 | array_splice($url, $offset, 2);
601 | }
602 | }
603 | $url = implode('/', $url);
604 | $url = str_replace('./', '', $url);
605 | return $base . $url;
606 | }
607 |
608 | /**
609 | * try and convert the string to SimpleXML
610 | *
611 | * @param string $str the HTML
612 | * @return SimpleXMLElement or false on fail
613 | * @author Matt Harris
614 | */
615 | // TODO this was replaced by DOMDocument::loadHTML; remove this function?
616 | function toXML($str) {
617 | $xml = false;
618 |
619 | try {
620 | $xml = @ new SimpleXMLElement($str);
621 | } catch (Exception $e) {
622 | if ( stripos('String could not be parsed as XML', $e->getMessage()) ) {
623 | return false;
624 | }
625 | }
626 | return $xml;
627 | }
628 |
629 | /**
630 | * Run tidy on the given string if it is installed. This function configures
631 | * tidy to support HTML5.
632 | *
633 | * @param string $html the html to run through tidy.
634 | * @return the tidied html or false if tidy is not installed.
635 | * @author Matt Harris
636 | */
637 | // TODO this shouldn't be necessary anymore with DOMDocument::loadHTML, remove it?
638 | function tidy($html) {
639 | if ( class_exists('tidy') ) {
640 | $tidy = new tidy();
641 | $config = array(
642 | 'bare' => TRUE,
643 | 'clean' => TRUE,
644 | 'indent' => TRUE,
645 | 'output-xml' => TRUE, // 'output-xhtml' => TRUE,
646 | // must be -xml to cleanup named entities that are ok in XHTML but not XML
647 | 'wrap' => 200,
648 | 'hide-comments' => TRUE,
649 | 'new-blocklevel-tags' => implode(' ', array(
650 | 'header', 'footer', 'article', 'section', 'aside', 'nav', 'figure',
651 | )),
652 | 'new-inline-tags' => implode(' ', array(
653 | 'mark', 'time', 'meter', 'progress',
654 | )),
655 | );
656 | $tidy->parseString( $html, $config, 'utf8' );
657 | $tidy->cleanRepair();
658 | $html = str_ireplace( '','', (string)$tidy );
659 | unset($tidy);
660 | return $html;
661 | } else {
662 | $this->error('no tidy :(');
663 | // need some other way to clean here. html5lib?
664 | return $html;
665 | }
666 | return false;
667 | }
668 |
669 | /**
670 | * Twitter now shortens rel-me URLs and replaces them with their
671 | * t.co short links (even in the return value from
672 | * verify_credentials). For this specific case, issue a HEAD request
673 | * to find the real URL.
674 | *
675 | * @param string $url the original URL, possibly a t.co short-link
676 | * @return the expanded URL if found; otherwise the unmodified original URL
677 | * @author Kyle Mahan
678 | */
679 | function expand_tco($url) {
680 | if (strpos($url, '/t.co/')) {
681 | $this->tmhOAuth->request('HEAD', $url, array(), false);
682 | if ($this->tmhOAuth->response['code'] == 301
683 | || $this->tmhOAuth->response['code'] == 302) {
684 | $redirect_url = $this->tmhOAuth->response['info']['redirect_url'];
685 | if ($redirect_url) {
686 | return $redirect_url;
687 | }
688 | }
689 | }
690 | return $url;
691 | }
692 |
693 | function redirect($url=false) {
694 | $url = ! $url ? $this->here() : $url;
695 | header( "Location: $url" );
696 | die;
697 | }
698 |
699 | function here($withqs=false) {
700 | $url = sprintf('%s://%s%s',
701 | $_SERVER['SERVER_PORT'] == 80 ? 'http' : 'https',
702 | $_SERVER['SERVER_NAME'],
703 | $_SERVER['REQUEST_URI']
704 | );
705 | $parts = parse_url($url);
706 | $url = sprintf('%s://%s%s',
707 | $parts['scheme'],
708 | $parts['host'],
709 | $parts['path']
710 | );
711 | if ($withqs) {
712 | $url .= '?' . $url['query'];
713 | }
714 | return $url;
715 | }
716 |
717 | function normalise_url($url) {
718 | $parts = parse_url($url);
719 | if ( ! isset($parts['path']))
720 | $url = $url . '/';
721 |
722 | return strtolower($url);
723 | }
724 | }
725 |
726 | ?>
727 |
--------------------------------------------------------------------------------