PageRenderTime 74ms CodeModel.GetById 13ms app.highlight 40ms RepoModel.GetById 9ms app.codeStats 1ms

/xengine.php

https://github.com/xopherdeep/x4deep0.1
PHP | 1452 lines | 1025 code | 197 blank | 230 comment | 122 complexity | 062a8eca9e4b54df39a52c4060d24268 MD5 | raw file
   1<?php
   2	/**
   3	 * Xengine Version 2.x
   4	 * @author XopherDeeP <heylisten@xtiv.net>
   5	 * @version v2.0.0-beta1.1
   6	**/
   7
   8	/*
   9	  Xengine Version 2 address the fact that Xtras and HTML files are stored in their own containing Directory.
  10	  v1 split the Xtras into x/xtra and html files into html/frontdoor & html/backdoor
  11	  v2 now splits the xtrans into x/_suite_/_xTra_/
  12	    where xTra contains all php and html/tpl files, along with css & js files.
  13
  14	*/
  15
  16
  17	# Xengine is Small and PowerFull; Hook into it using Xtras. The Xengine Idea is: Drop and Build!
  18	# It setups an easy to use connection between Clean URLs and PHP Classes
  19	# The eXtend PHP Classes with Xengine allowing Easy Access to the the DB using $q = $this->q(); 
  20	# The DB doesn't connect until the function is called, once connected, it can be accessed via $this->Q
  21	# The CleanURL Structure is as Follows: domain.com/class/method/param1/param2/param3/etc
  22	# where class is the class name found in the Xtra's. ex: xClass.php, the method should be found there.
  23	# If there is an HTML page to render with the method, the files go in the html dir, 
  24
  25	class Xengine
  26	{
  27		var $_CFG;
  28		var $_SET = array(
  29			'action'	=> '',
  30			'method'	=> '',
  31			'HTML' => array(
  32				'HEAD' => array(
  33					'TITLE' => null,
  34					'CSS'   => '',
  35					'JS'    => '',
  36					'STYLE' => ''
  37				),
  38				'BODY' => array(
  39					'HTML' => '',
  40					'CSS'  => '',
  41					'JS'   => ''
  42				)
  43			)
  44		);
  45		var $_DBF;
  46		var $Xtra;
  47		var $method;
  48		var $_debugReport = array();
  49
  50		function __construct($cfg = false,$parent = false)
  51		{
  52			define('DOC_ROOT'	,$_SERVER['DOCUMENT_ROOT']);
  53		
  54			// Glue some configss together
  55			$cfg['dir']['cfg']   = DOC_ROOT.'/'.$cfg['dir']['backdoor'].'/'. $cfg['dir']['cfg'];
  56			$cfg['dir']['libs']  = $cfg['dir']['backdoor'].'/'. $cfg['dir']['libs'];
  57			$cfg['dir']['Xtra']  = $cfg['dir']['backdoor'] + '/' + $cfg['dir']['Xtra'];
  58			
  59			define('LIBS_DIR'	,DOC_ROOT.'/'.$cfg['dir']['libs']); 			# Location of the Library Files
  60			define('XPHP_DIR'	,DOC_ROOT.'/'.$cfg['dir']['Xtra']); 			# Location of the Xtras Files
  61			
  62
  63			$cfg['dir']['libs'] = LIBS_DIR;
  64			// SETUP Xengine based on x.cfg
  65			define('BIN'		,DOC_ROOT.'/'.$cfg['dir']['Xtra']); 				# Location of the Bin Files
  66			set_include_path(LIBS_DIR);
  67
  68			$this->_comment("Xengine Started!");
  69			ini_set('display_errors', $cfg['debug']['on']);
  70
  71			if(!$cfg)
  72				die("Configuration Needed");
  73
  74			// We need to be able to write to this directory...
  75			if(!is_writeable($cfg['dir']['cfg'])){
  76				die($cfg['dir']['cfg']." Not Writable!");
  77					
  78			}
  79
  80
  81			$this->_CFG   = $cfg;
  82			$this->_LANG  = $cfg['lang'] ;
  83			$this->_BOTS  = $cfg['bots_list'];
  84
  85			if(!defined('DB_CFG'))
  86				define("DB_CFG", $cfg['dir']['cfg']."/cfg.db.$_SERVER[HTTP_HOST].inc");
  87		}
  88
  89
  90		/*
  91			The Client has 'Knocked' on the website's 'Door'
  92			Identify the whole: user, location, content, module, timestamp
  93			Decide what to do with them. 
  94		*/
  95		public function knock()
  96		{
  97			try {
  98				register_shutdown_function(array( &$this, "shutDownFunction" ));
  99
 100				$this->keyhole();											// Identify the Whole.
 101				$this->openDoor();											// Open the Door a.k.a Execute Mods.
 102				$this->browse(); 											// Display the Content, HTML, JSON, XML, JPEG.
 103				exit;														// EXIT
 104			}catch(Exception $e){ 
 105				$this->reportSystemError(array(
 106					'summary'     => 'X ERROR :: '.$e->getMessage(), 
 107					'description' => $e->getMessage(),
 108					'attr' => array(
 109						'type'      => 'defect',
 110						'component' => 'x'.ucfirst($this->_SET['action']),
 111						'priority'  => 'trivial',
 112						'reporter'  => $_SESSION['user']['username'].'@'.$_SERVER['HTTP_HOST'],
 113						'keywords'  =>  $this->_SET['action'].'::'. $this->_SET['method'],
 114						'milestone' => 'Bee Hive'
 115					)
 116    			));
 117				$this->set(array(
 118					'action' => 'access',
 119					'method' => 'error',
 120					'params' => array(
 121						'error' => $e->getMessage()
 122					),
 123					'request' => array(
 124						'action' => $this->_SET['action'],
 125						'method' => $this->_SET['method']
 126					)
 127				));
 128				//$this->dump($this->_SET);
 129				$this->browse(); 
 130			}
 131		}
 132
 133		private function keyhole()
 134		{
 135			session_start();
 136
 137			// Who Am I?
 138			$this->whoAmI();
 139			
 140			// Where Am I?
 141			$this->whereAmI();
 142 			
 143 			// What Content Type am I
 144			$this->whatAmI();
 145			
 146			// How Am I Built
 147 			$this->howAmI();
 148
 149			// When Am I Happening
 150			// $this->whenAmI();
 151			
 152			// Why Am I Existing
 153			// $this->whyAmI();
 154 			
 155 			
 156		}
 157
 158		// The Key holds an array of Bool
 159		private function whoAmI($who=false)
 160		{
 161			// Define Their KEY - Refrenced for Access. 
 162			$this->Key = array(
 163				'is' => array(
 164					'admin'   => isset($_SESSION['user']) ?  ($_SESSION['user']['power_lvl'] > 7)  : false,
 165					'user'    => (isset($_SESSION['user']) && !empty($_SESSION['user'])) ,
 166					'guest'   => ( isset($_SESSION['user'] ) != true),
 167					'bot'     => ( preg_match('/'.implode("|", $this->_BOTS).'/', $_SERVER['HTTP_USER_AGENT'], $matches) ) ? 
 168						array_search($matches[0], $bots_list) : false
 169				)
 170			); 
 171
 172		}
 173
 174		private function whereAmI()
 175		{
 176			// This Function Sets all the variables on where the Client IS based on the URL they've Hit.
 177			$this->uri         = substr( $_SERVER['REQUEST_URI'], 1 );	// Begins with a / - slice it off.
 178			$this->url         = parse_url( $this->uri );				
 179			$this->_SET['params']        = (isset($this->url['path'])) ? explode('/', $this->url['path']) : array('/');
 180			
 181			
 182			if(!isset($this->_SET['params'][1])){
 183				$this->_SET['params'] = array('','');
 184			}
 185
 186			// BOOL
 187			$this->atSideDoor  = ($this->_SET['params'][0] === $this->_CFG['dir']['sidedoor'] 
 188				|| $this->_SET['params'][1] === $this->_CFG['dir']['sidedoor']);	
 189
 190			// Back Door - Admin Panel of Pages. 
 191			$this->atBackDoor  = ($this->_SET['params'][0] === $this->_CFG['dir']['backdoor']);	// BOOL
 192
 193
 194			$this->atMailBox   = ($this->_SET['params'][0] === $this->_CFG['dir']['bin']);		// BOOL
 195			
 196		}
 197
 198		public function whatAmI()
 199		{
 200			// Let's Discover if this document is looking for an extension
 201			$e = explode('.', $this->url['path']);
 202			$this->Key['is']['content'] = (count($e) > 1) ? $e[count($e)-1] : 'html';
 203		}
 204
 205		// Here we determine what it is the client is trying to access. 
 206		private function howAmI()
 207		{	
 208			// ../Xtra/method/param1/param2/param3/etc	
 209			$p = $this->_SET['params'];
 210			$this->_SET['action'] = $this->_SET['method'] = 'index';
 211
 212			// If we are at the back door, remove it out of our params.
 213			if ($this->atBackDoor) {
 214				unset($p[0]);
 215				$p = array_values($p);
 216			}
 217
 218			if ($this->atSideDoor) {
 219				unset($p[0]);
 220				$p = array_values($p);
 221			}
 222
 223			if ( isset($p[0]) ) {
 224				$this->_SET['action']   = ($p[0]) ? $p[0] : 'index';
 225				unset($p[0]);
 226			}
 227
 228			if ( isset($p[1]) ) {
 229				$this->_SET['method'] = ($p[1]) ? $p[1] : 'index';
 230				unset($p[1]);
 231			}
 232
 233			foreach ($p as $key => $value) {
 234				if($value == '.json' || $value == '.xml'){
 235					$_SESSION['output'] = 'json';
 236					unset($p[$key]);
 237
 238				}
 239			}
 240
 241			$this->_SET['params'] = $p;
 242		}
 243
 244		private function openDoor()
 245		{
 246			// Door #1 
 247			// If we Do not have a DB Connected & Setup; Run through the DB Setup.
 248			if( false == file_exists(DB_CFG) ){
 249				// We need to know how to connect to our db first!
 250				// This Xtra configures the Connection to the Database. 
 251				$this->_SET['action'] = 'wwwSetup';
 252				$this->_SET['method'] = 'install';
 253				$this->atSideDoor     = true;
 254				//$this->dump()
 255			} else {		
 256				// With the DB communicating, we able to Run! 
 257				// Let the Dogs Run and Bark at them: AutoRuns. 
 258				// Access, Login, Analytics, Backup, wwwSetup
 259				$this->autoRunSniff();
 260			}
 261			
 262			// The Door is Open; All the Xtras are Locked & Loaded; the Xengine is Up and Running;
 263			// Allow them to the Walk the Path Requested, ie: /login/logout )
 264			$this->walkPath();
 265		}
 266
 267		/*
 268			Here is where we loop through the autoRun methods
 269			allowing them to sniff the Request and do their own Magic.
 270		*/ 
 271
 272		private function autoRunSniff(){
 273			// autoRun the  requisets.
 274			$this->_comment("Running AutoRun Xtra's");
 275			//	$this->dump($this->q());
 276			$q = $this->q();
 277
 278			// ok... we have a db file. but do we have a db!?
 279			$this->Q("SHOW TABLES LIKE '".$this->Q->db['prefix']."configs'");
 280
 281
 282
 283    		if($q->ERROR){
 284    			// Log the Error to The Trac System!!!!
 285				$sql = '';
 286
 287				if(isset( $this->Q->sql )){
 288					$sql = $this->removeLocalData($this->lang( 
 289						$this->_LANG['DB']['ERROR']['SQL'],
 290						array('sql' => $this->Q->sql)
 291					),$this->Q);
 292				}
 293
 294				$description = '';
 295				$description .= $sql;	
 296
 297				$error = array(
 298					'summary'     => 'DB ERROR :: '.$this->removeLocalData($this->Q->ERROR,$this->Q), 
 299					'description' => $description,
 300					'attr' => array(
 301						'type'      => 'defect',
 302						//'component' => 'x'.ucfirst($this->_SET['action']),
 303						'priority'  => 'trivial',
 304						'reporter'  => $_SESSION['user']['username'].'@'.$_SERVER['HTTP_HOST'],
 305						'keywords'  =>  $this->_SET['action'].'::'. $this->_SET['method']
 306					)
 307    			);
 308
 309				$this->reportSystemError($error);
 310
 311				$this->set(array(
 312					'action' => 'access',
 313					'method' => 'db',
 314					'params' => array( $this->uri, $q->ERROR )
 315				));
 316    		}else{
 317		    	if(isset($_GET['theme'])){
 318		    		$this->STYLE = $_GET['theme'];
 319		    	}
 320
 321				$xphp = $this->getXtras();
 322				
 323    			foreach($xphp as $k => $x){
 324    				try {	    			
 325	    				$class = $x['class'];		
 326						$methods = get_class_methods($class);
 327
 328    					if(in_array('autoRun', $methods)){	 
 329							$this->_comment("Auto Run: ". $class);	
 330							
 331							$this->_xtra = $class;
 332							// $return = $class::autoRun($this);
 333
 334							$class = new $class($this->_CFG);
 335							$class = $this->mergeO($class,$this);
 336							$return = call_user_func_array(array($class,'autoRun'), array($this));
 337
 338							$this->_comment('AutoRan '.get_class($class).': ');
 339
 340							foreach ($class as $key => $value) {
 341								$this->$key = $value;
 342							}
 343
 344
 345							if(is_array($return)){
 346								$this->_SET = $this->set($return);
 347								$this->_SET = array_merge($return,$this->_SET);
 348							}
 349
 350
 351							$this->_comment("AutoRun Found in: ".get_class($class)." ~ Complete...");
 352	    				}
 353    				} catch (Exception $e) {
 354    					$this->_comment($e->getMessage());
 355    				}
 356	    		}
 357    		}
 358		}
 359
 360		private function walkPath()
 361		{
 362			$this->_comment("Xtra: ".$this->_SET['action']." | Method:".$this->_SET['method']);
 363			// Look to see if any Xtra matches
 364			$Xtra = 'x'.ucwords($this->_SET['action']);
 365
 366			$this->_comment("Looking for Class $Xtra");
 367			$php  = XPHP_DIR."/$Xtra.php";
 368			$this->_comment("Looking for file $php");
 369			if( file_exists($php) ){
 370				$this->runXtra($Xtra,$php);
 371			}
 372		}
 373
 374		function is_class_method($type="public", $method, $class) {
 375			    $refl = new ReflectionMethod($class, $method);
 376			    switch($type) {
 377			        case "static":
 378			        	return $refl->isStatic();
 379			        break;
 380			        case "public":
 381			        	return $refl->isPublic();
 382			        break;
 383			        case "private":
 384			        	return $refl->isPrivate();
 385			        break;
 386			    }
 387			}
 388
 389		private function runXtra($Xtra,$php)
 390		{
 391			# require the dynamic file.
 392			require_once($php);
 393			# create a new class
 394
 395			$Xtra = new $Xtra($this->_CFG);
 396			$Xtra = $this->mergeO($Xtra,$this);
 397
 398			# if the method exists...
 399			if( method_exists($Xtra,$this->_SET['method']) && $this->is_class_method('public',$this->_SET['method'],$Xtra) )
 400			{
 401				// $Xtra->Q = $this->Q;
 402    			# call the function w/ params
 403    			$this->_comment("Running $php");	
 404
 405    			array_values($this->_SET['params']);
 406
 407
 408    		 
 409				$return = call_user_func_array( array($Xtra,$this->_SET['method']), $this->_SET['params'] );
 410
 411
 412				$this->_SET = $this->apply($this->_SET,$Xtra->_SET); 
 413				
 414				if(is_array($return))
 415					$this->_SET = array_merge($return,$this->_SET);
 416				
 417
 418
 419				// $this->dump($this->_SET); 
 420
 421				# We might have logged in...
 422    			$this->whoAmI($this->Key);
 423    			$this->whatAmI($this->Key);
 424
 425				if($return && $this->_SET['action'] == 'login' && $this->Key['is']['user']){
 426					//$this->_SET['action'] = (isset($this->wait['Xtra'])) ? $this->wait['Xtra'] : $this->_SET['action'] ;
 427					//$this->_SET['method'] = (isset($this->wait['method'])) ? $this->wait['method'] : $this->_SET['method'];
 428					// Run this over on more time...
 429					//$this->walkThru();
 430					// makes for a quick No-redirect ;)		
 431					//unset($_POST['password']);
 432				}
 433			# Illegal Method has been Called!
 434    		}else{
 435
 436    			// Test to see if Navi knows where to go.
 437
 438
 439    			# Kill the Engine send a 404!!
 440				$this->_SET['action']   = 'access';
 441				$this->_SET['method'] = 'notFound';
 442				$this->_SET['params']($this->_LANG['404'],$this->_LANG['404_msg']);
 443    		}
 444		}
 445
 446		private function browse() 
 447		{			
 448			$this->_comment("Sending data to Browser");			
 449			// Dislays/Outputs Data To Browser.
 450			
 451	    	$this->set('IS_USER',$this->Key['is']['user']);
 452			$this->set('IS_ADMIN',$this->Key['is']['admin']);
 453
 454			$this->display($this->Key['is']['content'], $this->_SET);
 455
 456			//$this->dump($this->_SET);
 457		//	exit;
 458
 459		}
 460
 461		private function display($type='html',$array)
 462		{ 
 463			// Choose which type of content we are displaying.
 464			//exit;
 465			ob_clean();
 466			if(isset($_REQUEST['callback'])){
 467				$callback = $_REQUEST['callback'];
 468				//start output
 469				if ($callback) {
 470				    header('Content-Type: text/javascript');
 471				    echo $callback . '(' . json_encode($array) . ');';
 472				} else {
 473				    header('Content-Type: application/x-json');
 474				    echo json_encode($array);
 475				}	
 476				exit;
 477			}else{
 478				switch ($type) {
 479					default:
 480						# HTML
 481						header('Content-Type: text/html');
 482						$this->viewTemplate();
 483					break;
 484
 485					case 'json': 
 486						ob_clean();	
 487						unset($array['HTML']);
 488						unset($array['ICON']);
 489						unset($array['admin_menu']);
 490						unset($array['xtras']);
 491						header('Content-type: text/javascript');
 492		    			echo json_encode($array);
 493					break;
 494					
 495					case ('xml'): 
 496						ob_clean();	
 497						header('Content-Type: text/xml');
 498		    			echo $this->viewXml($array); 
 499					break;
 500				}	
 501			}
 502		}
 503
 504		private function viewTemplate(){
 505			// This handles the templating, which file to load, what theme to request, what thumbnailer to use.
 506
 507			// Pre Bootstrap...
 508			// $layout = ($this->atBackDoor) ? 'backdoor' : 'frontdoor';
 509
 510			$layout = ($this->atBackDoor) ? 'watchtower' : 'frontdoor';
 511
 512
 513
 514			$layout = ($this->atSideDoor) ? 'sidedoor' : $layout;
 515			
 516			// Regardless of Door, if there is a DB error...
 517			// @TODO This Could be caught earlier... though
 518
 519			// $this->dump($this->lang( 
 520			// 	$this->_LANG['DB']['ERROR']['SQL'],
 521			// 	array('sql' => $this->Q->mSql)
 522			// ));
 523
 524			// DATABASE ERROR
 525			if(false !== $this->Q->ERROR && file_exists(DB_CFG)){
 526				// function removeLocalData($r,$Q)
 527				// {
 528				// 	$r = str_replace($Q->db['database'].'.', '', $r);
 529				// 	$r = str_replace($Q->db['prefix'], '', $r);
 530				// 	return $r;
 531				// } 
 532
 533				$sql = '';
 534
 535				if(isset( $this->Q->sql )){
 536					$sql = $this->removeLocalData($this->lang( 
 537						$this->_LANG['DB']['ERROR']['SQL'],
 538						array('sql' => $this->Q->sql)
 539					),$this->Q);
 540				}
 541
 542				$description = '';
 543				$description .= $sql;	
 544
 545				$error = array(
 546					'summary'     => 'DB ERROR :: '.$this->removeLocalData($this->Q->ERROR,$this->Q), 
 547					'description' => $description,
 548					'attr' => array(
 549						'type'      => 'defect',
 550						'component' => 'xCore',//.ucfirst($this->_SET['action']),
 551						'priority'  => 'trivial',
 552						'reporter'  => $_SESSION['user']['username'].'@'.$_SERVER['HTTP_HOST'],
 553						'keywords'  =>  $this->_SET['action'].'::'. $this->_SET['method']
 554					)
 555    			);
 556
 557				//$this->reportSystemError($error);
 558
 559				$layout = 'sidedoor';
 560				$this->set(array(
 561					'action' => 'access', 
 562					'method' => 'db', 
 563					'request' => $this->Q->ERROR, 
 564					'reason' => $this->lang( 
 565						$this->_LANG['DB']['ERROR']['SQL'],
 566						array('sql' => $this->Q->sql)
 567					)
 568				)); 
 569			}
 570
 571			$lib = explode('/', $this->_CFG['dir']['libs']);
 572			$lib = $lib[count($lib)-1];
 573
 574
 575			// This is our last chance to change the output's HTML template.  
 576			$html_door = ($this->atBackDoor) ? $this->_CFG['html']['private'] : $this->_CFG['html']['public'];
 577
 578			// Override any all all links with custom navigation.
 579			if( isset($this->Key['heylisten']) ){
 580				// Get List of Bloxs.
 581				$this->set(array(
 582					'action' => 'index',
 583					'method' => 'index'
 584				));	 
 585
 586			}else if(!file_exists($this->_CFG['dir']['html']
 587				.'/'.$html_door
 588				.'/'.$this->_SET['action']
 589				.'/'.$this->_SET['method']
 590				.'.html')
 591			){
 592				$this->set(array(
 593					'action' => 'access',
 594					'method' => '404'
 595				));				
 596				//$this->_SET['HTML']['HEAD']['TITLE'] = "Page Template Not Found";
 597			}
 598
 599
 600			if(is_array($this->_SET['_LANG'])){
 601				$lang = array_merge_recursive($this->_LANG,$this->_SET['_LANG']); 
 602			}
 603
 604
 605			// $this->dump($lang);
 606
 607			$assign = array(
 608				'Xtra'        => $this->_SET['action'],
 609				'method'      => $this->_SET['method'],
 610				'params'      => $this->_SET['params'],
 611				'Door'        => $html_door,
 612				'toBackDoor'  => $this->_CFG['dir']['backdoor'],
 613				'toFrontDoor' => $this->_CFG['dir']['frontdoor'],
 614				'toSideDoor'  => $this->_CFG['dir']['sidedoor'],
 615				'HTTP_HOST'   => $_SERVER['HTTP_HOST'],
 616				'html_title'  => $_SERVER['HTTP_HOST'],
 617				'USER'        => $_SESSION['user'],
 618				'ERROR'       => false, // Set this to Display an Error
 619				
 620				// Sets the template variable TPL_EXISTS to make sure we have the page
 621				'LANG'        => $lang ,
 622				
 623				// KEY
 624				'masterKey' => $this->Key,
 625
 626				// Depreciate
 627				'IS_ADMIN'    => $this->_LANG,
 628				'blox'        => false,
 629				'LAYOUT'      => $layout,
 630				'LAYOUTS'     =>  $this->_CFG['html'],
 631				'thumb'       => '/'.$this->_CFG['dir']['backdoor'].'/'.$lib.'/phpThumb/phpThumb.php?f=png&q=100&'
 632
 633			);
 634
 635			$assign['TPL_EXISTS'] = file_exists(str_replace("//","/",$this->_CFG['dir']['html'].'/'.$assign['Door'].'/'.$this->_SET['action'].'/'.$this->_SET['method'].'.html'));
 636
 637			$this->_SET['HTML']['JSAN'] = file_get_contents($this->_CFG['dir']['bin'].'/js/ux/JSAN.js');
 638
 639			// Initate Smarty and Pass the assigned vars.
 640			$this->initSmarty(array_merge($assign, $this->_SET));
 641		}
 642
 643 		/**
 644	     * initSmarty() includes the smarty files and configures the new class:
 645	     * @return new Smarty() w/ cfg;
 646	     */
 647		private function initSmarty($a){
 648			# Include the Smarty Class
 649			
 650			$this->lib($this->_CFG['SMARTY_V'].'/libs/Smarty.class.php');
 651
 652			$dir          = LIBS_DIR."/".$this->_CFG['SMARTY_V'];
 653			
 654			// Be sure to clean again.
 655			
 656			//ob_clean();
 657			
 658			# Start the Smarty Class
 659			$this->smarty               = new Smarty();	
 660			# Configure Smarty			
 661			$this->smarty->compile_dir  = $dir."/templates_c";
 662			$this->smarty->cache_dir    = $dir."/cache";
 663			$this->smarty->config_dir   = $dir."/configs";
 664
 665
 666			
 667
 668 
 669
 670			 
 671			$this->smarty->template_dir = $this->_CFG['dir']['html'];
 672			$this->smarty->assign($a);			
 673
 674			
 675			//
 676			// if($this->_CFG['debug']['cache']  == false){
 677			// 	$this->smarty->clearAllCache();
 678			// }
 679
 680
 681			ob_clean();
 682			$this->smarty->display('index.tpl');
 683			//
 684			if($this->_CFG['debug']['cache']  == false){
 685				$this->smarty->clearAllCache();
 686			}
 687
 688			return $this->smarty;
 689		}
 690
 691 		
 692	    private function ob_start(){
 693	    	/** Improve buffer usage and compression */
 694			if (function_exists('ob_start')){
 695				/** Check that Zlib is not enabled by default (value should be 1-9, else it will be an empty string) */
 696				if (@ini_get('zlib.output_compression') || !function_exists('ob_gzhandler')){
 697					ob_start();
 698				}else{
 699					ob_start('ob_gzhandler');
 700				}
 701			}
 702	    }
 703
 704		/**
 705		 * The main function for converting to an XML document.
 706		 * Pass in a multi dimensional array and this recrusively loops through and builds up an XML document.
 707		 *
 708		 * @param array $data
 709		 * @param string $rootNodeName - what you want the root node to be - defaultsto data.
 710		 * @param SimpleXMLElement $xml - should only be used recursively
 711		 * @return string XML
 712		 */
 713		private function viewXml($data, $rootNodeName = 'data', $xml=null)
 714		{
 715			// turn off compatibility mode as simple xml throws a wobbly if you don't.
 716			ini_set ('zend.ze1_compatibility_mode', 0);
 717
 718			if ($xml == null)
 719			{
 720				$xml = simplexml_load_string("<?xml version='1.0' encoding='utf-8'?><$rootNodeName />");
 721			}
 722
 723			// loop through the data passed in.
 724			foreach($data as $key => $value)
 725			{
 726				// no numeric keys in our xml please!
 727				if (is_numeric($key))
 728				{
 729					// make string key...
 730					$key = "unknownNode_". (string) $key;
 731				}
 732
 733				// replace anything not alpha numeric
 734				$key = preg_replace('/[^a-z]/i', '', $key);
 735
 736				// if there is another array found recrusively call this function
 737				if (is_array($value))
 738				{
 739					$node = $xml->addChild($key);
 740					// recrusive call.
 741					$this->viewXml($value, $rootNodeName, $node);
 742				} else {
 743					// add single node.
 744	                $value = htmlentities($value);
 745					$xml->addChild($key,$value);
 746				}
 747			}
 748			// pass back as string. or simple xml object if you want!
 749			return $xml->asXML();
 750		}
 751
 752		/*
 753		 * lib($file) a simple include function to easily grab
 754		 * the location of our library files
 755		 */
 756		public function lib($file){
 757			$this->_comment(get_class($this)." Requesting Library $file");
 758			try{
 759				require_once(LIBS_DIR.'/'.$file);
 760			}catch(Exception $e){
 761				throw new Exception(get_class($this)." Failed to Load Library: ".$file, 1); 
 762			} 
 763		}
 764
 765
 766		////////////////////////////////
 767		////////////////////////////////
 768		////////////////////////////////
 769		public function q()
 770		{
 771			if(!isset($this->Q)){
 772				
 773				/*if(get_parent_class($this) != ''){
 774					echo get_class($this);
 775					$c = get_parent_class($this);
 776					$this->Q = parent::q();
 777				} */
 778
 779				$this->_comment("Init DB from: ". get_class($this));
 780
 781				require(DB_CFG);
 782				foreach($this->db as $key => $value){
 783					if($key == 'pass'){
 784						for($i=0;$i<count($this->mainDomain()); $i++){
 785							$value = base64_decode($value);
 786						}
 787					}
 788					$this->db[$key] = $value;
 789				}
 790
 791				$db 	= "x".$this->_CFG['db'];
 792
 793				if(!class_exists($db)){
 794					$this->_comment('Loading DB');
 795					$this->lib("x4deep/$db.php");
 796				}
 797
 798				$this->Q = new $db($this->db['host'],$this->db['user'],$this->db['pass'],$this->db['database'],$this->db['prefix']);					
 799			}else{
 800				$this->_comment("Recycled DB from: ". get_class($this));
 801				//$this->Q = parent::q();
 802			}
 803
 804			// Return the class that may have already been created...
 805			return $this->Q;
 806		}
 807
 808		function getXTras(){
 809			// This is where we should get the control panel icons.
 810
 811			if(!isset($this->_xtras)){
 812				// We should only run this once 
 813				if ($handle = opendir(XPHP_DIR)) {
 814					$time = microtime(true); 
 815					$this->_comment("Loading Xtra Files...");
 816
 817				    while (false !== ($file = readdir($handle))) {
 818				        if ($file != "." && $file != "..") {
 819				            $ext = explode(".",$file);
 820
 821				            if(strtolower($ext[count($ext)-1]) === 'php'){
 822				            	$class = str_replace('.php','',$file);
 823				            	
 824				            	require_once(XPHP_DIR.'/'.$file);
 825				            	//$this->_comment("Loaded Xtra File ".$file);
 826
 827				            	$rc = new ReflectionClass($class);
 828								$doc = $rc->getDocComment();
 829
 830								if($doc){
 831									$data =  trim(preg_replace('/\r?\n *\* */', ' ', $doc));
 832									 
 833									preg_match_all('/@([a-z]+)\s+(.*?)\s*(?=$|@[a-z]+\s)/s', $data, $matches);
 834									$info = array_combine($matches[1], $matches[2]);
 835
 836									$ext = explode('.',$file);
 837									$jig = array(
 838										'author'  => '',
 839										'class'   => $ext[0],
 840										'file'    => $file,
 841										'icon'    => '',
 842										'link'    => '',
 843										'mini'    => '',
 844										'name'    => '',
 845										'version' => 0
 846									);
 847
 848									$files[$file] = array_merge($jig,$info);
 849								}
 850				            }
 851				        }
 852				    }
 853				    closedir($handle);
 854					ksort($files);
 855					//$this->set('xphp_files',$files);
 856					$this->_xtras = $this->_SET['xtras'] = $files;
 857
 858					$time = round(microtime(true) - $time,5); 
 859					$this->_comment("Loaded ".count($files)." Xtra Files in ".$time);
 860				} 
 861			}else{
 862				$files = $this->_SET['xtras'] = $this->_xtras;
 863			}
 864			
 865			return $files;
 866		}
 867
 868		function syncDbTables(){
 869			// Go through all the modules.
 870			
 871			$mods = $this->getXTras();
 872			foreach($mods as $k => $v){
 873				$php = str_replace('.php','',$k);
 874				if( method_exists($php,'dbSync') ){
 875					$db = $php::dbSync();
 876					if(!empty($db)){
 877						foreach($db as $table => $columns){
 878							if(!empty($columns)){
 879								$this->syncTable($table,$columns);
 880							}
 881							
 882						}
 883					}
 884				}
 885			}
 886		}
 887
 888		// MySQL Function...
 889		function syncTable($table,$columns){
 890			$q = $this->q();
 891			// Get Current Table
 892
 893			// $chk = $q->Q("DESC $table");
 894
 895			// // RENAME THIS TABLE TO STANDARD PREFIX TEQ
 896			// if(!empty($chk) && $q->PREFIX){
 897			// 	$q->Q("RENAME TABLE $table TO $q->PREFIX$table");
 898			// }
 899
 900			//$c = $q->Q("DESC $q->PREFIX$table");
 901
 902			$sql = '';
 903
 904			$c = $q->Q("SHOW TABLES LIKE '$q->PREFIX$table'");
 905
 906			if(!empty($c)){
 907				$c = $q->Q("DESC $q->PREFIX$table");
 908			}
 909
 910			if(!empty($c) && is_array($columns)){
 911				foreach($c as $k => $v){
 912					$col = $v['Field'];
 913					// Check Columns
 914					if( isset( $columns[$col] ) ){
 915						// Column Doesn't Match
 916						if(is_array($columns[$col])){
 917							if($columns[$col]['Type'] != $v['Type'] || (isset($columns[$col]['Default']) && $v['Default'] != $columns[$col]['Default'])  ){
 918								// Add Sync to Sql
 919								$sync = "`$v[Field]` `$v[Field]` ".$columns[$col]['Type'];
 920
 921								if(isset($columns[$col]['Default'])){
 922									$sync .= ' DEFAULT "'.$columns[$col]['Default'].'"';
 923								}
 924
 925
 926								$sql = ($sql) ? $sql.", CHANGE $sync " : $sync;
 927							}
 928						}else if(is_string($columns[$col]) && isset($columns[$columns[$col]]['Type'])){
 929							$sync = "`$col` `$columns[$col]` ".$columns[$columns[$col]]['Type'];
 930							$sql = ($sql) ? $sql.", CHANGE $sync " : $sync;
 931						}
 932						unset( $columns[$col] );
 933						unset( $c[$k] );
 934					}
 935				}
 936
 937				// Change Columns
 938				if($sql){
 939					// Run SQL
 940					$q->Q("ALTER TABLE `$q->PREFIX$table` CHANGE $sql");
 941					if(isset($_GET['debug'])){
 942						//echo $q->mSql.'<hr>';
 943						//echo $q->error;
 944					}
 945					return $q->error;
 946				}
 947
 948				// New columns
 949				if(!empty($columns)){
 950					foreach($columns as $k => $v){
 951						if(is_array($v)){
 952							$sync = "`$k` ".$v['Type'];
 953							$q->Q("ALTER TABLE `$q->PREFIX$table` ADD $sync");
 954						}
 955						//echo $q->error;
 956					}
 957
 958				}
 959
 960
 961			}else{
 962
 963				if( is_array($columns) ){
 964				# CREATE TABLE
 965					foreach($columns as $k => $v){
 966						if(is_array($v)){
 967							$sync = "`$k` ".$v['Type'];
 968							$sql = ($sql) ? $sql.", $sync " : $sync;
 969						}
 970					}
 971					$q->Q("CREATE TABLE `$q->PREFIX$table`( id INT(6) NOT NULL AUTO_INCREMENT, PRIMARY KEY(id),$sql );");
 972					// echo $q->error;
 973				}else{
 974				# Rename Table...
 975					$chk = $q->Q("SHOW TABLES LIKE '$table'");
 976
 977					if(empty($chk)){
 978						$chk = $q->Q("SHOW TABLES LIKE '$q->PREFIX$table'");
 979						// RENAME THIS TABLE TO STANDARD PREFIX TEQ
 980						if(!empty($chk)){
 981							$q->Q("RENAME TABLE $q->PREFIX$table TO $q->PREFIX$columns");
 982						}
 983					}else{
 984						$q->Q("RENAME TABLE $table TO $q->PREFIX$columns");
 985					}
 986
 987				}
 988			}
 989		}
 990
 991		function mainDomain(){
 992			$domain = $_SERVER['HTTP_HOST'];
 993			$domain = explode('.',$domain);
 994			$i      = 0;
 995			while(count($domain) > 2){
 996				unset($domain[$i]);
 997				$i++;
 998			}
 999			$domain = implode('.',$domain);
1000			return $domain;
1001		}
1002
1003		
1004
1005		/*
1006	     */
1007
1008		 public function set($k,$v=false){
1009	    	//$this->dump($this->_SET);
1010	    	if(!is_array($k)){
1011	    		//var_dump($k); 
1012				return $this->_SET[$k] = $v;
1013	    		$class = get_class($this);
1014	    		$_SESSION[$class][$k] = $v;
1015	    	}else if(is_array($k)){
1016	    		return $this->_SET = array_merge($this->_SET,$k);
1017	    		 
1018	    	}
1019		} 
1020
1021		private function apply($array,$default){
1022			$new = array();
1023			foreach ($default as $key => $value) {
1024				// if array has new from default.
1025				if( isset( $array[$key] )){
1026					if( is_array($array[$key]) ){
1027						// we are dealing with an array, dig deeper.
1028						$new[$key] = $this->apply($array[$key],$default[$key]);
1029					} else {
1030						// ok - we've hit a value, lets set it in the new array.
1031						$new[$key] = $array[$key];
1032					} 
1033				}else{
1034					// the new array that got passed.
1035					$new[$key] = $value;
1036				}
1037			}
1038			return $new;
1039		}
1040
1041		private function mergeO($obj,$default){
1042			foreach ($default as $key => $value) {
1043				$obj->$key = $value;
1044			}
1045			return $obj;
1046		}
1047
1048		public function shutDownFunction() { 
1049			$error = error_get_last();
1050		  
1051		    $t = $error['type'];
1052
1053		    if($t === E_ERROR /*|| $t === E_WARNING*/){ 
1054				//ob_clean();
1055				function FriendlyErrorType($type){ 
1056				    switch($type){ 
1057				        case E_ERROR: // 1 // 
1058				            return 'E_ERROR'; 
1059				        case E_WARNING: // 2 // 
1060				            return 'E_WARNING'; 
1061				        case E_PARSE: // 4 // 
1062				            return 'E_PARSE'; 
1063				        case E_NOTICE: // 8 // 
1064				            return 'E_NOTICE'; 
1065				        case E_CORE_ERROR: // 16 // 
1066				            return 'E_CORE_ERROR'; 
1067				        case E_CORE_WARNING: // 32 // 
1068				            return 'E_CORE_WARNING'; 
1069				        case E_CORE_ERROR: // 64 // 
1070				            return 'E_COMPILE_ERROR'; 
1071				        case E_CORE_WARNING: // 128 // 
1072				            return 'E_COMPILE_WARNING'; 
1073				        case E_USER_ERROR: // 256 // 
1074				            return 'E_USER_ERROR'; 
1075				        case E_USER_WARNING: // 512 // 
1076				            return 'E_USER_WARNING'; 
1077				        case E_USER_NOTICE: // 1024 // 
1078				            return 'E_USER_NOTICE'; 
1079				        case E_STRICT: // 2048 // 
1080				            return 'E_STRICT'; 
1081				        case E_RECOVERABLE_ERROR: // 4096 // 
1082				            return 'E_RECOVERABLE_ERROR'; 
1083				        case E_DEPRECATED: // 8192 // 
1084				            return 'E_DEPRECATED'; 
1085				        case E_USER_DEPRECATED: // 16384 // 
1086				            return 'E_USER_DEPRECATED'; 
1087				    } 
1088				    return ""; 
1089				} 
1090
1091
1092				$file = realpath($_SERVER['DOCUMENT_ROOT']);
1093
1094				$file = str_replace($file , '', $error['file']);
1095
1096			    $e = array(
1097					'summary'     => FriendlyErrorType($error['type'])
1098						.' :: '.$error['message'].' :: '.$file.'#L'.$error['line'], 
1099					'description' => $error['message'].' :: '.'[source:trunk'.$file.'#L'.$error['line'].']',
1100					'attr'        => array(
1101						'type'      => 'defect',
1102						//'component' => 'x'.ucfirst($this->_SET['action']),
1103						'priority'  => 'trivial',
1104						'reporter'  => $_SESSION['user']['username'].'@'.$_SERVER['HTTP_HOST'],
1105						'keywords'  =>  $this->_SET['action'].'::'. $this->_SET['method']
1106					)
1107				);
1108
1109				$this->reportSystemError($e);		    	
1110		    }
1111
1112		}
1113
1114		private function removeLocalData($r,$Q)
1115			{
1116			$r = str_replace($Q->db['database'].'.', '', $r);
1117			$r = str_replace($Q->db['prefix'], '', $r);
1118			return $r;
1119		} 
1120
1121
1122		///////////////////////////// 
1123		//// Debug Functions
1124		//
1125		//
1126
1127		// This should be used sparingly, and in production only!
1128		public function _comment($msg,$clear=false){
1129			$time = round(microtime(true) - $this->_CFG['debug']['runtime'],5); 
1130
1131
1132
1133
1134			$echo = $this->_debugReport[] = ">'''[wiki:".get_class($this)."]''': ^[~~".$time."~~]^ $msg";
1135
1136
1137
1138			if($this->_CFG['debug']['on'])
1139				echo $echo;
1140
1141
1142
1143		}
1144
1145		public function devBug($var,$title,$dump = true,$halt = true)
1146		{
1147			# code...
1148			$this->_comment($title);
1149			$this->_dump($var,$dump,$halt);
1150		}
1151
1152		// Same with this ^^^
1153		public function dump($var,$dump=true,$halt = true)
1154		{
1155			if($this->_CFG['debug']['on']){
1156				if($dump){
1157					echo '<pre>';
1158					var_dump($var);
1159					echo '</pre>';
1160				} else {
1161					echo $var;
1162				}
1163			}
1164			if($halt)
1165				exit();
1166		}
1167
1168		/**
1169		 * rebuildSession();
1170		 * If accessing the site and users php session was lost.
1171		 * This will attempt to restore the session quitly using
1172		 * the browser cookies .
1173		 *
1174		 */
1175		function rebuildSession(){
1176			# If there are cookies, but there isnt a session...
1177			if( isset($_COOKIE['user']['secret']) && !isset($_SESSION['user']['secret']) ){
1178				//// Level 1 Security Check ////
1179				$u = $_COOKIE['user'];
1180				$secret = sha1(
1181					md5(
1182						$u['email'].base64_decode($u['hash']).$u['id'].$u['username']
1183					)
1184				);
1185
1186				# Check Cookie Secret before hitting the DB
1187				if( $secret === $u['secret'] ){
1188					# Passed Level 1 Authority - Allows access to find user in DB.
1189					$q = $this->q();
1190					$row = $q->Select('email,hash,id,username,user_secret,user_lastvisit','Users',array(
1191						'email'=>$u['email']
1192					));
1193
1194					//// Level 2 Security Check ////
1195					if($row[0]['user_secret'] === $secret){
1196						# Client is the Correct User.- ReBuild Session Data
1197						$this->setUser($row);
1198					}
1199				}
1200			}
1201		}
1202
1203		function setConfig($option,$value){
1204			$q = $this->q();
1205
1206			$cfg = $q->Select('*','config',array('config_option'=>$option));
1207			if(empty($cfg)){
1208				return $q->Insert('config',array(
1209					'config_option'	=> $option,
1210					'config_value'	=> $value
1211				));
1212			}else{
1213				return $q->Update('config',array(
1214					'config_value'	=> $value
1215				),array(
1216					'id'	=> $cfg[0]['id']
1217				));
1218			}
1219		}
1220
1221		// allows
1222		public function __call($method,$args){
1223
1224			if(isset($this->_xtra)){
1225				$class = $this->_xtra;
1226				if(method_exists($class,$method)){
1227					$class = new $class($this->_CFG);
1228					$class = $this->mergeO($class,$this);
1229					return call_user_func_array(array($class,$method), $args);
1230				}
1231			}
1232 
1233
1234			if(!isset($this->_xtras)){
1235				$this->getXtras();
1236			}
1237
1238			foreach($this->_xtras as $x){
1239		    	$class = $x['class'];	
1240				if(method_exists($class,$method)){
1241					$class = new $class($this->_CFG);
1242					$class = $this->mergeO($class,$this);
1243					return call_user_func_array(array($class,$method), $args);
1244				}
1245		    }
1246			
1247
1248	        // if(method_exists($x['class'],$method))
1249	        // return call_user_method_array($method,$x['class'],$args);
1250		    //throw new Exception("This Method {$method} doesn't exist in ".get_class($this));
1251		    $this->_comment("This Method {$method} doesn't exist in ".get_class($this));
1252		}
1253
1254		public function lang($str,$extract)
1255		{
1256			extract($extract);
1257
1258			// $this->dump($username);
1259			// exit();
1260
1261			return eval('return "'.$str.'";');
1262		}
1263
1264		public function initRPC($rpc=false)
1265		{
1266			if(!$rpc && isset($this->_RPC))
1267				$rpc = $this->_RPC;
1268			else 
1269				return false;
1270
1271			if(!class_exists('Zend_Loader')){
1272				$this->lib('Zend/Loader.php'); 
1273				
1274				$z = new Zend_Loader();
1275				$z->loadClass('Zend_XmlRpc_Client');
1276			}
1277
1278
1279			$c = new Zend_XmlRpc_Client("http://$rpc[user]:$rpc[pass]@$rpc[www]");
1280
1281			// Need to bypass the webdav auth
1282			$http = $c ->getHttpClient(); 
1283			$http->setAuth( $rpc['user'], $rpc['pass'], Zend_Http_Client::AUTH_BASIC );
1284			$c->setHttpClient($http);  
1285
1286			return $this->RPC = $c;
1287		}
1288
1289		function is_email ($email, $checkDNS = false) {
1290	        //      Check that $email is a valid address
1291	        //              (http://tools.ietf.org/html/rfc3696)
1292	        //              (http://tools.ietf.org/html/rfc2822)
1293	        //              (http://tools.ietf.org/html/rfc5322#section-3.4.1)
1294	        //              (http://tools.ietf.org/html/rfc5321#section-4.1.3)
1295	        //              (http://tools.ietf.org/html/rfc4291#section-2.2)
1296	        //              (http://tools.ietf.org/html/rfc1123#section-2.1)
1297
1298	        //      the upper limit on address lengths should normally be considered to be 256
1299	        //              (http://www.rfc-editor.org/errata_search.php?rfc=3696)
1300	        if (strlen($email) > 256)       return false;   //      Too long
1301
1302	        //      Contemporary email addresses consist of a "local part" separated from
1303	        //      a "domain part" (a fully-qualified domain name) by an at-sign ("@").
1304	        //              (http://tools.ietf.org/html/rfc3696#section-3)
1305	        $index = strrpos($email,'@');
1306
1307	        if ($index === false)           return false;   //      No at-sign
1308	        if ($index === 0)                       return false;   //      No local part
1309	        if ($index > 64)                        return false;   //      Local part too long
1310
1311	        $localPart              = substr($email, 0, $index);
1312	        $domain                 = substr($email, $index + 1);
1313	        $domainLength   = strlen($domain);
1314	       
1315	        if ($domainLength === 0)        return false;   //      No domain part
1316	        if ($domainLength > 255)        return false;   //      Domain part too long
1317
1318	        //      Let's check the local part for RFC compliance...
1319	        //
1320	        //      Any ASCII graphic (printing) character other than the
1321	        //      at-sign ("@"), backslash, double quote, comma, or square brackets may
1322	        //      appear without quoting.  If any of that list of excluded characters
1323	        //      are to appear, they must be quoted
1324	        //              (http://tools.ietf.org/html/rfc3696#section-3)
1325	        if (preg_match('/^"(?:.)*"$/', $localPart) > 0) {
1326	                //      Quoted-string tests:
1327	                //
1328	                //      Note that since quoted-pair
1329	                //      is allowed in a quoted-string, the quote and backslash characters may
1330	                //      appear in a quoted-string so long as they appear as a quoted-pair.
1331	                //              (http://tools.ietf.org/html/rfc2822#section-3.2.5)
1332	                $groupCount     = preg_match_all('/(?:^"|"$|\\\\\\\\|\\\\")|(\\\\|")/', $localPart, $matches);
1333	                array_multisort($matches[1], SORT_DESC);
1334	                if ($matches[1][0] !== '')                                                                              return false;   //      Unescaped quote or backslash character inside quoted string
1335	                if (preg_match('/^"\\\\*"$/', $localPart) > 0)                                  return false;   //      "" and "\" are slipping through - must tidy this up
1336	        } else {
1337	                //      Unquoted string tests:
1338	                //
1339	                //      Period (".") may...appear, but may not be used to start or end the
1340	                //      local part, nor may two or more consecutive periods appear.
1341	                //              (http://tools.ietf.org/html/rfc3696#section-3)
1342	                if (preg_match('/^\\.|\\.\\.|\\.$/', $localPart) > 0)                   return false;   //      Dots in wrong place
1343
1344	                //      Any excluded characters? i.e. <space>, @, [, ], \, ", <comma>
1345	                if (preg_match('/[ @\\[\\]\\\\",]/', $localPart) > 0)
1346	                        //      Check all excluded characters are escaped
1347	                        $stripped = preg_replace('/\\\\[ @\\[\\]\\\\",]/', '', $localPart);
1348	                        if (preg_match('/[ @\\[\\]\\\\",]/', $stripped) > 0)            return false;   //      Unquoted excluded characters
1349	        }
1350
1351	        //      Now let's check the domain part...
1352
1353	        //      The domain name can also be replaced by an IP address in square brackets
1354	        //              (http://tools.ietf.org/html/rfc3696#section-3)
1355	        //              (http://tools.ietf.org/html/rfc5321#section-4.1.3)
1356	        //              (http://tools.ietf.org/html/rfc4291#section-2.2)
1357	        if (preg_match('/^\\[(.)+]$/', $domain) === 1) {
1358	                //      It's an address-literal
1359	                $addressLiteral = substr($domain, 1, $domainLength - 2);
1360	                $matchesIP              = array();
1361	               
1362	                //      Extract IPv4 part from the end of the address-literal (if there is one)
1363	                if (preg_match('/\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/', $addressLiteral, $matchesIP) > 0) {
1364	                        $index = strrpos($addressLiteral, $matchesIP[0]);
1365	                       
1366	                        if ($index === 0) {
1367	                                //      Nothing there except a valid IPv4 address, so...
1368	                                return true;
1369	                        } else {
1370	                                //      Assume it's an attempt at a mixed address (IPv6 + IPv4)
1371	                                if ($addressLiteral[$index - 1] !== ':')                        return false;   //      Character preceding IPv4 address must be ':'
1372	                                if (substr($addressLiteral, 0, 5) !== 'IPv6:')          return false;   //      RFC5321 section 4.1.3
1373
1374	                                $IPv6 = substr($addressLiteral, 5, ($index ===7) ? 2 : $index - 6);
1375	                                $groupMax = 6;
1376	                        }
1377	                } else {
1378	                        //      It must be an attempt at pure IPv6
1379	                        if (substr($addressLiteral, 0, 5) !== 'IPv6:')                  return false;   //      RFC5321 section 4.1.3
1380	                        $IPv6 = substr($addressLiteral, 5);
1381	                        $groupMax = 8;
1382	                }
1383
1384	                $groupCount     = preg_match_all('/^[0-9a-fA-F]{0,4}|\\:[0-9a-fA-F]{0,4}|(.)/', $IPv6, $matchesIP);
1385	                $index          = strpos($IPv6,'::');
1386
1387	                if ($index === false) {
1388	                        //      We need exactly the right number of groups
1389	                        if ($groupCount !== $groupMax)                                                  return false;   //      RFC5321 section 4.1.3
1390	                } else {
1391	                        if ($index !== strrpos($IPv6,'::'))                                             return false;   //      More than one '::'
1392	                        $groupMax = ($index === 0 || $index === (strlen($IPv6) - 2)) ? $groupMax : $groupMax - 1;
1393	                        if ($groupCount > $groupMax)                                                    return false;   //      Too many IPv6 groups in address
1394	                }
1395
1396	                //      Check for unmatched characters
1397	                array_multisort($matchesIP
1398	[1], SORT_DESC);
1399	                if ($matchesIP[1][0] !== '')                                                            return false;   //      Illegal characters in address
1400
1401	                //      It's a valid IPv6 address, so...
1402	                return true;
1403	        } else {
1404	                //      It's a domain name...
1405
1406	                //      The syntax of a legal Internet host name was specified in RFC-952
1407	                //      One aspect of host name syntax is hereby changed: the
1408	                //      restriction on the first character is relaxed to allow either a
1409	                //      letter or a digit.
1410	                //              (http://tools.ietf.org/html/rfc1123#section-2.1)
1411	                //
1412	                //      NB RFC 1123 updates RFC 1035, but this is not currently apparent from reading RFC 1035.
1413	                //
1414	                //      Most common applications, including email and the Web, will generally not permit...escaped strings
1415	                //              (http://tools.ietf.org/html/rfc3696#section-2)
1416	                //
1417	                //      Characters outside the set of alphabetic characters, digits, and hyphen MUST NOT appear in domain name
1418	                //      labels for SMTP clients or servers
1419	                //              (http://tools.ietf.org/html/rfc5321#section-4.1.2)
1420	                //
1421	                //      RFC5321 precludes the use of a trailing dot in a domain name for SMTP purposes
1422	                //              (http://tools.ietf.org/html/rfc5321#section-4.1.2)
1423	                $matches        = array();
1424	                $groupCount     = preg_match_all('/(?:[0-9a-zA-Z][0-9a-zA-Z-]{0,61}[0-9a-zA-Z]|[a-zA-Z])(?:\\.|$)|(.)/', $domain, $matches);
1425	                $level          = count($matches[0]);
1426
1427	                if ($level == 1)                                                                                        return false;   //      Mail host can't be a TLD
1428
1429	                $TLD = $matches[0][$level - 1];
1430	                if (substr($TLD, strlen($TLD) - 1, 1) === '.')                          return false;   //      TLD can't end in a dot
1431	                if (preg_match('/^[0-9]+$/', $TLD) > 0)                                         return false;   //      TLD can't be all-numeric
1432
1433	                //      Check for unmatched characters
1434	                array_multisort($matches[1], SORT_DESC);
1435	                if ($matches[1][0] !== '')                                                                      return false;   //      Illegal characters in domain, or label longer than 63 characters
1436
1437	                //      Check DNS?
1438	                if ($checkDNS && function_exists('checkdnsrr')) {
1439	                        if (!(checkdnsrr($domain, 'A') || checkdnsrr($domain, 'MX'))) {
1440	                                                                                                                                        return false;   //      Domain doesn't actually exist
1441	                        }
1442	                }
1443
1444	                //      Eliminate all other factors, and the one which remains must be the truth.
1445	                //              (Sherlock Holmes, The Sign of Four)
1446	                return true;
1447	        }
1448		}		
1449
1450
1451	}
1452?>