Просмотр файла news/libraries/web/pingback.php

Размер файла: 4.65Kb
  1. <?php
  2.  
  3. /*
  4. Copyright (c) 2009-2014 F3::Factory/Bong Cosca, All rights reserved.
  5.  
  6. This file is part of the Fat-Free Framework (http://fatfree.sf.net).
  7.  
  8. THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF
  9. ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  10. IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  11. PURPOSE.
  12.  
  13. Please see the license.txt file for more information.
  14. */
  15.  
  16. namespace Web;
  17.  
  18. //! Pingback 1.0 protocol (client and server) implementation
  19. class Pingback extends \Prefab {
  20.  
  21. protected
  22. //! Transaction history
  23. $log;
  24.  
  25. /**
  26. * Return TRUE if URL points to a pingback-enabled resource
  27. * @return bool
  28. * @param $url
  29. **/
  30. protected function enabled($url) {
  31. $web=\Web::instance();
  32. $req=$web->request($url);
  33. $found=FALSE;
  34. if ($req && $req['body']) {
  35. // Look for pingback header
  36. foreach ($req['headers'] as $header)
  37. if (preg_match('/^X-Pingback:\h*(.+)/',$header,$href)) {
  38. $found=$href[1];
  39. break;
  40. }
  41. if (!$found &&
  42. // Scan page for pingback link tag
  43. preg_match('/<link\h+(.+?)\h*\/?>/i',$req['body'],$parts) &&
  44. preg_match('/rel\h*=\h*"pingback"/i',$parts[1]) &&
  45. preg_match('/href\h*=\h*"\h*(.+?)\h*"/i',$parts[1],$href))
  46. $found=$href[1];
  47. }
  48. return $found;
  49. }
  50.  
  51. /**
  52. * Load local page contents, parse HTML anchor tags, find permalinks,
  53. * and send XML-RPC calls to corresponding pingback servers
  54. * @return NULL
  55. * @param $source string
  56. **/
  57. function inspect($source) {
  58. $fw=\Base::instance();
  59. $web=\Web::instance();
  60. $parts=parse_url($source);
  61. if (empty($parts['scheme']) || empty($parts['host']) ||
  62. $parts['host']==$fw->get('HOST')) {
  63. $req=$web->request($source);
  64. $doc=new \DOMDocument('1.0',$fw->get('ENCODING'));
  65. $doc->stricterrorchecking=FALSE;
  66. $doc->recover=TRUE;
  67. if ($req && @$doc->loadhtml($req['body'])) {
  68. // Parse anchor tags
  69. $links=$doc->getelementsbytagname('a');
  70. foreach ($links as $link) {
  71. $permalink=$link->getattribute('href');
  72. // Find pingback-enabled resources
  73. if ($permalink && $found=$this->enabled($permalink)) {
  74. $req=$web->request($found,
  75. array(
  76. 'method'=>'POST',
  77. 'header'=>'Content-Type: application/xml',
  78. 'content'=>xmlrpc_encode_request(
  79. 'pingback.ping',
  80. array($source,$permalink),
  81. array('encoding'=>$fw->get('ENCODING'))
  82. )
  83. )
  84. );
  85. if ($req && $req['body'])
  86. $this->log.=date('r').' '.
  87. $permalink.' [permalink:'.$found.']'.PHP_EOL.
  88. $req['body'].PHP_EOL;
  89. }
  90. }
  91. }
  92. unset($doc);
  93. }
  94. }
  95.  
  96. /**
  97. * Receive ping, check if local page is pingback-enabled, verify
  98. * source contents, and return XML-RPC response
  99. * @return string
  100. * @param $func callback
  101. * @param $path string
  102. **/
  103. function listen($func,$path=NULL) {
  104. $fw=\Base::instance();
  105. if (PHP_SAPI!='cli') {
  106. header('X-Powered-By: '.$fw->get('PACKAGE'));
  107. header('Content-Type: application/xml; '.
  108. 'charset='.$charset=$fw->get('ENCODING'));
  109. }
  110. if (!$path)
  111. $path=$fw->get('BASE');
  112. $web=\Web::instance();
  113. $args=xmlrpc_decode_request($fw->get('BODY'),$method,$charset);
  114. $options=array('encoding'=>$charset);
  115. if ($method=='pingback.ping' && isset($args[0],$args[1])) {
  116. list($source,$permalink)=$args;
  117. $doc=new \DOMDocument('1.0',$fw->get('ENCODING'));
  118. // Check local page if pingback-enabled
  119. $parts=parse_url($permalink);
  120. if ((empty($parts['scheme']) ||
  121. $parts['host']==$fw->get('HOST')) &&
  122. preg_match('/^'.preg_quote($path,'/').'/'.
  123. ($fw->get('CASELESS')?'i':''),$parts['path']) &&
  124. $this->enabled($permalink)) {
  125. // Check source
  126. $parts=parse_url($source);
  127. if ((empty($parts['scheme']) ||
  128. $parts['host']==$fw->get('HOST')) &&
  129. ($req=$web->request($source)) &&
  130. $doc->loadhtml($req['body'])) {
  131. $links=$doc->getelementsbytagname('a');
  132. foreach ($links as $link) {
  133. if ($link->getattribute('href')==$permalink) {
  134. call_user_func_array($func,
  135. array($source,$req['body']));
  136. // Success
  137. die(xmlrpc_encode_request(NULL,$source,$options));
  138. }
  139. }
  140. // No link to local page
  141. die(xmlrpc_encode_request(NULL,0x11,$options));
  142. }
  143. // Source failure
  144. die(xmlrpc_encode_request(NULL,0x10,$options));
  145. }
  146. // Doesn't exist (or not pingback-enabled)
  147. die(xmlrpc_encode_request(NULL,0x21,$options));
  148. }
  149. // Access denied
  150. die(xmlrpc_encode_request(NULL,0x31,$options));
  151. }
  152.  
  153. /**
  154. * Return transaction history
  155. * @return string
  156. **/
  157. function log() {
  158. return $this->log;
  159. }
  160.  
  161. /**
  162. * Instantiate class
  163. * @return object
  164. **/
  165. function __construct() {
  166. // Suppress errors caused by invalid HTML structures
  167. libxml_use_internal_errors(TRUE);
  168. }
  169.  
  170. }