Exemple #1
0
 /**
  * 取得缓存类实例
  * @static
  * @access public
  * @return mixed
  */
 static function getInstance($type = '', $options = array())
 {
     static $_instance = array();
     $guid = $type . to_guid_string($options);
     if (!isset($_instance[$guid])) {
         $obj = new Cache();
         $_instance[$guid] = $obj->connect($type, $options);
     }
     return $_instance[$guid];
 }
Exemple #2
0
 function __construct(array $params = array())
 {
     parent::__construct($params);
     if (array_key_exists('DelegateTarget', $params)) {
         $this->_pathDelegate = new \Core\Delegate($params['DelegateTarget'], $params['DelegateMethod']);
     }
 }
Exemple #3
0
 private function get_jsapi_ticket($key = 'ticket', $default = null)
 {
     \Core\Cache::init_config_params();
     $this->ticket = \Core\Cache::get('jsapi_ticket');
     if (empty($this->ticket)) {
         $host = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=%s";
         $url = sprintf($host, $this->get_accesstoken());
         $info = \Core\Curl::get($url);
         $respone = json_decode($info->response, true);
         if (isset($respone['ticket'])) {
             $this->ticket = $respone;
         }
         \Core\Cache::set('jsapi_ticket', $respone);
     }
     if (!isset($this->ticket[$key])) {
         $this->ticket[$key] = $default;
     }
     return $this->ticket[$key];
 }
Exemple #4
0
 /**
  * 获取token
  */
 public function get_accesstoken($key = 'access_token', $default = null)
 {
     \Core\Cache::init_config_params();
     $this->accesstoken = \Core\Cache::get('access_token');
     if (empty($this->accesstoken)) {
         $host = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
         $url = sprintf($host, $this->appid, $this->appsecret);
         $info = \Core\Curl::get($url);
         $respone = json_decode($info->response, true);
         if (isset($respone['access_token'])) {
             $this->accesstoken = $respone;
         }
         \Core\Cache::set('access_token', $respone);
     }
     if (!isset($this->accesstoken[$key])) {
         $this->accesstoken[$key] = $default;
     }
     return $this->accesstoken[$key];
 }
Exemple #5
0
	private function _registerFeature($feature, $url, $component){
		if(!defined('SERVER_ID')){
			throw new \Exception('Unable to load the licenser without a valid server id set!');
		}
		
		// Lookup any matching feature and do not allow two components to register the same feature code!
		if(isset($this->_features[$feature]) && $this->_features[$feature]['component'] != $component){
			throw new \Exception('Feature ' . $feature . ' already defined in another component! (' . $this->_features[$feature]['component'] . ' vs ' . $component . ')');
		}
		
		// Lookup the cache for this licensed key value.
		$cached = \Core\Cache::Get(md5('LICENSER:' . SERVER_ID . $feature));

		$this->_features[$feature] = [
			'feature' => $feature,
			'url' => $url,
			'component' => $component,
			'value' => $cached,
		];
	}
Exemple #6
0
 /**
  * Lookup query
  *
  * @param string $query  IP or hostname to lookup
  * @param bool   $is_utf Require UTF-8
  *
  * @return WhoisResult
  */
 public static function Lookup($query = '', $is_utf = true)
 {
     // See if this query has been cached by Core <3
     $cachekey = \Core\str_to_url('whois-' . $query);
     $cached = \Core\Cache::Get($cachekey);
     if ($cached) {
         $result = $cached;
     } else {
         $whois = new phpwhois\Whois();
         $result = $whois->lookup($query, $is_utf);
         // Cache the results for 6 hours
         \Core\Cache::Set($cachekey, $result, 3600 * 6);
     }
     if (!is_array($result)) {
         return new WhoisNotFoundResult($query);
     }
     if (!sizeof($result)) {
         return new WhoisNotFoundResult($query);
     }
     return new WhoisResult($result, $query);
 }
Exemple #7
0
 /**
  * 请求token
  */
 public function get_accesstoken($key = 'access_token', $default = null)
 {
     \Core\Cache::init_config_params();
     $this->enterprise_accesstoken = \Core\Cache::get('enterprise_accesstoken');
     if (empty($this->enterprise_accesstoken)) {
         $host = 'https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=%s&corpsecret=%s';
         $url = sprintf($host, $this->corpid, $this->corpsecret);
         $info = \Core\Curl::get($url);
         $respone = json_decode($info->response, true);
         if (isset($respone['access_token'])) {
             $this->enterprise_accesstoken = $respone;
         }
         \Core\Cache::set('enterprise_accesstoken', $respone);
     }
     if (!isset($this->accesstoken[$key])) {
         $this->accesstoken[$key] = $default;
     }
     return $this->accesstoken[$key];
 }
Exemple #8
0
 /**
  * Copy in all the assets for this theme into the assets location.
  *
  * Returns false if nothing changed, else will return an array of all the changes that occured.
  *
  * @param bool $install   Set to false to uninstall the assets instead of installing.
  * @param int  $verbosity 0 for standard output, 1 for real-time, 2 for real-time verbose output.
  *
  * @return false | array
  * @throws \InstallerException
  */
 public function _parseAssets($install = true, $verbosity = 0)
 {
     $assetbase = \Core\Filestore\get_asset_path();
     $coretheme = \ConfigHandler::Get('/theme/selected');
     // WHY is core theme set to blank?!?
     // Damn installer...
     // this happens in the installer.
     if ($coretheme === null) {
         $coretheme = 'default';
     }
     $theme = $this->getKeyName();
     $changes = [];
     foreach ($this->_xmlloader->getElements('/assets/file') as $node) {
         // Cannot install assets if the directory is not setup!
         if (!$this->getAssetDir()) {
             continue;
         }
         $b = $this->getBaseDir();
         // The base filename with the directory.
         $filename = $node->getAttribute('filename');
         // The new theme asset will be installed into the same directory as its theme.
         // This differs from usual components because they just follow whatever theme is currently running.
         //$nf = Core::File($assetbase . $theme . '/' . $filename);
         $trimmedfilename = substr($b . $node->getAttribute('filename'), strlen($this->getAssetDir()));
         $themespecificfilename = $assetbase . $theme . '/' . $trimmedfilename;
         $newfilename = 'assets/' . $trimmedfilename;
         // Before anything, check and see if this file has a custom override file present.
         if (file_exists(ROOT_PDIR . 'themes/custom/' . $newfilename)) {
             // If so, then copy that asset to the custom directory too!
             $f = \Core\Filestore\Factory::File(ROOT_PDIR . 'themes/custom/' . $newfilename);
             $srcname = '!CUSTOM!';
         } else {
             // Otherwise, the local file is guaranteed to be a local file.
             $f = new \Core\Filestore\Backends\FileLocal($b . $filename);
             $srcname = '-theme- ';
         }
         if ($verbosity == 2) {
             CLI::PrintActionStart('Installing ' . $srcname . ' asset ' . $f->getBasename());
         }
         $nf = \Core\Filestore\Factory::File($newfilename);
         /*
         			// The various replacement possibilities for this file.
         			// The new destination must be in the theme-specific directory, this is a
         			// bit of a hack from the usual behaviour of the filestore system.
         			// Since that's designed to return the default if the theme-specific doesn't exist.
         			$replacements = array(
         				// The theme is not default, but the system translated the path to the default directory.
         				// This is because the file doesn't exist in any theme.
         				// This is actually expected behaviour, except unwanted here.
         				'default/' . $trimmedfilename => $theme . '/' . $trimmedfilename,
         				// The theme is not the currently installed, but the system translated the path to the that directory.
         				// This is because the filename is the same as the installed theme, so the system just translated there.
         				// We don't want that.
         				$coretheme . '/' . $trimmedfilename => $theme . '/' . $trimmedfilename,
         			);
         
         
         			foreach($replacements as $k => $v){
         				if($k == $v) continue;
         				if(strpos($nf->getFilename(), $k) !== false){
         					$nf->setFilename( str_replace($k, $v, $nf->getFilename()) );
         				}
         			}
         */
         // Check if this file even needs updated. (this is primarily used for reporting reasons)
         if ($nf->exists() && $nf->identicalTo($f)) {
             //echo "Skipping file, it's identical.<br/>";
             if ($verbosity == 2) {
                 CLI::PrintActionStatus('skip');
             }
             continue;
         } elseif ($nf->exists()) {
             $action = 'Replaced';
         } else {
             $action = 'Installed';
         }
         if (!$f->isReadable()) {
             throw new \InstallerException('Source file [' . $f->getFilename() . '] is not readable.');
         }
         try {
             $f->copyTo($nf, true);
         } catch (\Exception $e) {
             throw new \InstallerException('Unable to copy [' . $f->getFilename() . '] to [' . $nf->getFilename() . ']');
         }
         $change = $action . ' ' . $nf->getFilename();
         $changes[] = $change;
         if ($verbosity == 1) {
             CLI::PrintLine($change);
         } elseif ($verbosity == 2) {
             CLI::PrintActionStatus('ok');
         }
     }
     // If there are custom assets not registered by any application, install them too!
     // This will allow an admin to upload additional css resources and images easily.
     $directory = \Core\Filestore\Factory::Directory('themes/custom/assets');
     $ls = $directory->ls(null, true);
     $baseStrLen = strlen(ROOT_PDIR . '/themes/custom/assets');
     foreach ($ls as $fileOrDir) {
         if ($fileOrDir instanceof File) {
             $newfilename = substr($fileOrDir->getFilename(), $baseStrLen);
             if ($verbosity == 2) {
                 CLI::PrintActionStart('Installing CUSTOM   asset ' . $newfilename);
             }
             $nf = \Core\Filestore\Factory::File('asset/' . $newfilename);
             if ($nf->exists() && $nf->identicalTo($fileOrDir)) {
                 //echo "Skipping file, it's identical.<br/>";
                 if ($verbosity == 2) {
                     CLI::PrintActionStatus('skip');
                 }
                 continue;
             } elseif ($nf->exists()) {
                 $action = 'Replaced';
             } else {
                 $action = 'Installed';
             }
             try {
                 $fileOrDir->copyTo($nf, true);
             } catch (\Exception $e) {
                 throw new \InstallerException('Unable to copy [' . $fileOrDir->getFilename() . '] to [' . $nf->getFilename() . ']');
             }
             $change = $action . ' ' . $nf->getFilename();
             $changes[] = $change;
             if ($verbosity == 1) {
                 CLI::PrintLine($change);
             } elseif ($verbosity == 2) {
                 CLI::PrintActionStatus('ok');
             }
         }
     }
     if (!sizeof($changes)) {
         if ($verbosity > 0) {
             CLI::PrintLine('No changes required');
         }
         return false;
     }
     // Make sure the asset cache is purged!
     \Core\Cache::Delete('asset-resolveurl');
     return $changes;
 }
Exemple #9
0
	/**
	 * Get the temporary local version of the file.
	 * This is useful for doing operations such as hash and identicalto.
	 *
	 * @return FileLocal
	 */
	protected function _getTmpLocal() {
		if ($this->_tmplocal === null) {
			$f = md5($this->getFilename());

			// Gotta love obviously-named flags.
			$needtodownload = true;

			$this->_tmplocal = Filestore\Factory::File('tmp/remotefile-cache/' . $f);

			// File exists already!  Check and see if it needs to be redownloaded.
			if ($this->cacheable && $this->_tmplocal->exists()) {
				// Lookup this file in the system cache.
				$systemcachedata = Cache::Get('remotefile-cache-header-' . $f);
				if ($systemcachedata && isset($systemcachedata['headers'])) {
					// I can only look them up if the cache is available.

					// First check will be the expires header.
					if(isset($systemcachedata['headers']['Expires']) && strtotime($systemcachedata['headers']['Expires']) > time()){
						$needtodownload = false;
						// And set the headers!
						// This is required
						$this->_headers = $systemcachedata['headers'];
						$this->_response = $systemcachedata['response'];
					}
					// Next, try ETag.
					elseif ($this->_getHeader('ETag') && isset($systemcachedata['headers']['ETag'])) {
						$needtodownload = ($this->_getHeader('ETag') != $systemcachedata['headers']['ETag']);
					}
					// No?  How 'bout 
					elseif ($this->_getHeader('Last-Modified') && isset($systemcachedata['headers']['Last-Modified'])) {
						$needtodownload = ($this->_getHeader('Last-Modified') != $systemcachedata['headers']['Last-Modified']);
					}
					// Still no?  The default is to download it anyway.
				}
			}

			if ($needtodownload || !$this->cacheable) {
				// Make sure that the headers are updated, this is a requirement to use the 302 tag.
				$this->_getHeaders();
				if(($this->_response == '302' || $this->_response == '301') && $this->_redirectFile !== null){
					$this->_tmplocal = $this->_redirectFile->_getTmpLocal();
				}
				else{
					// BTW, use cURL.
					$curl = curl_init();
					curl_setopt_array(
						$curl, array(
							CURLOPT_HEADER         => false,
							CURLOPT_NOBODY         => false,
							CURLOPT_RETURNTRANSFER => true,
							CURLOPT_URL            => $this->getURL(),
							CURLOPT_HTTPHEADER     => \Core::GetStandardHTTPHeaders(true),
						)
					);

					$result = curl_exec($curl);
					if($result === false){
						switch(curl_errno($curl)){
							case CURLE_COULDNT_CONNECT:
							case CURLE_COULDNT_RESOLVE_HOST:
							case CURLE_COULDNT_RESOLVE_PROXY:
								$this->_response = 404;
								return $this->_tmplocal;
								break;
							default:
								$this->_response = 500;
								return $this->_tmplocal;
								break;
						}
					}

					curl_close($curl);

					// Copy the data down to the local file.
					$this->_tmplocal->putContents($result);
				}

				// And remember this header data for nexttime.
				Cache::Set(
					'remotefile-cache-header-' . $f,
					[
						'headers'  => $this->_getHeaders(),
						'response' => $this->_response,
					]
				);
			}
		}

		return $this->_tmplocal;
	}
	public static function _UploadHandler(Form $form) {
		$localfile = \Core\Filestore\Factory::File($form->getElement('upload')->get('value'));
		$localobj = $localfile->getContentsObject();
		if(!$localobj instanceof Core\Filestore\Contents\ContentTGZ){
			$localfile->delete();
			\Core\set_message('Invalid file uploaded', 'error');
			return false;
		}
		
		$tmpdir = $localobj->extract('tmp/installer-' . Core::RandomHex(4));
		
		// There should now be a package.xml metafile inside that temporary directory.
		// Parse it to get the necessary information for this package.
		$metafile = \Core\Filestore\Factory::File($tmpdir->getPath() . 'package.xml');
		if(!$metafile->exists()){
			$localfile->delete();
			$tmpdir->delete();
			\Core\set_message('Invalid package, package does not contain a "package.xml" file.');
			return false;
		}
		
		$pkg     = new PackageXML($metafile->getFilename());
		$key     = str_replace(' ', '-', strtolower($pkg->getName()));
		$name    = $pkg->getName();
		$type    = $pkg->getType();
		$version = $pkg->getVersion();
		
		// Validate the contents of the package.
		if(!(
			$type == 'component' ||
			$type == 'theme' ||
			$type == 'core'
		)){
			$localfile->delete();
			$tmpdir->delete();
			\Core\set_message('Invalid package, package does not appear to be a valid Core package.');
			return false;
		}

		// Now that the data is extracted in a temporary directory, extract every file in the destination.
		/** @var $datadir \Core\Filestore\Directory */
		$datadir = $tmpdir->get('data/');
		if(!$datadir){
			\Core\set_message('Invalid package, package does not contain a "data" directory.');
			return false;
		}
		
		if($type == 'component'){
			$destdir = ROOT_PDIR . 'components/' . $key . '/';
		}
		elseif($type == 'theme'){
			$destdir = ROOT_PDIR . 'themes/' . $key . '/';
		}
		else{
			$destdir = ROOT_PDIR . '/';
		}

		try{
			// Will give me an array of Files in the data directory.
			$files = $datadir->ls(null, true);
			// Used to get the relative path for each contained file.
			$datalen = strlen($datadir->getPath());
			foreach($files as $file){
				if(!$file instanceof \Core\Filestore\Backends\FileLocal) continue;

				// It's a file, copy it over.
				// To do so, resolve the directory path inside the temp data dir.
				$dest = \Core\Filestore\Factory::File($destdir . substr($file->getFilename(), $datalen));
				/** @var $dest \Core\Filestore\Backends\FileLocal */
				$dest->copyFrom($file, true);
			}
		}
		catch(Exception $e){
			// OH NOES!
			$localfile->delete();
			$tmpdir->delete();
			\Core\set_message($e->getMessage(), 'error');
			return false;
		}
		
		
		// Cleanup everything
		$localfile->delete();
		$tmpdir->delete();

		// Clear the cache so the next pageload will pick up on the new components and goodies.
		\Core\Cache::Flush();
		\Core\Templates\Backends\Smarty::FlushCache();
		
		// Print a nice message to the user that it completed.
		\Core\set_message('Successfully installed ' . $name . ' ' . $version, 'success');
		return '/updater';
	}
Exemple #11
0
	/**
	 * Get an array of locales currently available on the base system.
	 *
	 * @return array
	 */
	public static function GetLocalesAvailable(){
		$cacheKey = 'core-i18n-locales';
		$cacheTime = DEVELOPMENT_MODE ? 3600 : 604800;
		$cached = Cache::Get($cacheKey, $cacheTime);
		if($cached){
			return $cached;
		}

		exec('locale -a', $output);
		$locales = [];
		foreach($output as $line){
			if($line == 'C' || $line == 'POSIX' || $line == 'C.UTF-8'){
				// Yeah, skip these!
				continue;
			}
			if(($dotpos = strpos($line, '.')) !== false){
				// Trim anything after the ".", this is the charset which we, (in theory), don't need.
				// ex: .UTF-8 or .UTF-16.
				$line = substr($line, 0, $dotpos);
			}
			
			if(isset(self::$Languages[$line])){
				$locales[$line] = self::$Languages[$line];
			}
		}

		// Cache this so I don't have to execute the command and lookup the values all over again!
		Cache::Set($cacheKey, $locales, $cacheTime);
		return $locales;
	}
Exemple #12
0
 /**
  * 异步任务
  *
  * @param $serv
  * @param $task_id
  * @param $from_id
  * @param $data
  */
 public function task($serv, $task_id, $from_id, $data)
 {
     static $db = null;
     static $cache = null;
     if (!$db) {
         $db = new DB();
     }
     if (!$cache) {
         $cache = new Cache();
     }
     $d = json_decode($data, true);
     $type = $d['type'];
     unset($d['type']);
     //获取在线用户列表
     $onlines = $db->fetch_all('select * from %t where 1', array('online'));
     $notme = false;
     $message = "";
     switch ($type) {
         //处理消息
         case 'message':
             #1 将用户消息入库
             $db->insert("message", $d);
             $notme = true;
             $message = $d['msg'];
             $type = self::TYPE_NORMAL;
             break;
             //推送在线会员列表
         //推送在线会员列表
         case 'pushOnline':
             $message = $db->fetch_all("select * from %t where 1", array('online'));
             $type = self::TYPE_PUSH_ONLINEMEMBERS;
             //给单独用户推送在线会员列表
             if ($d['sendto']) {
                 $msg = $this->createRecMsg($message, $type);
                 $serv->send((int) $d['sendto'], $this->frame($msg), $from_id);
             }
             break;
         case 'login':
             if ($db->fetch_first("select * from %t where openid=%s", array('online', $d['openid']))) {
                 $db->update('online', array('fd' => $d['fd']), " openid='" . $d['openid'] . "'");
                 $cache->set($d['fd'], $d['openid']);
             } else {
                 $serv->close($d['fd']);
             }
             break;
         case 'logout':
             $cache->delete($d['fd']);
             break;
     }
     //检查登陆授权
     var_dump($cache->get($d['fd']));
     //		if(!$cache->get($d['fd'])) { $serv->close($d['fd']); }
     //将消息发给在线用户
     if ($onlines) {
         echo date("H:i:s") . " : 当前有 " . count($onlines) . " 人在线,开始发送消息 == " . json_encode($message) . " \n";
         foreach ($onlines as $key => $val) {
             if ($notme && $val['fd'] == $d['fd']) {
                 continue;
             }
             $msg = $this->createRecMsg($message, $type, $val['fd']);
             //开始发送消息
             $serv->send((int) $val['fd'], $this->frame($msg), $from_id);
         }
     } else {
         echo "没有在线用户";
     }
 }
	public static function PerformInstall($type, $name, $version, $dryrun = false, $verbose = false){

		if($verbose){
			// These are needed to force the output to be sent immediately.
			while ( @ob_end_flush() ); // even if there is no nested output buffer
			if(function_exists('apache_setenv')){
				// This function doesn't exist in CGI mode :/
				apache_setenv('no-gzip', '1');
			}
			ini_set('output_buffering','on');
			ini_set('zlib.output_compression', 0);
			ob_implicit_flush();

			// Give some basic styles for this output.
			echo '<html>
	<head>
	<!-- Yes, the following is 1024 spaces.  This is because some browsers have a 1Kb buffer before they start rendering text -->
	' . str_repeat(" ", 1024) . '
		<style>
			body {
				background: none repeat scroll 0 0 black;
				color: #22EE33;
				font-family: monospace;
			}
		</style>
	</head>
	<body>';
		}

		$timer = microtime(true);
		// Give this script a few more seconds to run.
		set_time_limit(max(90, ini_get('max_execution_time')));

		// This will get a list of all available updates and their sources :)
		if($verbose) self::_PrintHeader('Retrieving Updates');
		$updates = UpdaterHelper::GetUpdates();
		if($verbose){
			self::_PrintInfo('Found ' . $updates['sitecount'] . ' repository site(s)!', $timer);
			self::_PrintInfo('Found ' . $updates['pkgcount'] . ' packages!', $timer);
		}

		// A list of changes that are to be applied, (mainly for the dry run).
		$changes = array();

		// Target in on the specific object we're installing.  Useful for a shortcut.
		switch($type){
			case 'core':
				$initialtarget = &$updates['core'];
				break;
			case 'components':
				$initialtarget = &$updates['components'][$name];
				break;
			case 'themes':
				$initialtarget = &$updates['themes'][$name];
				break;
			default:
				return [
					'status' => 0,
					'message' => '[' . $type . '] is not a valid installation type!',
				];
		}

		// This is a special case for testing the installer UI.
		$test = ($type == 'core' && $version == '99.1337~(test)');

		if($test && $verbose){
			self::_PrintHeader('Performing a test installation!');
		}

		if($test){
			if($verbose){
				self::_PrintInfo('Sleeping for a few seconds... because servers are always slow when you don\'t want them to be!', $timer);
			}
			sleep(4);

			// Also overwrite some of the target's information.
			$repo = UpdateSiteModel::Find(null, 1);
			$initialtarget['source'] = 'repo-' . $repo->get('id');
			$initialtarget['location'] = 'http://corepl.us/api/2_4/tests/updater-test.tgz.asc';
			$initialtarget['destdir'] = ROOT_PDIR;
			$initialtarget['key'] = 'B2BEDCCB';
			$initialtarget['status'] = 'update';

			//if($verbose){
			//	echo '[DEBUG]' . $nl;
			//	var_dump($initialtarget);
			//}
		}

		// Make sure the name and version exist in the updates list.
		// In theory, the latest version of core is the only one displayed.
		if(!$test && $initialtarget['version'] != $version){
			return [
				'status' => 0,
				'message' => $initialtarget['typetitle'] . ' does not have the requested version available.',
				'debug' => [
					'versionrequested' => $version,
					'versionfound' => $initialtarget['version'],
				],
			];
		}

		// A queue of components to check.
		$pendingqueue = array($initialtarget);
		// A queue of components that will be installed that have satisfied dependencies.
		$checkedqueue = array();

		// This will assemble the list of required installs in the correct order.
		// If a given dependency can't be met, the installation will be aborted.
		if($verbose){
			self::_PrintHeader('CHECKING DEPENDENCIES');
		}
		do{
			$lastsizeofqueue = sizeof($pendingqueue);

			foreach($pendingqueue as $k => $c){
				$good = true;

				if(isset($c['requires'])){
					if($verbose){
						self::_PrintInfo('Checking dependencies for ' . $c['typetitle'], $timer);
					}

					foreach($c['requires'] as $r){

						// Sometimes there will be blank requirements in the metafile.
						if(!$r['name']) continue;

						$result = UpdaterHelper::CheckRequirement($r, $checkedqueue, $updates);

						if($result === false){
							// Dependency not met
							return [
								'status' => 0,
								'message' => $c['typetitle'] . ' requires ' . $r['name'] . ' ' . $r['version']
							];
						}
						elseif($result === true){
							// Dependency met via either installed components or new components
							// yay
							if($verbose){
								self::_PrintInfo('Dependency [' . $r['name'] . ' ' . $r['version'] . '] met with already-installed packages.', $timer);
							}
						}
						else{
							if($verbose){
								self::_PrintInfo('Additional package [' . $result['typetitle'] . '] required to meet dependency [' . $r['name'] . ' ' . $r['version'] . '], adding to queue and retrying!', $timer);
							}
							// It's an array of requirements that are needed to satisfy this installation.
							$pendingqueue = array_merge(array($result), $pendingqueue);
							$good = false;
						}
					}
				}
				else{
					if($verbose){
						self::_PrintInfo('Skipping dependency check for ' . $c['typetitle'] . ', no requirements present', $timer);
					}

					// The require key isn't present... OK!
					// This happens with themes, as they do not have any dependency logic.
				}

				if($good === true){
					$checkedqueue[] = $c;
					$changes[] = (($c['status'] == 'update') ? 'Update' : 'Install') .
						' ' . $c['typetitle'] . ' ' . $c['version'];
					unset($pendingqueue[$k]);
				}
			}
		}
		while(sizeof($pendingqueue) && sizeof($pendingqueue) != $lastsizeofqueue);

		// Do validation checks on all these changes.  I need to make sure I have the GPG key for each one.
		// This is done here to save having to download the files from the remote server first.
		foreach($checkedqueue as $target){
			// It'll be validated prior to installation anyway.
			if(!$target['key']) continue;

			$output = array();
			exec('gpg --homedir "' . GPG_HOMEDIR . '" --list-public-keys "' . $target['key'] . '"', $output, $result);
			if($result > 0){
				// Key validation failed!
				if($verbose){
					echo implode("<br/>\n", $output);
				}
				return [
					'status' => 0,
					'message' => $c['typetitle'] . ' failed GPG verification! Is the key ' . $target['key'] . ' installed?'
				];
			}
		}


		// Check that the queued packages have not been locally modified if installed.
		if($verbose){
			self::_PrintHeader('Checking for local modifications');
		}
		foreach($checkedqueue as $target){
			if($target['status'] == 'update'){
				switch($target['type']){
					case 'core':
						$c = Core::GetComponent('core');
						break;
					case 'components':
						$c = Core::GetComponent($target['name']);
						break;
					case 'themes':
						$c = null;
						break;
				}

				if($c){
					// Are there changes?
					if(sizeof($c->getChangedAssets())){
						foreach($c->getChangedAssets() as $change){
							$changes[] = 'Overwrite locally-modified asset ' . $change;
						}
					}
					if(sizeof($c->getChangedFiles())){
						foreach($c->getChangedFiles() as $change){
							$changes[] = 'Overwrite locally-modified file ' . $change;
						}
					}
					if(sizeof($c->getChangedTemplates())){
						foreach($c->getChangedTemplates() as $change){
							$changes[] = 'Overwrite locally-modified template ' . $change;
						}
					}
				}
			}
		}


		// If dry run is enabled, stop here.
		// After this stage, dragons be let loose from thar cages.
		if($dryrun){
			return [
				'status' => 1,
				'message' => 'All dependencies are met, ok to install',
				'changes' => $changes,
			];
		}


		// Reset changes, in this case it'll be what was installed.
		$changes = array();

		// By now, $checkedqueue will contain all the pending changes, theoretically with
		// the initially requested package at the end of the list.
		foreach($checkedqueue as $target){

			if($verbose){
				self::_PrintHeader('PERFORMING INSTALL (' . strtoupper($target['typetitle']) . ')');
			}

			// This package is already installed and up to date.
			if($target['source'] == 'installed'){
				return [
					'status' => 0,
					'message' => $target['typetitle'] . ' is already installed and at the newest version.',
				];
			}
			// If this package is coming from a repo, install it from that repo.
			elseif(strpos($target['source'], 'repo-') !== false){
				/** @var $repo UpdateSiteModel */
				$repo = new UpdateSiteModel(substr($target['source'], 5));
				if($verbose){
					self::_PrintInfo('Using repository ' . $repo->get('url') . ' for installation source', $timer);
				}

				// Setup the remote file that will be used to download from.
				$file = new \Core\Filestore\Backends\FileRemote($target['location']);
				$file->username = $repo->get('username');
				$file->password = $repo->get('password');

				// The initial HEAD request pulls the metadata for the file, and sees if it exists.
				if($verbose){
					self::_PrintInfo('Performing HEAD lookup on ' . $file->getFilename(), $timer);
				}
				if(!$file->exists()){
					return [
						'status' => 0,
						'message' => $target['location'] . ' does not seem to exist!'
					];
				}
				if($verbose){
					self::_PrintInfo('Found a(n) ' . $file->getMimetype() . ' file that returned a ' . $file->getStatus() . ' status.', $timer);
				}

				// Get file contents will download the file.
				if($verbose){
					self::_PrintInfo('Downloading ' . $file->getFilename(), $timer);
				}
				$downloadtimer = microtime(true);
				$obj = $file->getContentsObject();
				// Getting the object simply sets it up, it doesn't download the contents yet.
				$obj->getContents();
				// Now it has :p
				// How long did it take?
				if($verbose){
					self::_PrintInfo('Downloaded ' . $file->getFilesize(true) . ' in ' . (round(microtime(true) - $downloadtimer, 2) . ' seconds'), $timer);
				}

				if(!($obj instanceof \Core\Filestore\Contents\ContentASC)){
					return [
						'status' => 0,
						'message' => $target['location'] . ' does not appear to be a valid GPG signed archive'
					];
				}

				if(!$obj->verify()){
					// Maybe it can at least get the key....
					if($key = $obj->getKey()){
						return [
							'status' => 0,
							'message' => 'Unable to locate public key for ' . $key . '.  Is it installed?'
						];
					}
					return [
						'status' => 0,
						'message' => 'Invalid GPG signature for ' . $target['typetitle'],
					];
				}

				// The object's key must also match what's in the repo.
				if($obj->getKey() != $target['key']){
					return [
						'status' => 0,
						'message' => '!!!WARNING!!!, Key for ' . $target['typetitle'] . ' is valid, but does not match what was expected form the repository data!  This could be a major risk!',
						'debug' => [
							'detectedkey' => $obj->getKey(),
							'expectedkey' => $target['key'],
						],
					];
				}
				if($verbose){
					self::_PrintInfo('Found key ' . $target['key'] . ' for package maintainer, appears to be valid.', $timer);
					exec('gpg --homedir "' . GPG_HOMEDIR . '" --list-public-keys "' . $target['key'] . '"', $output, $result);
					foreach($output as $line){
						if(trim($line)) self::_PrintInfo(htmlentities($line), $timer);
					}
				}

				if($verbose) self::_PrintInfo('Checking write permissions', $timer);
				$dir = \Core\directory($target['destdir']);
				if(!$dir->isWritable()){
					return [
						'status' => 0,
						'message' => $target['destdir'] . ' is not writable!'
					];
				}
				if($verbose) self::_PrintInfo('OK!', $timer);


				// Decrypt the signed file.
				if($verbose) self::_PrintInfo('Decrypting signed file', $timer);

				if(version_compare(Core::GetComponent('core')->getVersionInstalled(), '4.1.1', '<=') && $file->getBaseFilename() == 'download'){
					// HACK < 4.1.2
					// Retrieve the filename from the last part of the URL.
					// This is required because the URL may be /download?file=component/blah.tgz.asc
					$f = substr($file->getFilename(), strrpos($file->getFilename(), '/'), -4);
					/** @var $localfile \Core\Filestore\File */
					$localfile = $obj->decrypt('tmp/updater/' . $f);
				}
				else{
					/** @var $localfile \Core\Filestore\File */
					$localfile = $obj->decrypt('tmp/updater/');
				}

				/** @var $localobj \Core\Filestore\Contents\ContentTGZ */
				$localobj = $localfile->getContentsObject();
				if($verbose) self::_PrintInfo('OK!', $timer);

				// This tarball will be extracted to a temporary directory, then copied from there.
				if($verbose){
					self::_PrintInfo('Extracting tarball ' . $localfile->getFilename(), $timer);
				}
				$tmpdir = $localobj->extract('tmp/installer-' . Core::RandomHex(4));

				// Now that the data is extracted in a temporary directory, extract every file in the destination.
				/** @var $datadir \Core\Filestore\Directory */
				$datadir = $tmpdir->get('data/');
				if(!$datadir){
					return [
						'status' => 0,
						'message' => 'Invalid package, ' . $target['typetitle'] . ', does not contain a "data" directory.'
					];
				}
				if($verbose) self::_PrintInfo('OK!', $timer);


				if($verbose){
					self::_PrintInfo('Installing files into ' . $target['destdir'], $timer);
				}

				// Will give me an array of Files in the data directory.
				$files = $datadir->ls(null, true);
				// Used to get the relative path for each contained file.
				$datalen = strlen($datadir->getPath());
				foreach($files as $file){
					if(!$file instanceof \Core\Filestore\Backends\FileLocal) continue;

					// It's a file, copy it over.
					// To do so, resolve the directory path inside the temp data dir.
					$dest = \Core\Filestore\Factory::File($target['destdir'] . substr($file->getFilename(), $datalen));
					/** @var $dest \Core\Filestore\Backends\FileLocal */
					if($verbose){
						self::_PrintInfo('...' . substr($dest->getFilename(''), 0, 67), $timer);
					}
					$dest->copyFrom($file, true);
				}
				if($verbose) self::_PrintInfo('OK!', $timer);


				// Cleanup the temp directory
				if($verbose){
					self::_PrintInfo('Cleaning up temporary directory', $timer);
				}
				$tmpdir->remove();
				if($verbose) self::_PrintInfo('OK!', $timer);

				$changes[] = 'Installed ' . $target['typetitle'] . ' ' . $target['version'];
			}
		}

		// Clear the cache so the next pageload will pick up on the new components and goodies.
		\Core\Cache::Flush();
		\Core\Templates\Backends\Smarty::FlushCache();

		// Yup, that's it.
		// Just extract the files and Core will autoinstall/autoupgrade everything on the next page view.


		// yay...
		return [
			'status' => 1,
			'message' => 'Performed all operations successfully!',
			'changes' => $changes,
		];
	}
Exemple #14
0
	/**
	 * Load all the components in the system, replacement for the Core.
	 * @throws CoreException
	 */
	private function _loadComponents() {
		// cannot reload components.
		if ($this->_components) return null;

		$this->_components = array();
		$this->_libraries  = array();
		$tempcomponents    = false;
		Core\Utilities\Logger\write_debug('Starting loading of component metadata');

		// If the site is in DEVELOPMENT mode, component caching would probably be a bad idea; ie: the developer probably wants
		// those component files loaded everytime.
		if(DEVELOPMENT_MODE){
			$enablecache = false;
		}
		else{
			$enablecache = true;
		}

		// Is there a cache of elements available?  This is a primary system cache that greatly increases performance,
		// since it will no longer have to run through each component.xml file to register each one.
		if($enablecache){
			Core\Utilities\Logger\write_debug('Checking core-components cache');
			// Try to load up the cached components and check them first.
			$tempcomponents = \Core\Cache::Get('core-components', (3600 * 24));

			if($tempcomponents !== false){
				// Cached components only need to be loaded.
				foreach ($tempcomponents as $c) {
					try {
						$c->load();
					}
					catch (Exception $e) {
						// Don't completely bail out here, just invalidate the cache and continue on.
						\Core\Cache::Delete('core-components');
						$tempcomponents = false;
					}
				}
			}
		}


		if(!$enablecache || $tempcomponents == false){
			\Core\Utilities\Profiler\Profiler::GetDefaultProfiler()->record('Scanning for component.xml files manually');
			Core\Utilities\Logger\write_debug('Scanning for component.xml files manually');

			// Core is first, (obviously)
			$tempcomponents['core'] = ComponentFactory::Load(ROOT_PDIR . 'core/component.xml');
			Core\Utilities\Logger\write_debug('Core component loaded');

			// First, build my cache of components, regardless if the component is installed or not.
			$dh = opendir(ROOT_PDIR . 'components');
			if (!$dh) throw new CoreException('Unable to open directory [' . ROOT_PDIR . 'components/] for reading.');

			// This will read through every directory in 'components', which is
			// where all components in the system are installed to.
			while (($file = readdir($dh)) !== false) {
				// skip hidden directories.
				if ($file{0} == '.') continue;

				// skip non-directories
				if (!is_dir(ROOT_PDIR . 'components/' . $file)) continue;

				// Skip directories that do not have a readable component.xml file.
				if (!is_readable(ROOT_PDIR . 'components/' . $file . '/component.xml')) continue;

				//Core\Utilities\Logger\write_debug(' * Loading component ' . $file);
				$c = ComponentFactory::Load(ROOT_PDIR . 'components/' . $file . '/component.xml');
				Core\Utilities\Logger\write_debug('Opened component ' . $file);

				// All further operations are case insensitive.
				// The original call to Component needs to be case sensitive because it sets the filename to pull.
				$file = strtolower($file);

				// If the component was flagged as invalid.. just skip to the next one.
				if (!$c->isValid()) {
					if (DEVELOPMENT_MODE) {
						\Core\set_message('Component ' . $c->getName() . ' appears to be invalid.');
					}
					continue;
				}


				$tempcomponents[$file] = $c;
				unset($c);
			}
			closedir($dh);
			\Core\Utilities\Profiler\Profiler::GetDefaultProfiler()->record('Component XML files scanned');

			// Now I probably could actually load the components!

			foreach ($tempcomponents as $c) {
				/** @var Component_2_1 $c */
				try {
					// Load some of the data in the class so that it's available in the cached version.
					// This is because the component 2.1 has built-in caching for many of the XML requests.
					// by calling them once, that lookup data is cached in that component, which in turn gets
					// copied to the cache version here!
					$c->load();
					$c->getClassList();
					$c->getViewSearchDir();
					$c->getSmartyPluginDirectory();
					$c->getWidgetList();
				}
				catch (Exception $e) {
					var_dump($e);
					die();
				}
			}

			// Cache this list!
			if($enablecache){
				Core\Utilities\Logger\write_debug(' * Caching core-components for next pass');
				\Core\Cache::Set('core-components', $tempcomponents, (3600 * 24));
			}
		}

		$list = $tempcomponents;

		\Core\Utilities\Profiler\Profiler::GetDefaultProfiler()->record('Component metadata loaded, starting registration');
		Core\Utilities\Logger\write_debug(' * Component metadata loaded, starting registration');

		// The core component at a minimum needs to be loaded and registered.
		//		$this->_registerComponent($list['core']);
		//		$this->_components['core']->loadFiles();
		//		unset($list['core']);

		// Now that I have a list of components available, copy them into a list of 
		//	components that are installed.

		do {
			$size = sizeof($list);
			foreach ($list as $n => $c) {
				/** @var $c Component_2_1 */

				// Disabled components don't get recognized.
				if($c->isInstalled() && !$c->isEnabled()){
					// But they do get sent to the disabled list!
					$this->_componentsDisabled[$n] = $c;

					unset($list[$n]);
					continue;
				}

				// Clear out the temporary class list
				$this->_tmpclasses = [];

				// If it's loaded, register it and remove it from the list!
				if ($c->isInstalled() && $c->isLoadable() && $c->loadFiles()) {

					try{
						// Allow for on-the-fly package upgrading regardless of DEV mode or not.
						if ($c->needsUpdated()) {

							// Load this component's classes in case an upgrade operation requires one.
							// This allows a component to be loaded partially without completely being loaded.
							$this->_tmpclasses = $c->getClassList();

							// Lock the site first!
							// This is because some upgrade procedures take a long time to upgrade.
							file_put_contents(TMP_DIR . 'lock.message', 'Core Plus is being upgraded, please try again in a minute. ');
							$c->upgrade();
							unlink(TMP_DIR . 'lock.message');
						}
					}
					catch(Exception $e){
						SystemLogModel::LogErrorEvent('/core/component/failedupgrade', 'Ignoring component [' . $n . '] due to an error during upgrading!', $e->getMessage());

						unlink(TMP_DIR . 'lock.message');
						//$c->disable();
						$this->_componentsDisabled[$n] = $c;
						unset($list[$n]);
						continue;
					}

					try{
						$this->_components[$n] = $c;
						$this->_registerComponent($c);
						$c->loadSupplementalModels();
					}
					catch(Exception $e){
						SystemLogModel::LogErrorEvent('/core/component/failedregister', 'Ignoring component [' . $n . '] due to an error during registration!', $e->getMessage());

						//$c->disable();
						$this->_componentsDisabled[$n] = $c;
						unset($list[$n]);
						continue;
					}

					unset($list[$n]);
					continue;
				}


				// Allow for on-the-fly package upgrading regardless of DEV mode or not.
				// Guess this is needed for the loadFiles part...
				if ($c->isInstalled() && $c->needsUpdated() && $c->isLoadable()) {
					// Lock the site first!
					// This is because some upgrade procedures take a long time to upgrade.
					file_put_contents(TMP_DIR . 'lock.message', 'Core Plus is being upgraded, please try again in a minute. ');

					$c->upgrade();
					$c->loadFiles();
					$this->_components[$n] = $c;
					$this->_registerComponent($c);
					unlink(TMP_DIR . 'lock.message');

					unset($list[$n]);
					continue;
				}

				// Allow packages to be auto-installed if in DEV mode.
				// If DEV mode is not enabled, just install the new component, do not enable it.
				if (!$c->isInstalled() && $c->isLoadable()) {
					// Load this component's classes in case an install operation requires one.
					// This allows a component to be loaded partially without completely being loaded.
					$this->_tmpclasses = $c->getClassList();

					// w00t
					$c->install();
					// BLAH, until I fix the disabled-packages-not-viewable bug...
					$c->enable();
					$c->loadFiles();
					$this->_components[$n] = $c;
					$this->_registerComponent($c);

					/*
					if(!DEVELOPMENT_MODE){
						$c->disable();
					}
					else{
						$c->enable();
						$c->loadFiles();
						$this->_components[$n] = $c;
						$this->_registerComponent($c);
					}
					*/
					unset($list[$n]);
					continue;
				}
			}
		}
		while ($size > 0 && ($size != sizeof($list)));

		// If dev mode is enabled, display a list of components installed but not loadable.

		foreach ($list as $n => $c) {

			//$this->_components[$n] = $c;
			$this->_componentsDisabled[$n] = $c;

			// Ignore anything with the execmode different, those should be minor notices for debugging if anything.
			if ($c->error & Component_2_1::ERROR_WRONGEXECMODE) continue;

			if (DEVELOPMENT_MODE) {
				SystemLogModel::LogErrorEvent('/core/component/missingrequirement', 'Could not load installed component ' . $n . ' due to requirement failed.', $c->getErrors());
			}
		}

		// Don't forget to load the themes too!
		if(class_exists('ThemeHandler')){
			foreach(ThemeHandler::GetAllThemes() as $theme){
				/** @var $theme Theme */
				$theme->load();
			}
		}

		// Lastly, make sure that the template path cache is updated!
		if(class_exists('\\Core\\Templates\\Template')){
			\Core\Templates\Template::RequeryPaths();	
		}
	}
	/**
	 * Run through and reinstall all components and themes.
	 *
	 * @return int
	 */
	public function reinstallAll() {
		// Admin-only page.
		if(!\Core\user()->checkAccess('g:admin')){
			return View::ERROR_ACCESSDENIED;
		}

		// Just run through every component currently installed and reinstall it.
		// This will just ensure that the component is up to date and correct as per the component.xml metafile.
		$view    = $this->getView();
		$request = $this->getPageRequest();


		if($request->isPost()){
			$view->mode = View::MODE_NOOUTPUT;
			$view->contenttype = View::CTYPE_HTML;
			$view->record = false;
			$view->templatename = null;
			$view->render();

			// Try to perform the reinstall.
			$changes  = array();
			$errors   = array();
			$allpages = [];

			$t = ThemeHandler::GetTheme();

			CLI::PrintHeader('Reinstalling Theme ' . $t->getName());
			if (($change = $t->reinstall(1)) !== false) {

				SystemLogModel::LogInfoEvent('/updater/theme/reinstall', 'Theme ' . $t->getName() . ' reinstalled successfully', implode("\n", $change));

				$changes[] = '<b>Changes to theme [' . $t->getName() . ']:</b><br/>' . "\n" . implode("<br/>\n", $change) . "<br/>\n<br/>\n";
			}

			foreach (Core::GetComponents() as $c) {
				/** @var $c Component_2_1 */

				try{
					if(!$c->isInstalled()) continue;
					if(!$c->isEnabled()) continue;

					CLI::PrintHeader('Reinstalling Component ' . $c->getName());
					// Request the reinstallation
					$change = $c->reinstall(1);

					// 1.0 version components don't support verbose changes :(
					if ($change === true) {
						$changes[] = '<b>Changes to component [' . $c->getName() . ']:</b><br/>' . "\n(list of changes not supported with this component!)<br/>\n<br/>\n";
					}
					// 2.1 components support an array of changes, yay!
					elseif ($change !== false) {
						$changes[] = '<b>Changes to component [' . $c->getName() . ']:</b><br/>' . "\n" . implode("<br/>\n", $change) . "<br/>\n<br/>\n";
					}
					// I don't care about "else", nothing changed if it was false.

					// Get the pages, (for the cleanup operation)
					$allpages = array_merge($allpages, $c->getPagesDefined());
				}
				catch(DMI_Query_Exception $e){
					$changes[] = 'Attempted database changes to component [' . $c->getName() . '], but failed!<br/>';
					//var_dump($e); die();
					$errors[] = array(
						'type' => 'component',
						'name' => $c->getName(),
						'message' => $e->getMessage() . '<br/>' . $e->query,
					);
				}
				catch(Exception $e){
					$changes[] = 'Attempted changes to component [' . $c->getName() . '], but failed!<br/>';
					//var_dump($e); die();
					$errors[] = array(
						'type' => 'component',
						'name' => $c->getName(),
						'message' => $e->getMessage(),
					);
				}
			}

			// Flush any non-existent admin page.
			// These can be created from developers changing their page URLs after the page is already registered.
			// Purging admin-only pages is relatively safe because these are defined in component metafiles anyway.
			CLI::PrintHeader('Cleaning up non-existent pages');
			$pageremovecount = 0;
			foreach(
				\Core\Datamodel\Dataset::Init()
					->select('baseurl')
					->table('page')
					->where('admin = 1')
					->execute() as $row
			){
				$baseurl = $row['baseurl'];

				// This page existed already, no need to do anything :)
				if(isset($allpages[$baseurl])) continue;

				++$pageremovecount;

				// Otherwise, this page was deleted or for some reason doesn't exist in the component list.....
				// BUH BAI
				\Core\Datamodel\Dataset::Init()->delete()->table('page')->where('baseurl = ' . $baseurl)->execute();
				\Core\Datamodel\Dataset::Init()->delete()->table('page_meta')->where('baseurl = ' . $baseurl)->execute();
				CLI::PrintLine("Flushed non-existent admin page: " . $baseurl);
				$changes[] = "<b>Flushed non-existent admin page:</b> " . $baseurl;
			}
			if($pageremovecount == 0){
				CLI::PrintLine('No pages flushed');
			}



			if(sizeof($errors) > 0){
				CLI::PrintHeader('Done, but with errors');
				foreach($errors as $e){
					CLI::PrintError('Error while processing ' . $e['type'] . ' ' . $e['name'] . ': ' . $e['message']);
				}
			}
			else{
				CLI::PrintHeader('DONE!');
			}

			foreach($changes as $str){
				echo $str;
			}

			// Flush the system cache, just in case
			\Core\Cache::Flush();
			\Core\Templates\Backends\Smarty::FlushCache();

			// Increment the version counter.
			$version = ConfigHandler::Get('/core/filestore/assetversion');
			ConfigHandler::Set('/core/filestore/assetversion', ++$version);
		} // End if is post.

		//$page->title = 'Reinstall All Components';
		$this->setTemplate('/pages/admin/reinstallall.tpl');
	}
	/**
	 * Render the View to the browser.
	 */
	public function render(){
		\Core\Utilities\Profiler\Profiler::GetDefaultProfiler()->record('Starting PageRequest->render()');

		$view = $this->getView();
		$page = $this->getPageModel();

		// Dispatch the hooks here if it's a 404 or 403.
		if ($view->error == View::ERROR_ACCESSDENIED || $view->error == View::ERROR_NOTFOUND) {
			// Let other things chew through it... (optionally)
			HookHandler::DispatchHook('/core/page/error-' . $view->error, $view);
		}

		try {
			// This will pre-fetch the contents of the entire page and store it into memory.
			// If it is cacheable, then it will be cached and used for the next execution.

			// If the user has the view user activity permission, add the link to that page!
			if(\Core\user()->checkAccess('p:user_activity_list') && $page && $page->exists()){
				$view->addControl(
					'User Activity Details',
					'/useractivity/details?filter[baseurl]=' . $page->get('baseurl'),
					'eye'
				);
			}

			$view->fetch();
		}
		catch (Exception $e) {
			// If something happens in the rendering of the template... consider it a server error.
			$view->error   = View::ERROR_SERVERERROR;
			$view->baseurl = '/error/error/500';
			$view->setParameters(array());
			$view->templatename   = '/pages/error/error500.tpl';
			$view->mastertemplate = ConfigHandler::Get('/theme/default_template');
			$view->assignVariable('exception', $e);
			\Core\ErrorManagement\exception_handler($e);

			$view->fetch();
		}


		if($this->isCacheable()){
			$uakey = \Core\UserAgent::Construct()->getPseudoIdentifier();
			$urlkey = $this->host . $this->uri;
			$expires = $page->get('expires'); // Number of seconds.
			$key = 'page-cache-' . md5($urlkey . '-' . $uakey);

			$d = new \Core\Date\DateTime();
			$d->modify('+' . $expires . ' seconds');

			$view->headers['Cache-Control'] = 'max-age=' . $expires;
			$view->headers['Expires'] = $d->format('r', \Core\Date\Timezone::TIMEZONE_GMT);
			$view->headers['Vary'] = 'Accept-Encoding,User-Agent,Cookie';
			$view->headers['X-Core-Cached-Date'] = \Core\Date\DateTime::NowGMT('r');
			$view->headers['X-Core-Cached-Server'] = 1; // @todo Implement multi-server support.
			$view->headers['X-Core-Cached-Render-Time'] = \Core\Utilities\Profiler\Profiler::GetDefaultProfiler()->getTimeFormatted();

			// Record the actual View into cache.
			\Core\Cache::Set($key, $view, $expires);

			// And record the key onto an index cache record so there's a record of what to delete on updates.
			$indexkey = $page->getIndexCacheKey();
			$index = \Core\Cache::Get($indexkey, SECONDS_ONE_DAY);
			if(!$index){
				$index = [];
			}
			$index[] = $key;
			\Core\Cache::Set($indexkey, $index, SECONDS_ONE_DAY);
		}
		elseif(($reason = $this->isNotCacheableReason()) !== null){
			$view->headers['X-Core-NotCached-Reason'] = $reason;
		}
		$view->headers['X-Core-Render-Time'] = \Core\Utilities\Profiler\Profiler::GetDefaultProfiler()->getTimeFormatted();

		$view->render();

		// Make sure I update any existing page now that the controller has ran.
		if ($page && $page->exists() && $view->error == View::ERROR_NOERROR) {

			// Only increase the pageview count if the visitor is not a bot.
			// UA detection isn't very accurate, but this isn't for precision accuracy, merely a rough estimate.
			if(!\Core\UserAgent::Construct()->isBot()){
				$page->set('pageviews', $page->get('pageviews') + 1);
			}

			$page->set('last_template', $view->templatename);
			$page->set('body', $view->fetchBody());

			$page->save();
		}

		// Just before the page stops execution...
		HookHandler::DispatchHook('/core/page/postrender');
	}
Exemple #17
0
			// All Models MUST reside in the global namespace in order to be valid.
			continue;
		}

		$ref = new ReflectionClass($class);
		if(!$ref->getProperty('HasSearch')->getValue()){
			// This model doesn't have the searchable flag, skip it.
			continue;
		}

		CLI::PrintActionStart("Syncing searchable model $class");
		$fac = new ModelFactory($class);
		foreach($fac->get() as $m){
			/** @var Model $m */
			$m->set('search_index_pri', '!');
			$m->save();
		}
		CLI::PrintActionStatus('ok');
		$changes[] = "Synced searchable model " . $class;
	}
}

// Flush the system cache, just in case
\Core\Cache::Flush();
\Core\Templates\Backends\Smarty::FlushCache();


CLI::PrintHeader('DONE!');
foreach($changes as $line){
	CLI::PrintLine($line);
}
Exemple #18
0
 public function __construct($ip_addr)
 {
     try {
         if ($ip_addr == '127.0.0.1') {
             // Load local connections up with Columbus, OH.
             // Why?  ;)
             $cache = ['city' => 'Columbus', 'province' => 'OH', 'country' => 'US', 'timezone' => 'America/New_York', 'postal' => '43215'];
         } else {
             $cacheKey = 'iplookup-' . $ip_addr;
             $cache = Cache::Get($cacheKey);
             if (!$cache) {
                 $reader = new \GeoIp2\Database\Reader(ROOT_PDIR . 'components/geographic-codes/libs/maxmind-geolite-db/GeoLite2-City.mmdb');
                 /** @var \GeoIp2\Model\CityIspOrg $geo */
                 $geo = $reader->cityIspOrg($ip_addr);
                 //$geo = $reader->cityIspOrg('67.149.214.236');
                 $reader->close();
                 $sd = isset($geo->subdivisions[0]) ? $geo->subdivisions[0] : null;
                 $cache = ['city' => $geo->city->name, 'province' => $sd ? $sd->isoCode : '', 'country' => $geo->country->isoCode, 'timezone' => $geo->location->timeZone, 'postal' => $geo->postal->code];
                 Cache::Set($cacheKey, $cache, SECONDS_ONE_WEEK);
             }
         }
     } catch (\Exception $e) {
         // Well, we tried!  Load something at least.
         $cacheKey = 'iplookup-' . $ip_addr;
         $cache = ['city' => 'McMurdo Base', 'province' => '', 'country' => 'AQ', 'timezone' => 'CAST', 'postal' => ''];
         Cache::Set($cacheKey, $cache, SECONDS_ONE_HOUR);
     }
     $this->city = $cache['city'];
     $this->province = $cache['province'];
     $this->country = $cache['country'];
     $this->timezone = $cache['timezone'];
     $this->postal = $cache['postal'];
 }
Exemple #19
0
	/**
	 * Construct a UserAgent object with full caching enabled.
	 *
	 * @param $useragent
	 *
	 * @return UserAgent
	 */
	public static function Construct($useragent = null){
		if($useragent === null){
			$useragent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
		}

		$cachekey = 'useragent-constructor-' . md5($useragent);
		$cache = Cache::Get($cachekey);
		if(!$cache){
			$cache = new UserAgent($useragent);
			Cache::Set($cachekey, $cache, SECONDS_ONE_WEEK);
		}

		return $cache;
	}
	/**
	 * Component installation operations all share common actions, (mostly).
	 *
	 * Returns false if nothing changed, else will return an array containing all changes.
	 *
	 * @param int $verbosity 0 for standard output, 1 for real-time, 2 for real-time verbose output.
	 *
	 * @return false | array
	 * @throws InstallerException
	 */
	private function _performInstall($verbosity = 0) {
		// make sure that some of the installer elements are available!
		require_once(ROOT_PDIR . 'core/libs/core/InstallerException.php'); #SKIPCOMPILER

		$changed = array();

		$change = $this->_parseDBSchema(true, $verbosity);
		if ($change !== false){
			$changed = array_merge($changed, $change);
		}

		$change = $this->_parseConfigs(true, $verbosity);
		if ($change !== false){
			$changed = array_merge($changed, $change);
		}

		$change = $this->_parseUserConfigs(true, $verbosity);
		if ($change !== false){
			$changed = array_merge($changed, $change);
		}

		$change = $this->_parsePages(true, $verbosity);
		if ($change !== false){
			$changed = array_merge($changed, $change);
		}

		$change = $this->_parseWidgets(true, $verbosity);
		if ($change !== false){
			$changed = array_merge($changed, $change);
		}

		$change = $this->_parseAssets(true, $verbosity);
		if ($change !== false){
			$changed = array_merge($changed, $change);
		}

		// Core has some additional things that need to ran through.
		if($this->getKeyName() == 'core'){
			// Make sure that files/private has a restrictive .htaccess file installed.
			$f = \Core\Filestore\Factory::File('private/.htaccess');
			if(!$f->exists() && $f->isWritable()){
				$src = \Core\Filestore\Factory::File('core/htaccess.private');
				if($src->copyTo($f)){
					$changed[] = 'Installed private htaccess file into ' . $f->getFilename();
				}
			}

			// Make sure that files/public has the appropriate .htaccess file installed.
			$f = \Core\Filestore\Factory::File('public/.htaccess');
			if(!$f->exists() && $f->isWritable()){
				$src = \Core\Filestore\Factory::File('core/htaccess.public');
				if($src->copyTo($f)){
					$changed[] = 'Installed public htaccess file into ' . $f->getFilename();
				}
			}

			// Make sure that files/public has the appropriate .htaccess file installed.
			$f = \Core\Filestore\Factory::File('asset/.htaccess');
			// This is a bit of a hack because I need the parent directory for assets, not the theme-specific version.
			$f->setFilename(dirname(dirname($f->getFilename())) . '/.htaccess');
			if(!$f->exists() && $f->isWritable()){
				$src = \Core\Filestore\Factory::File('core/htaccess.assets');
				if($src->copyTo($f)){
					$changed[] = 'Installed assets htaccess file into ' . $f->getFilename();
				}
			}
		}

		// Ensure that the core component cache is purged too!
		\Core\Cache::Delete('core-components');

		return (sizeof($changed)) ? $changed : false;
	}