You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							176 lines
						
					
					
						
							4.8 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							176 lines
						
					
					
						
							4.8 KiB
						
					
					
				| <?php | |
| 
 | |
| /* | |
|  | |
| 	Copyright (c) 2009-2019 F3::Factory/Bong Cosca, All rights reserved. | |
|  | |
| 	This file is part of the Fat-Free Framework (http://fatfreeframework.com). | |
|  | |
| 	This is free software: you can redistribute it and/or modify it under the | |
| 	terms of the GNU General Public License as published by the Free Software | |
| 	Foundation, either version 3 of the License, or later. | |
|  | |
| 	Fat-Free Framework is distributed in the hope that it will be useful, | |
| 	but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | |
| 	General Public License for more details. | |
|  | |
| 	You should have received a copy of the GNU General Public License along | |
| 	with Fat-Free Framework.  If not, see <http://www.gnu.org/licenses/>. | |
|  | |
| */ | |
| 
 | |
| namespace Web; | |
| 
 | |
| //! Pingback 1.0 protocol (client and server) implementation | |
| class Pingback extends \Prefab { | |
| 
 | |
| 	protected | |
| 		//! Transaction history | |
| 		$log; | |
| 
 | |
| 	/** | |
| 	*	Return TRUE if URL points to a pingback-enabled resource | |
| 	*	@return bool | |
| 	*	@param $url | |
| 	**/ | |
| 	protected function enabled($url) { | |
| 		$web=\Web::instance(); | |
| 		$req=$web->request($url); | |
| 		$found=FALSE; | |
| 		if ($req['body']) { | |
| 			// Look for pingback header | |
| 			foreach ($req['headers'] as $header) | |
| 				if (preg_match('/^X-Pingback:\h*(.+)/',$header,$href)) { | |
| 					$found=$href[1]; | |
| 					break; | |
| 				} | |
| 			if (!$found && | |
| 				// Scan page for pingback link tag | |
| 				preg_match('/<link\h+(.+?)\h*\/?>/i',$req['body'],$parts) && | |
| 				preg_match('/rel\h*=\h*"pingback"/i',$parts[1]) && | |
| 				preg_match('/href\h*=\h*"\h*(.+?)\h*"/i',$parts[1],$href)) | |
| 				$found=$href[1]; | |
| 		} | |
| 		return $found; | |
| 	} | |
| 
 | |
| 	/** | |
| 	*	Load local page contents, parse HTML anchor tags, find permalinks, | |
| 	*	and send XML-RPC calls to corresponding pingback servers | |
| 	*	@return NULL | |
| 	*	@param $source string | |
| 	**/ | |
| 	function inspect($source) { | |
| 		$fw=\Base::instance(); | |
| 		$web=\Web::instance(); | |
| 		$parts=parse_url($source); | |
| 		if (empty($parts['scheme']) || empty($parts['host']) || | |
| 			$parts['host']==$fw->HOST) { | |
| 			$req=$web->request($source); | |
| 			$doc=new \DOMDocument('1.0',$fw->ENCODING); | |
| 			$doc->stricterrorchecking=FALSE; | |
| 			$doc->recover=TRUE; | |
| 			if (@$doc->loadhtml($req['body'])) { | |
| 				// Parse anchor tags | |
| 				$links=$doc->getelementsbytagname('a'); | |
| 				foreach ($links as $link) { | |
| 					$permalink=$link->getattribute('href'); | |
| 					// Find pingback-enabled resources | |
| 					if ($permalink && $found=$this->enabled($permalink)) { | |
| 						$req=$web->request($found, | |
| 							[ | |
| 								'method'=>'POST', | |
| 								'header'=>'Content-Type: application/xml', | |
| 								'content'=>xmlrpc_encode_request( | |
| 									'pingback.ping', | |
| 									[$source,$permalink], | |
| 									['encoding'=>$fw->ENCODING] | |
| 								) | |
| 							] | |
| 						); | |
| 						if ($req['body']) | |
| 							$this->log.=date('r').' '. | |
| 								$permalink.' [permalink:'.$found.']'.PHP_EOL. | |
| 								$req['body'].PHP_EOL; | |
| 					} | |
| 				} | |
| 			} | |
| 			unset($doc); | |
| 		} | |
| 	} | |
| 
 | |
| 	/** | |
| 	*	Receive ping, check if local page is pingback-enabled, verify | |
| 	*	source contents, and return XML-RPC response | |
| 	*	@return string | |
| 	*	@param $func callback | |
| 	*	@param $path string | |
| 	**/ | |
| 	function listen($func,$path=NULL) { | |
| 		$fw=\Base::instance(); | |
| 		if (PHP_SAPI!='cli') { | |
| 			header('X-Powered-By: '.$fw->PACKAGE); | |
| 			header('Content-Type: application/xml; '. | |
| 				'charset='.$charset=$fw->ENCODING); | |
| 		} | |
| 		if (!$path) | |
| 			$path=$fw->BASE; | |
| 		$web=\Web::instance(); | |
| 		$args=xmlrpc_decode_request($fw->BODY,$method,$charset); | |
| 		$options=['encoding'=>$charset]; | |
| 		if ($method=='pingback.ping' && isset($args[0],$args[1])) { | |
| 			list($source,$permalink)=$args; | |
| 			$doc=new \DOMDocument('1.0',$fw->ENCODING); | |
| 			// Check local page if pingback-enabled | |
| 			$parts=parse_url($permalink); | |
| 			if ((empty($parts['scheme']) || | |
| 				$parts['host']==$fw->HOST) && | |
| 				preg_match('/^'.preg_quote($path,'/').'/'. | |
| 					($fw->CASELESS?'i':''),$parts['path']) && | |
| 				$this->enabled($permalink)) { | |
| 				// Check source | |
| 				$parts=parse_url($source); | |
| 				if ((empty($parts['scheme']) || | |
| 					$parts['host']==$fw->HOST) && | |
| 					($req=$web->request($source)) && | |
| 					$doc->loadhtml($req['body'])) { | |
| 					$links=$doc->getelementsbytagname('a'); | |
| 					foreach ($links as $link) { | |
| 						if ($link->getattribute('href')==$permalink) { | |
| 							call_user_func_array($func,[$source,$req['body']]); | |
| 							// Success | |
| 							die(xmlrpc_encode_request(NULL,$source,$options)); | |
| 						} | |
| 					} | |
| 					// No link to local page | |
| 					die(xmlrpc_encode_request(NULL,0x11,$options)); | |
| 				} | |
| 				// Source failure | |
| 				die(xmlrpc_encode_request(NULL,0x10,$options)); | |
| 			} | |
| 			// Doesn't exist (or not pingback-enabled) | |
| 			die(xmlrpc_encode_request(NULL,0x21,$options)); | |
| 		} | |
| 		// Access denied | |
| 		die(xmlrpc_encode_request(NULL,0x31,$options)); | |
| 	} | |
| 
 | |
| 	/** | |
| 	*	Return transaction history | |
| 	*	@return string | |
| 	**/ | |
| 	function log() { | |
| 		return $this->log; | |
| 	} | |
| 
 | |
| 	/** | |
| 	*	Instantiate class | |
| 	*	@return object | |
| 	**/ | |
| 	function __construct() { | |
| 		// Suppress errors caused by invalid HTML structures | |
| 		libxml_use_internal_errors(TRUE); | |
| 	} | |
| 
 | |
| }
 | |
| 
 |