/**
  * Main controller interceptor for all multi upload methods with this utility.
  */
 public function index()
 {
     $request = $this->getPageRequest();
     $view = $this->getView();
     // This page is ALWAYS json.
     $view->contenttype = View::CTYPE_JSON;
     $view->mode = View::MODE_AJAX;
     if (!is_array(\Core\Session::Get('multifileinputobjects'))) {
         return View::ERROR_BADREQUEST;
     }
     // Whatever the method, it should have a matching key that identifies which form it came from,
     // (since that form element has the metadata attached to it)
     // This can either be in the POST (for full uploads), or in the headers.
     $key = false;
     if (isset($_POST['key'])) {
         $key = $_POST['key'];
     }
     if (isset($_SERVER['HTTP_X_KEY'])) {
         $key = $_SERVER['HTTP_X_KEY'];
     }
     if (!$key) {
         return View::ERROR_BADREQUEST;
     }
     // The key also must exist!
     if (!isset(\Core\Session::Get('multifileinputobjects')[$key])) {
         return View::ERROR_BADREQUEST;
     }
     $this->_formelement = unserialize(\Core\Session::Get('multifileinputobjects')[$key]['obj']);
     if ($request->method == View::METHOD_POST) {
         //var_dump($_SERVER);die();
         // Damn browsers that don't support DELETE...
         if (isset($_REQUEST['_method']) && $_REQUEST['_method'] === 'DELETE') {
             $view->jsondata = $this->_doDelete();
         } elseif (sizeof($_FILES)) {
             $view->jsondata = $this->_doPost();
         } elseif (isset($_SERVER['HTTP_CONTENT_DISPOSITION'])) {
             $view->jsondata = $this->_doStream();
         } else {
             // NO COOKIE FOR YOU!
             return View::ERROR_BADREQUEST;
         }
         /*fix for IE not handling XMLHTTPRequest file uploads correctly */
         header('Vary: Accept');
         if (isset($_SERVER['HTTP_ACCEPT']) && strpos($_SERVER['HTTP_ACCEPT'], 'application/json') !== false) {
             $view->contenttype = "application/json";
         } else {
             //$view->contenttype = "text/plain";
             $view->mode = View::MODE_NOOUTPUT;
             echo json_decode($view->jsondata);
         }
         /*end IE fix*/
     } else {
         // What, it's not a post even?
         return View::ERROR_BADREQUEST;
     }
 }
 public function setValue($value)
 {
     if (!$value) {
         $this->_error = $this->get('title') . ' is required.';
         return false;
     }
     if ($value != \Core\Session::Get('captcha')) {
         $this->_error = $this->get('title') . ' does not match image.';
         return false;
     }
     parent::setValue('');
 }
 public function render()
 {
     if (!$this->get('basedir')) {
         throw new Exception('MultiFileInput cannot be rendered without a basedir attribute!');
     }
     // Make sure it ends with a trailing slash.
     if (substr($this->get('basedir'), -1) != '/') {
         $this->_attributes['basedir'] .= '/';
     }
     //var_dump($_SESSION['multifileinputobjects'], serialize($this->_attributes)); die();
     // This is a slightly different element than the traditional form system, as it must be able to be called without
     // the rest of the form system on submit.
     // This is because this system will do an ajax submit to do the actual upload.
     if (!is_array(\Core\Session::Get('multifileinputobjects'))) {
         \Core\Session::Set('multifileinputobjects', []);
     }
     // I don't need this key to be cryptographically secure, just generally unique.
     $key = md5(serialize($this->_attributes));
     foreach (\Core\Session::Get('multifileinputobjects') as $obj) {
         if (!isset($obj['key'])) {
             continue;
         }
         if ($obj['key'] == $key) {
             $this->set('id', $obj['id']);
         }
     }
     if (!isset($this->_attributes['id'])) {
         // This system requires a valid id.
         $this->set('id', 'multifileinput-' . Core::RandomHex('2'));
     }
     $this->set('key', $key);
     $this->set('uploadkey', $key);
     // Convert the string representation of a filesize to the raw bytes.
     $size = strtoupper(str_replace(' ', '', ini_get('upload_max_filesize')));
     if (strpos($size, 'G') !== false) {
         $size = preg_replace('/[^0-9]/', '', $size);
         $size = $size * (1024 * 1024 * 1024);
     } elseif (strpos($size, 'M') !== false) {
         $size = preg_replace('/[^0-9]/', '', $size);
         $size = $size * (1024 * 1024);
     } elseif (strpos($size, 'K') !== false) {
         $size = preg_replace('/[^0-9]/', '', $size);
         $size = $size * 1024;
     }
     $this->set('maxsize', $size);
     // Now that the session variable has been initialized, the traditional session variable is reliable.
     $_SESSION['multifileinputobjects'][$key] = array('obj' => serialize($this), 'key' => $key, 'id' => $this->_attributes['id']);
     return parent::render();
 }
Example #4
0
 /**
  * Internal function to parse and handle the configs in the theme.xml file.
  * This is used for installations and upgrades.
  *
  * Returns false if nothing changed, else will return the configuration options changed.
  *
  * @param boolean $install Set to false to force uninstall/disable mode.
  * @param int     $verbosity (default 0) 0: standard output, 1: real-time, 2: real-time verbose output.
  *
  * @return false | array
  *
  * @throws \InstallerException
  */
 public function _parseConfigs($install = true, $verbosity = 0)
 {
     // Keep track of if this changed anything.
     $changes = array();
     $action = $install ? 'Installing' : 'Uninstalling';
     $set = $install ? 'Set' : 'Unset';
     \Core\Utilities\Logger\write_debug($action . ' configs for ' . $this->getName());
     // I need to get the schema definitions first.
     $node = $this->_xmlloader->getElement('configs');
     //$prefix = $node->getAttribute('prefix');
     // Now, get every table under this node.
     foreach ($node->getElementsByTagName('config') as $confignode) {
         /** @var \DOMElement $confignode */
         $key = $confignode->getAttribute('key');
         $options = $confignode->getAttribute('options');
         $type = $confignode->getAttribute('type');
         $default = $confignode->getAttribute('default');
         $title = $confignode->getAttribute('title');
         $description = $confignode->getAttribute('description');
         $mapto = $confignode->getAttribute('mapto');
         $encrypted = $confignode->getAttribute('encrypted');
         $formAtts = $confignode->getAttribute('form-attributes');
         if ($encrypted === null || $encrypted === '') {
             $encrypted = '0';
         }
         if ($verbosity == 2) {
             CLI::PrintActionStart($action . ' config ' . $key);
         }
         // Themes only allow for keys starting with "/theme/"!
         // This is to encourage that all themes share a common subset of configuration options.
         // EG: if the end user sees: "Site Logo", "Business Address", "Business Phone" on one theme,
         // they would be expecting to see those same options with the same values if they change the theme,
         // (and the new theme supports those same options).
         if (strpos($key, '/theme/') !== 0) {
             trigger_error('Please ensure that all config options in themes start with "/theme/"! (Mismatched config found in ' . $this->getName() . ':' . $key, E_USER_NOTICE);
             continue;
         }
         // Default if omitted.
         if (!$type) {
             $type = 'string';
         }
         $m = \ConfigHandler::GetConfig($key);
         $m->set('options', $options);
         $m->set('type', $type);
         $m->set('default_value', $default);
         $m->set('title', $title);
         $m->set('description', $description);
         $m->set('mapto', $mapto);
         $m->set('encrypted', $encrypted);
         $m->set('form_attributes', $formAtts);
         // Default from the xml, only if it's not already set.
         if ($m->get('value') === null || !$m->exists()) {
             $m->set('value', $confignode->getAttribute('default'));
         }
         // Allow configurations to overwrite any value.  This is useful on the initial installation.
         if (is_array(\Core\Session::Get('configs')) && isset(\Core\Session::Get('configs')[$key])) {
             $m->set('value', \Core\Session::Get('configs')[$key]);
         }
         if ($m->save()) {
             $changes[] = $set . ' configuration [' . $m->get('key') . '] to [' . $m->get('value') . ']';
             if ($verbosity == 2) {
                 CLI::PrintActionStatus(true);
             }
         } else {
             if ($verbosity == 2) {
                 CLI::PrintActionStatus('skip');
             }
         }
         // Make it available immediately
         \ConfigHandler::CacheConfig($m);
     }
     return sizeof($changes) ? $changes : false;
 }
	/**
	 * Load the values from the session data.
	 *
	 * This is automatically called by the load function.
	 */
	public function loadSession(){
		if(!$this->_name){
			// Ok, no name.. no loading.
			return;
		}
		if(($filters = \Core\Session::Get('filters/' . $this->_name)) !== null){
			foreach($filters as $f => $v){
				if(!isset($this->_elementindexes['filter[' . $f . ']'])) continue;
				/** @var $el FormElement */
				$el = $this->_elementindexes['filter[' . $f . ']'];
				$el->setValue($v);
			}
		}

		if(\Core\Session::Get('filtersort/' . $this->_name) !== null){
			$this->_sortkey = \Core\Session::Get('filtersort/' . $this->_name)['sortkey'];
			$this->_sortdir = \Core\Session::Get('filtersort/' . $this->_name)['sortdir'];
		}

		$cachedPageData = \Core\Session::Get('filterpage/' . $this->_name);
		if($cachedPageData !== null && isset($cachedPageData['page'])) {
			$this->_currentpage = \Core\Session::Get('filterpage/' . $this->_name)['page'];
		}
		if($cachedPageData !== null && isset($cachedPageData['limit'])){
			$this->setLimit(\Core\Session::Get('filterpage/' . $this->_name)['limit']);
		}
	}
	/**
	 * @return null|int
	 */
	public function pageinsertables_update(){
		$request = $this->getPageRequest();
		$view = $this->getView();
		$view->mode = View::MODE_AJAX;
		$view->contenttype = View::CTYPE_JSON;
		$view->record = false;

		// This is an ajax-only request.
		if(!$request->isAjax()){
			return View::ERROR_BADREQUEST;
		}

		$formid = $request->getPost('___formid');
		if(!$formid){
			return View::ERROR_NOTFOUND;
		}

		// Lookup that form!
		if(\Core\Session::Get('FormData/' . $formid) === null){
			return View::ERROR_NOTFOUND;
		}

		/** @var $form Form */
		$form = unserialize(\Core\Session::Get('FormData/' . $formid));

		if(!$form){
			return View::ERROR_NOTFOUND;
		}

		// Run though each element submitted and try to validate it.
		if (strtoupper($form->get('method')) == 'POST') $src =& $_POST;
		else $src =& $_GET;

		$form->loadFrom($src, true);

		// Now that the form has been loaded with the data, reinitialize the page's insertable elements.
		foreach($form->getModels() as $prefix => $model){
			if($model instanceof PageModel && $form->getElement($prefix . '[page_template]')){
				$pagetemplate = $form->getElement($prefix . '[page_template]');

				// Get all insertables currently present and remove them from the form.
				// (They will be added back shortly)
				foreach($form->getElements(true, false) as $el){
					$name = $el->get('name');
					if(strpos($name, $prefix . '[insertables]') === 0){
						$form->removeElement($name);
					}
				}

				// Now that the previous insertables are removed, update the value on the model and add the new insertables.
				// This block of logic is required because the template systems look at the last template set in the database.
				// Since what's in the databse isn't what we want here, we need to spoof it so the correct template is
				// used for retrieving form elements.
				$model->set('page_template', $pagetemplate->get('value'));

				// Set the last_template so that the traditional queries to getTemplate work without reverting back to the default template.
				$t = $model->getBaseTemplateName();

				// Allow the specific template to be overridden.
				if (($override = $model->get('page_template'))){
					$t = substr($t, 0, -4) . '/' . $override;
					$model->set('last_template', $t);
				}
				else{
					$model->set('last_template', null);
				}

				$tpl = Core\Templates\Template::Factory($model->getTemplateName());
				if($tpl){
					// My counter for which element was added last... I need this because I have "addElementAfter"...
					// so if I just kept adding the stack after a single element, they'd be in reverse order.
					// ie: stack: [a, b, c] -> {ref_el}, c, b, a
					$lastelementadded = $pagetemplate;
					$insertables = $tpl->getInsertables();
					foreach($insertables as $key => $dat){
						$type = $dat['type'];
						$dat['name'] = $prefix . '[insertables][' . $key . ']';

						// This insertable may already have content from the database... if so I want to pull that!
						$i = InsertableModel::Construct($model->get('baseurl'), $key);
						if ($i->get('value') !== null){
							$dat['value'] = $i->get('value');
						}

						$dat['class'] = 'insertable';

						$insertableelement = FormElement::Factory($type, $dat);
						$form->addElementAfter($insertableelement, $lastelementadded);
						$lastelementadded = $insertableelement;
					}
				}

				// Since there are new elements here, there may be old values that correspond to the new elements too.
				$form->loadFrom($src, true);

				// Don't forget to re-save these form updates back to the session!
				$form->persistent = true;
				$form->saveToSession();

				$view->jsondata = array(
					'status' => '1',
					'message' => 'Switched templatename successfully',
					'formid' => $form->get('uniqueid'),
				);
				return null;
			} // if($model instanceof PageModel && $form->getElement($prefix . '[page_template]'))
		} // foreach($form->getModels() as $prefix => $model)

		// Ummmm.....
		$view->jsondata = array(
			'status' => '0',
			'message' => 'No page found :/',
			'formid' => null,
		);
	}
Example #7
0
	/**
	 * Retrieve the messages and optionally clear the message stack.
	 *
	 * @param bool $returnSorted
	 * @param bool $clearStack
	 *
	 * @return array
	 */
	static public function GetMessages($returnSorted = false, $clearStack = true) {
		$stack = Session::Get('message_stack', []);

		if($returnSorted){
			$stack = \Core::SortByKey($stack, 'mtype');
		}

		if($clearStack){
			Session::UnsetKey('message_stack');
		}
		return $stack;
	}
 /**
  * Check the user's IP in the blacklist and see if it's found.
  *
  * If it is and has a high enough submission rate, (in a 24 hour period), then block the user completely and immediately.
  */
 public static function CheckIP()
 {
     $record = \sfsBlacklistModel::Construct(REMOTE_IP);
     // It's not in there, YAY!
     if (!$record->exists()) {
         return;
     }
     // Is the submission score high enough?
     $highscore = 100;
     if ($record->get('submissions') > $highscore) {
         // YOU can haz good party tiem nau
         \SystemLogModel::LogSecurityEvent('/security/blocked', 'Blocking IP due to over ' . $highscore . ' submissions to sfs in a 24 hour period.');
         die('IP Blocked due to high spam score');
     }
     // Submissions listed, but not exceedingly high?
     $warnlevel = 5;
     if ($record->get('submissions') > $warnlevel) {
         if (\Core\Session::Get('security_antispam_allowed') === null) {
             $html = '<html><body>';
             $html .= '<!-- You smell of spam.... are you sure you didn\'t come from a can?-->';
             if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['happyfuntime']) && \Core\Session::Get('happyfuntimecheck')) {
                 // It's an attempt!
                 if ($_POST['happyfuntime'] == \Core\Session::Get('happyfuntimecheck')) {
                     \SystemLogModel::LogSecurityEvent('/security/unblocked', 'User successfully answered an anti-bot math question, unblocking.');
                     \Core\Session::Set('security_antispam_allowed', true);
                 } else {
                     \SystemLogModel::LogSecurityEvent('/security/captchafailed', 'User attempted, but failed in answering an anti-bot math question.');
                     $html .= '<b>NOPE!</b>';
                 }
             }
             \SystemLogModel::LogSecurityEvent('/security/blocked', 'Blocking IP due to over ' . $warnlevel . ' submissions to sfs in a 24 hour period.');
             $random1 = rand(4, 6) * 2;
             $random2 = rand(1, 3) * 2;
             $random3 = rand(1, 2);
             switch ($random3) {
                 case 1:
                     $result = $random1 / $random2;
                     $operation = 'divided by';
                     break;
                 case 2:
                     $result = $random1 * $random2;
                     $operation = 'multiplied by';
                     break;
             }
             \Core\Session::Set('happyfuntimecheck', $result);
             switch ($random2) {
                 case 1:
                     $random2 = 'oNe';
                     break;
                 case 2:
                     $random2 = 'Tw0';
                     break;
                 case 3:
                     $random2 = 'ThRe';
                     break;
                 case 4:
                     $random2 = 'Foor';
                     break;
                 case 5:
                     $random2 = 'fIve';
                     break;
                 case 6:
                     $random2 = 'Siix';
                     break;
             }
             $html .= '<form method="POST"><p>What is ' . $random1 . ' ' . $operation . ' ' . $random2 . '?</p><input type="text" name="happyfuntime" size="3"/><input type="submit" value="GO"/></form></body></html>';
             die($html);
         }
     }
 }
Example #9
0
	/**
	 * Handler to actually perform the import.
	 *
	 * @param \Form $form
	 * @return bool
	 */
	public static function FormHandler2(\Form $form) {
		$filename = Session::Get('user-import/file');
		$file = Factory::File($filename);
		/** @var $contents \Core\Filestore\Contents\ContentCSV */
		$contents = $file->getContentsObject();

		// If the user checked that it has a header... do that.
		$contents->_hasheader = $form->getElement('has_header')->get('checked');

		// Merge
		$merge = $form->getElement('merge_duplicates')->get('checked');

		// Handle the map-to directives.
		$maptos = array();
		foreach($form->getElements() as $el){
			if(strpos($el->get('name'), 'mapto[') === 0 && $el->get('value')){
				$k = substr($el->get('name'), 6, -1);
				$maptos[$k] = $el->get('value');
			}
		}

		// Handle the group mappings
		$groups = $form->getElement('groups[]')->get('value');

		// And keep a log of the bad transfers and some other data.
		$counts = ['created' => 0, 'updated' => 0, 'failed' => 0, 'skipped' => 0];
		Session::Set('user-import/fails', []);

		$incoming = $contents->parse();
		foreach($incoming as $record){
			try{
				// Create a data map of this record for fields to actually map over.
				$dat = array();
				foreach($maptos as $recordkey => $userkey){
					$dat[$userkey] = $record[$recordkey];
				}

				// No email, NO IMPORT!
				if(!$dat['email']){
					$counts['skipped']++;
					continue;
				}

				// Try to find this record by email, since that's a primary key.
				$existing = \UserModel::Find(['email = ' . $dat['email'] ], 1);
				if($existing && !$merge){
					// Skip existing records.
					$counts['skipped']++;
				}
				elseif($existing){
					// Update!
					$existing->setFromArray($dat);
					$existing->setGroups($groups);

					if($existing->save()){
						$counts['updated']++;
					}
					else{
						$counts['skipped']++;
					}
				}
				else{
					$new = new \UserModel();
					$new->setFromArray($dat);
					$new->setGroups($groups);
					$new->save();
					$counts['created']++;
				}
			}
			catch(\Exception $e){
				// @todo Handle this
				die($e->getMessage());
			}
			//
		}

		Session::Set('user-import/counts', $counts);

		return true;
	}
Example #10
0
	/**
	 * Sync the search index fields of every model on the system.
	 *
	 * @return int
	 */
	public function syncSearchIndex(){
		// 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();
		$changes = [];
		$outoftime = false;
		$counter = 0;
		$resume = \Core\Session::Get('syncsearchresume', 1);
		$timeout = ini_get('max_execution_time');
		// Dunno why this is returning 0, but if it is, reset it to 30 seconds!
		if(!$timeout) $timeout = 30;
		$memorylimit = ini_get('memory_limit');
		if(stripos($memorylimit, 'M') !== false){
			$memorylimit = str_replace(['m', 'M'], '', $memorylimit);
			$memorylimit *= (1024*1024);
		}
		elseif(stripos($memorylimit, 'G') !== false){
			$memorylimit = str_replace(['g', 'G'], '', $memorylimit);
			$memorylimit *= (1024*1024*1024);
		}

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

			if($outoftime){
				break;
			}

			foreach($c->getClassList() as $class => $file){
				if($outoftime){
					break;
				}

				if($class == 'model'){
					continue;
				}
				if(strrpos($class, 'model') !== strlen($class) - 5){
					// If the class doesn't explicitly end with "Model", it's also not a model.
					continue;
				}
				if(strpos($class, '\\') !== false){
					// If this "Model" class is namespaced, it's not a valid model!
					// 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;
				}

				$c = ['name' => $class, 'count' => 0];
				$fac = new ModelFactory($class);
				while(($m = $fac->getNext())){
					++$counter;

					if($counter < $resume){
						// Allow this process to be resumed where it left off, since it may take more than 30 seconds.
						continue;
					}

					if(\Core\Utilities\Profiler\Profiler::GetDefaultProfiler()->getTime() + 5 >= $timeout){
						// OUT OF TIME!
						// Remember where this process left off and exit.
						\Core\Session::Set('syncsearchresume', $counter);
						$outoftime = true;
						break;
					}

					if(memory_get_usage(true) + 40485760 >= $memorylimit){
						// OUT OF MEMORY!
						// Remember where this process left off and exit.
						\Core\Session::Set('syncsearchresume', $counter);
						$outoftime = true;
						break;
					}

					/** @var Model $m */
					$m->set('search_index_pri', '!');
					$m->save();
					$c['count']++;
				}

				$changes[] = $c;
			}
		}

		if(!$outoftime){
			// It finished!  Unset the resume counter.
			\Core\Session::UnsetKey('syncsearchresume');
		}


		$view->title = 'Sync Searchable Index';
		$view->assign('changes', $changes);
		$view->assign('outoftime', $outoftime);
	}
Example #11
0
	/**
	 * Function that is fired off on page load.
	 * This checks if a form was submitted and that form was present in the SESSION.
	 *
	 * @return null
	 */
	public static function CheckSavedSessionData() {
		// This needs to ignore the /form/savetemporary.ajax page!
		// This is a custom page that's meant to intercept all POST submissions.
		if(preg_match('#^/form/(.*)\.ajax$#', REL_REQUEST_PATH)) return;

		// There has to be data in the session.
		$forms = \Core\Session::Get('FormData/*');

		$formid = (isset($_REQUEST['___formid'])) ? $_REQUEST['___formid'] : false;
		$form   = false;

		foreach ($forms as $k => $v) {
			// If the object isn't a valid object after unserializing...
			if (!($el = unserialize($v))) {
				\Core\Session::UnsetKey('FormData/' . $k);
				continue;
			}

			// Check the expires time
			if ($el->get('expires') <= Time::GetCurrent()) {
				\Core\Session::UnsetKey('FormData/' . $k);
				continue;
			}

			if ($k == $formid) {
				// Remember this for after all the checks have finished.
				$form = $el;
			}
		}

		// No form found... simple enough
		if (!$form) return;

		// Otherwise
		/** @var $form Form */

		// Ensure the submission types match up.
		if (strtoupper($form->get('method')) != $_SERVER['REQUEST_METHOD']) {
			\Core\set_message('t:MESSAGE_ERROR_FORM_SUBMISSION_TYPE_DOES_NOT_MATCH');
			return;
		}

		// Ensure the REFERRER and original URL match up.
		if($_SERVER['HTTP_REFERER'] != $form->originalurl){
			// @todo This is reported to be causing issues with production sites.
			//       If found true, this check may need to be removed / refactored.
			//\Core\set_message('Form submission referrer does not match, please try your submission again.', 'error');
			SystemLogModel::LogInfoEvent(
				'Form Referrer Mismatch',
				'Form referrer does not match!  Submitted: [' . $_SERVER['HTTP_REFERER'] . '] Expected: [' . $form->originalurl . ']'
			);
			//return;
		}

		// Run though each element submitted and try to validate it.
		if (strtoupper($form->get('method')) == 'POST') $src =& $_POST;
		else $src =& $_GET;

		$form->loadFrom($src);

		// Try to load the form from that form.  That will call all of the model's validation logic
		// and will throw exceptions if it doesn't.
		try{
			$form->getModel();

			// Still good?
			if (!$form->hasError()){
				$status = call_user_func($form->get('callsmethod'), $form);
			}
			else{
				$status = false;
			}
		}
		catch(ModelValidationException $e){
			\Core\set_message($e->getMessage(), 'error');
			$status = false;
		}
		catch(GeneralValidationException $e){
			\Core\set_message($e->getMessage(), 'error');
			$status = false;
		}
		catch(Exception $e){
			if(DEVELOPMENT_MODE){
				// Developers get the full message
				\Core\set_message($e->getMessage(), 'error');
			}
			else{
				// While users of production-enabled sites get a friendlier message.
				\Core\set_message('t:MESSAGE_ERROR_FORM_SUBMISSION_UNHANDLED_EXCEPTION');
			}
			Core\ErrorManagement\exception_handler($e);
			$status = false;
		}

		// The form was submitted.  Set its persistent flag to true so that whatever may be listening for it can retrieve the user's values.
		$form->persistent = true;

		// Regardless, bundle this form back into the session so the controller can use it if needed.
		\Core\Session::Set('FormData/' . $formid, serialize($form));

		// Fail statuses.
		if ($status === false) return;
		if ($status === null) return;

		// Guess it's not false and not null... must be good then.

		// @todo Handle an internal save procedure for "special" groups such as pageinsertables and what not.

		// Cleanup
		\Core\Session::UnsetKey('FormData/' . $formid);


		if ($status === 'die'){
			// If it's set to die, simply exit the script without outputting anything.
			exit;
		}
		elseif($status === 'back'){
			if($form->referrer && $form->referrer != REL_REQUEST_PATH){
				// Go back to the original form's referrer.
				\Core\redirect($form->referrer);
			}
			else{
				// Use Core to guess which page to redirect back to, (not as reliable).
				\Core\go_back();
			}
		}
		elseif ($status === true){
			// If the return code is boolean true, it's a reload.
			\Core\reload();
		}
		elseif($status === REL_REQUEST_PATH || $status === CUR_CALL){
			// If the page returned the same page as the current url, force a reload, (as redirect will ignore it)
			\Core\reload();
		}
		else{
			// Anything else gets sent to the redirect system.
			\core\redirect($status);
		}
	}
	/**
	 * Execute the controller and method this page request points to.
	 */
	public function execute() {

		\Core\Utilities\Profiler\Profiler::GetDefaultProfiler()->record('Starting PageRequest->execute()');

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

			$cached = \Core\Cache::Get($key, $expires);
			if($cached && $cached instanceof View){
				$this->_pageview = $cached;
				$this->_cached = true;
				return;
			}
		}

		// Anything that needs to fire off *before* the page is rendered.
		// This includes widgets, script addons, and anything else that needs a CurrentPage.
		HookHandler::DispatchHook('/core/page/preexecute');

		// Load the underlying controller.
		$pagedat   = $this->splitParts();

		/** @var View $view The valid view object for this page */
		$view = $this->getView();

		// The controller must exist first!
		// (note, the SplitParts logic already takes care of the "Is this a valid controller" logic)
		if (!(isset($pagedat['controller']) && $pagedat['controller'])) {
			$view->error = View::ERROR_NOTFOUND;
			return;
		}

		$component = Core::GetComponentByController($pagedat['controller']);

		//////////////////////////////////////////////////////////////////////////////
		///  In this block of logic, either the page is executed and a view returned,
		///  or a view is generated with an error.
		//////////////////////////////////////////////////////////////////////////////
		if (!$component) {
			// Not found
			$view->error = View::ERROR_NOTFOUND;
			return;
		}
		elseif(!is_a($component, 'Component_2_1')) {
			$view->error = View::ERROR_NOTFOUND;
			return;
		}

		// Any method that starts with a "_" is an internal-only method!
		if ($pagedat['method']{0} == '_') {
			$view->error = View::ERROR_NOTFOUND;
			return;
		}

		// It also must be a part of the class... obviously
		if (!method_exists($pagedat['controller'], $pagedat['method'])) {
			$view->error = View::ERROR_NOTFOUND;
			return;
		}


		/** @var $controller Controller_2_1 This will be a Controller object. */
		$controller = Controller_2_1::Factory($pagedat['controller']);

		$view->baseurl = $this->getBaseURL();
		$controller->setView($view);

		// Make sure that the controller can access this object.
		$controller->setPageRequest($this);

		// The main page object.
		$page = $this->getPageModel();

		// Check the access string first, (if there is one)
		if ($controller->accessstring !== null) {
			// Update the page's access string, (just in case it's saved at the end of execution)
			$page->set('access', $controller->accessstring);

			// And if the user doesn't have access to it...
			if (!\Core\user()->checkAccess($controller->accessstring)) {
				$view->error = View::ERROR_ACCESSDENIED;
				return;
			}
		}

		if($page->get('password_protected')) {
			if(\Core\Session::Get('page-password-protected/' . $page->get('baseurl')) !== $page->get('password_protected')){
				$view->templatename = '/pages/page/passwordprotected.tpl';

				$form = new Form();

				$form->set('callsmethod', 'PageRequest::PasswordProtectHandler');
				$form->addElement(
					'system', [
						'name'  => 'page',
						'value' => $page
					]
				);

				$form->addElement(
					'password', [
						'name'      => 'passinput',
						'title'     => 'Password',
						'required'  => 'required',
						'maxlength' => 128
					]
				);
				$form->addElement(
					'submit', [
						'value' => 'Submit'
					]
				);

				$view->assign('form', $form);

				return;
			}
		}

		// If the parent Controller object has a method named $pagedat['method'], assume it's a security error!
		// This is because if the parent Controller object has a method, it's most likely a utility method
		// that shouldn't be called from the public web!
		foreach(get_class_methods('Controller_2_1') as $parentmethod){
			$parentmethod = strtolower($parentmethod);
			if($parentmethod == $pagedat['method']){
				$view->error = View::ERROR_BADREQUEST;
				return;
			}
		}

		// Additional security logic for existing pages in multi-site mode.
		// If this exact URL is registered to another site, then
		// don't allow this site to display it.
		if(!$page->exists() && Core::IsComponentAvailable('multisite') && MultiSiteHelper::IsEnabled()){
			$site = MultiSiteHelper::GetCurrentSiteID();

			$anypage = PageModel::Find(['baseurl = ' . $page->get('baseurl')], 1);

			if($anypage){

				if($anypage->get('site') == -1){
					// If this is a global page.... that's ok.
					// Just remap the page variable to this one!
					$page = $anypage;
				}
				elseif($anypage->get('site') == $site){
					// Strange... it should have located this page...
					// Anyway, it's allowed, the site matches up.
					$page = $anypage;
				}
				else{
					\Core\redirect($anypage->getResolvedURL());
				}
			}
		}

		$return = call_user_func(array($controller, $pagedat['method']));
		if (is_int($return)) {
			// A generic error code was returned.  Create a View with that code and return that instead.
			$view->error = $return;
			//return;
		}
		elseif(is_a($return, 'View') && $return != $view){
			// The controller method changed the view, (which is allowed),
			// but this needs to be remapped to this object so render knows about it.
			$this->_pageview = $view = $return;
		}
		elseif ($return === null) {
			// Hopefully it's setup!
			$return = $controller->getView();
			if($return != $view){
				$this->_pageview = $view = $return;
			}
		}
		elseif(!is_a($return, 'View')){
			if(DEVELOPMENT_MODE){
				var_dump('Controller method returned', $return);
				die('Sorry, but this controller did not return a valid object.  Please ensure that your method returns either an integer, null, or a View object!');
			}
			else{
				$view->error = View::ERROR_SERVERERROR;
				return;
			}
		}
		// No else needed, else it's a valid object.


		// You may be asking why $view is one object, but $return is the return from page execution.
		// GREAT QUESTION, The $view is the original view object created from the page request.  That is passed into
		// the controller and exposed via $this->getView().  The return can be a view, int, or other status indicator.
		// However since the controller can return a different view, that view should be used instead!
		///** @var $return View */


		// Allow the controller to assign controls via a shortcut function.
		if($view->error == View::ERROR_NOERROR){
			$controls = $controller->getControls();

			// This method may do absolutely nothing, add the controls to the view itself, or return an array of them.
			if(is_array($controls)){
				foreach($controls as $control){
					$view->addControl($control);
				}
			}
		}


		// For some of the options, there may be some that can be used for a fuzzy page, ie: a page's non-fuzzy template,
		// title, or meta information.
		if($view->error == View::ERROR_NOERROR){
			if ($page->exists()) {
				$defaultpage = $page;
			} else {
				$defaultpage = null;
				$url         = $view->baseurl;
				while ($url != '') {
					$url = substr($url, 0, strrpos($url, '/'));
					$p   = PageModel::Find(array('baseurl' => $url, 'fuzzy' => 1), 1);
					if ($p === null) continue;
					if ($p->exists()) {
						$defaultpage = $p;
						break;
					}
				}
				if ($defaultpage === null) {
					// Fine....
					$defaultpage = $page;
				}
			}

			$defaultmetas = $defaultpage->getLink('PageMeta');

			// Make a list of the existing ones so I know which ones not to overwrite!
			// Just the key will suffice quite nicely.
			$currentmetas = array();
			foreach($view->meta as $k => $meta){
				$currentmetas[] = $k;
			}

			// Load some of the page information into the view now!
			foreach($defaultmetas as $meta){
				/** @var $meta PageMetaModel */
				$key = $meta->get('meta_key');

				$viewmeta = $meta->getViewMetaObject();

				// again, allow the executed controller have the final say on meta information.
				if ($meta->get('meta_value_title') && !in_array($key, $currentmetas)) {
					$view->meta[$key] = $viewmeta;
				}
			}


			// Since the controller already ran, do not overwrite the title.
			if ($view->title === null){
				$view->title = $defaultpage->get('title');
			}

			// Tracker to see if this page, (or a parent's page), is an admin-level page.
			// This is required because "admin" pages may have a different skin and should always have the dashboard as the top-level breadcrumb.
			/** @var boolean $isadmin */
			$isadmin = ($page->get('admin') == '1');

			$parents = array();
			$parenttree = $page->getParentTree();
			foreach ($parenttree as $parent) {
				/** @var PageModel $parent */
				$parents[] = array(
					'title' => $parent->get('title'),
					'link'  => $parent->getResolvedURL()
				);

				// Since I'm here, check if this page is an admin page.
				if($parent->get('admin')){
					$isadmin = true;
				}
			}
			$view->breadcrumbs = array_merge($parents, $view->breadcrumbs);

			if($isadmin && $view->baseurl != '/admin'){
				// Make sure that admin is the top breadcrumb.
				// This block doesn't need to apply for the actual admin page itself, as that doesn't need its own breadcrumb :/
				$adminlink = \Core\resolve_link('/admin');
				if(!isset($view->breadcrumbs[0])){
					// Nothing is even set!
					$view->breadcrumbs[] = ['title' => 'Administration', 'link' => $adminlink];
				}
				elseif($view->breadcrumbs[0]['link'] != $adminlink){
					// It's set, but not to admin.
					$view->breadcrumbs = array_merge([['title' => 'Administration', 'link' => $adminlink]], $view->breadcrumbs);
				}
			}
		}
		else{
			$defaultpage = null;
			$isadmin = false;
		}


		if(
			$view->mode == View::MODE_PAGEORAJAX &&
			$this->isAjax() &&
			$view->jsondata !== null &&
			$view->templatename === null
		){
			// Allow the content type to be overridden for ajax pages that have JSON data embedded in them.
			$view->contenttype = View::CTYPE_JSON;
		}


		if($view->mode == View::MODE_NOOUTPUT){
			$view->mastertemplate = false;
			$view->templatename = null;
		}
		elseif(
			$view->error == View::ERROR_NOERROR &&
			$view->contenttype == View::CTYPE_HTML &&
			$view->templatename === null
		){
			// Try to guess the templatename if it wasn't set.
			// This
			$cnameshort           = (strpos($pagedat['controller'], 'Controller') == strlen($pagedat['controller']) - 10) ? substr($pagedat['controller'], 0, -10) : $pagedat['controller'];
			$view->templatename = strtolower('/pages/' . $cnameshort . '/' . $pagedat['method'] . '.tpl');
		}
		elseif(
			$view->error == View::ERROR_NOERROR &&
			$view->contenttype == View::CTYPE_XML &&
			$view->templatename === null
		){
			$cnameshort           = (strpos($pagedat['controller'], 'Controller') == strlen($pagedat['controller']) - 10) ? substr($pagedat['controller'], 0, -10) : $pagedat['controller'];
			$view->templatename = Template::ResolveFile(strtolower('pages/' . $cnameshort . '/' . $pagedat['method'] . '.xml.tpl'));
		}

		// In addition to the autogeneration, also support the page_template from the datastore.
		if($defaultpage && $defaultpage->get('page_template')){
			// Switch the template over to that custom one.
			// Some legacy data will have the fully resolved path for this template.
			// This has been switched to just the basename of the custom template,
			// but legacy data be legacy, 'yo.                            0.o

			$base     = substr($view->templatename, 0, -4);
			$override = $defaultpage->get('page_template');
			if($base && strpos($override, $base) === 0){
				$view->templatename = $override;
			}
			elseif($base){
				$view->templatename = $base . '/' . $override;
			}
		}

		// Guess which theme skin (mastertemplate) should be used if one wasn't specified.
		if($view->mastertemplate == 'admin'){
			// If the master template is set explictly to be the admin skin, then transpose that to the set admin skin.
			// This is useful for the pages that may not be under the "/admin" umbrella, but still rendered with the admin UI.
			$view->mastertemplate = ConfigHandler::Get('/theme/default_admin_template');
		}
		elseif($view->mastertemplate){
			// No change needed, just skip the below cases.
		}
		elseif($view->mastertemplate === false){
			// If the master template is explictly set to false, the page wanted no master template!
		}
		elseif($isadmin){
			// This page doesn't have a master template set, but it or a parent is set as an admin-level page.
			$view->mastertemplate = ConfigHandler::Get('/theme/default_admin_template');
		}
		elseif ($defaultpage && $defaultpage->get('theme_template')) {
			// Master template set in the database?
			$view->mastertemplate = $defaultpage->get('theme_template');
		}
		elseif($defaultpage && $defaultpage->exists() && $defaultpage->get('admin')){
			// Or an admin level page?
			$view->mastertemplate = ConfigHandler::Get('/theme/default_admin_template');
		}
		elseif(sizeof($view->breadcrumbs) && $view->breadcrumbs[0]['title'] == 'Administration'){
			// Whatever, close e-damn-nough!
			// This happens for pages that don't actually exist, like "edit"....
			$view->mastertemplate = ConfigHandler::Get('/theme/default_admin_template');
		}
		else{
			$view->mastertemplate = ConfigHandler::Get('/theme/default_template');
		}

		// First of all, if the current theme is not available, reset back to the first theme available!
		if(!($theme = ThemeHandler::GetTheme())){
			/** @var \Theme\Theme $theme */
			$theme = ThemeHandler::GetTheme('base-v2');
			$view->mastertemplate = 'basic.tpl';
			\Core\set_message('t:MESSAGE_ERROR_INVALID_THEME_SELECTED');
		}

		// Make sure the selected mastertemplate actually exists!
		if($view->mastertemplate !== false){
			$themeskins = $theme->getSkins();
			$mastertplgood = false;
			foreach($themeskins as $skin){
				if($skin['file'] == $view->mastertemplate){
					// It's located!
					$mastertplgood =true;
					break;
				}
			}

			// A few special cases.
			if($view->mastertemplate == 'blank.tpl'){
				// This is acceptable as a default one.
				$mastertplgood =true;
			}

			if(!$mastertplgood){
				// Just use the first one instead!
				trigger_error('Invalid skin [' . $view->mastertemplate . '] selected for this page, skin is not located within the selected theme!  Using first available instead.', E_USER_NOTICE);
				$view->mastertemplate = $themeskins[0]['file'];
			}
		}

		// Handle some of the new automatic meta data associated with Pages and the resulting View.

		if(\ConfigHandler::Get('/core/page/indexable') == 'deny'){
			// Administratively set to noindex on all pages.
			$view->addMetaName('robots', 'noindex');
		}
		elseif(!$page->get('indexable')){
			// Bots have no business indexing user-action pages.
			$view->addMetaName('robots', 'noindex');
		}
		if(!isset($view->meta['title'])){
			$view->meta['title'] = $page->getSEOTitle();
		}

		HookHandler::DispatchHook('/core/page/postexecute');

		\Core\Utilities\Profiler\Profiler::GetDefaultProfiler()->record('Completed PageRequest->execute()');
	}
Example #13
0
 /**
  * {@inheritdoc}
  *
  * @see BaseFacebook::getPersistentData()
  */
 protected function getPersistentData($key, $default = false)
 {
     if (!in_array($key, self::$kSupportedKeys)) {
         self::errorLog('Unsupported key passed to getPersistentData.');
         return $default;
     }
     $session_var_name = $this->constructSessionVariableName($key);
     return \Core\Session::Get($session_var_name) !== null ? \Core\Session::Get($session_var_name) : $default;
 }
Example #14
0
	/**
	 * Internal function to parse and handle the configs in the component.xml file.
	 * This is used for installations and upgrades.
	 *
	 * Returns false if nothing changed, else will return an int of the number of configuration options changed.
	 *
	 * @param boolean $install   Set to false to force uninstall/disable mode.
	 * @param int     $verbosity (default 0) 0: standard output, 1: real-time, 2: real-time verbose output.
	 *
	 * @return boolean | int
	 * @throws InstallerException
	 */
	public function _parseConfigs($install = true, $verbosity = 0) {
		// Keep track of if this changed anything.
		$changes = array();

		$action = $install ? 'Installing' : 'Uninstalling';
		$set    = $install ? 'Set' : 'Removed';

		Core\Utilities\Logger\write_debug($action . ' configs for ' . $this->getName());

		// I need to get the schema definitions first.
		$node = $this->_xmlloader->getElement('configs');
		//$prefix = $node->getAttribute('prefix');
		$componentName = $this->getKeyName();

		// Now, get every table under this node.
		foreach ($node->getElementsByTagName('config') as $confignode) {
			/** @var DOMElement $confignode */
			$key         = $confignode->getAttribute('key');
			$options     = $confignode->getAttribute('options');
			$type        = $confignode->getAttribute('type');
			$default     = $confignode->getAttribute('default');
			$title       = $confignode->getAttribute('title');
			$description = $confignode->getAttribute('description');
			$mapto       = $confignode->getAttribute('mapto');
			$encrypted   = $confignode->getAttribute('encrypted');
			$formAtts    = $confignode->getAttribute('form-attributes');

			if($encrypted === null || $encrypted === '') $encrypted = '0';

			// Default if omitted.
			if(!$type) $type = 'string';

			if($verbosity == 2){
				CLI::PrintActionStart($action . ' config ' . $key);
			}

			$m   = ConfigHandler::GetConfig($key);
			if($install){
				// Installation/Upgrade Logic
				$m->set('options', $options);
				$m->set('type', $type);
				$m->set('default_value', $default);
				$m->set('title', $title);
				$m->set('description', $description);
				$m->set('mapto', $mapto);
				$m->set('encrypted', $encrypted);
				$m->set('form_attributes', $formAtts);
				$m->set('component', $componentName);

				// Default from the xml, only if it's not already set.
				if ($m->get('value') === null || !$m->exists()){
					$m->set('value', $confignode->getAttribute('default'));
				}
				// Allow configurations to overwrite any value.  This is useful on the initial installation.
				if(\Core\Session::Get('configs/' . $key) !== null){
					$m->set('value', \Core\Session::Get('configs/' . $key));
				}

				if ($m->save()){
					$changes[] = $set . ' configuration [' . $m->get('key') . '] to [' . $m->get('value') . ']';
					if($verbosity == 2){
						CLI::PrintActionStatus(true);
					}
				}
				else{
					if($verbosity == 2){
						CLI::PrintActionStatus('skip');
					}
				}

				// Make it available immediately
				ConfigHandler::CacheConfig($m);
			}
			else{
				// Uninstallation Logic
				$m->delete();

				$changes[] = $set . ' configuration [' . $key . ']';
				if($verbosity == 2){
					CLI::PrintActionStatus(true);
				}
			}
		}

		return (sizeof($changes)) ? $changes : false;

	} // private function _parseConfigs
	/**
	 * Get the value for a given configuration key
	 *
	 * @param string $key
	 * @return mixed
	 */
	private function _get($key){

		// If it's a standard config, pull the value from config.
		if(isset($this->_cacheFromDB[$key])){
			// Is it already overridden?
			if(isset($this->_overrides[$key])){
				return ConfigModel::TranslateValue($this->_cacheFromDB[$key]->get('type'), $this->_overrides[$key]);
			}
			else{
				return $this->_cacheFromDB[$key]->getValue();
			}
		}
		// Not there either?  Allow the SESSION to contain config variables.  This is critical for installation.
		elseif(\Core\Session::Get('configs/' . $key) !== null){
			return \Core\Session::Get('configs/' . $key);
		}
		// Else, just return null.
		else{
			return null;
		}
	}
Example #16
0
	/**
	 * Get the current system DMI based on configuration values.
	 *
	 * @throws DMI_Exception
	 * @throws DMI_Authentication_Exception
	 *
	 * @return DMI
	 */
	public static function GetSystemDMI(){
		if(self::$_Interface !== null) return self::$_Interface;
		
		self::$_Interface = new DMI();
		

		if(file_exists(ROOT_PDIR . 'config/configuration.xml')){
			// Because this is the system data connection, I also need to pull the settings automatically.
			// This will only be done if the configuration file exists.
			$cs = ConfigHandler::LoadConfigFile("configuration");
		}
		elseif(\Core\Session::Get('configs/*') !== null){
			// If the file doesn't exist, (ie: during installation), I need to check the session data.
			$cs = \Core\Session::Get('configs/*');
		}
		else{
			throw new DMI_Exception('No database settings defined for the DMI');
		}

		self::$_Interface->setBackend($cs['database_type']);
		
		self::$_Interface->connect($cs['database_server'], $cs['database_user'], $cs['database_pass'], $cs['database_name']);
		
		return self::$_Interface;
	}
Example #17
0
	private function _import3(){
		$view = $this->getView();
		$request = $this->getPageRequest();

		$view->templatename = 'pages/user/import3.tpl';
		$view->assign('count', \Core\Session::Get('user-import/counts', 0));
		$view->assign('fails', \Core\Session::Get('user-import/fails', 0)); // @todo Implement this

		\Core\Session::UnsetKey('user-import/*');
	}
Example #18
0
/**
 * Add a message to the user's stack.
 *	It will be displayed the next time the user (or session) renders the page.
 *
 * @param string $message_text The message text or the MESSAGE_ string constant for i18n and automatic type detection!
 * @param string $message_type
 *
 * @return boolean (on success)
 */
function set_message($messageText, $messageType = 'info'){
	if(strpos($messageText, 't:MESSAGE_') === 0){
		// It's an i18n message!  Retrieve the locale version of text and the message type.
		$messageText = substr($messageText, 2);

		if(strpos($messageText, 'MESSAGE_SUCCESS_') === 0){
			$messageType = 'success';
		}
		elseif(strpos($messageText, 'MESSAGE_ERROR_') === 0){
			$messageType = 'error';
		}
		elseif(strpos($messageText, 'MESSAGE_TUTORIAL_') === 0){
			$messageType = 'tutorial';
		}
		elseif(strpos($messageText, 'MESSAGE_WARNING_') === 0){
			$messageType = 'warning';
		}
		elseif(strpos($messageText, 'MESSAGE_INFO_') === 0){
			$messageType = 'info';
		}
		else{
			$messageType = 'info';
		}

		if(func_num_args() > 1){
			// Use func_call to call 1, as I need to pass in the other options too!
			$messageText = call_user_func_array('t', func_get_args());
		}
		else{
			$messageText = t($messageText);
		}
	}

	// CLI doesn't use sessions, echo directly to stdout instead.
	if(EXEC_MODE == 'CLI'){
		$messageText = preg_replace('/<br[^>]*>/i', "\n", $messageText);
		echo "[" . $messageType . "] - " . $messageText . "\n";
	}
	else{
		$stack = Session::Get('message_stack', []);

		$stack[] = array(
			'mtext' => $messageText,
			'mtype' => $messageType,
		);
		Session::Set('message_stack', $stack);
	}
}
	/**
	 * Get all the recorded events of this profiler as an array.
	 *
	 * @return array
	 */
	public function getEvents(){
		return Session::Get('datamodel_profiler_events/events', []);
	}