PageRenderTime 77ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/x/lib/x4deep/xengine.php

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