/** * 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; }
/** * 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); }
/** * 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); } }
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/*'); }
/** * Get the current user model that is logged in. * * To support legacy systems, this will also return the User object if it's available instead. * This support is for < 2.8.x Core installations and will be removed after some amount of time TBD. * * If no user systems are currently available, null is returned. * * @return \UserModel */ function user(){ static $_CurrentUserAccount = null; if(!class_exists('\\UserModel')){ return null; } if($_CurrentUserAccount !== null){ // Cache this for the page load. return $_CurrentUserAccount; } if(isset($_SERVER['HTTP_X_CORE_AUTH_KEY'])){ // Allow an auth key to be used to authentication the requested user instead! $user = \UserModel::Find(['apikey = ' . $_SERVER['HTTP_X_CORE_AUTH_KEY']], 1); if($user){ $_CurrentUserAccount = $user; } } elseif(Session::Get('user') instanceof \UserModel){ // There is a valid user account in the session! // But check if this user is forced to be resynced first. if(isset(Session::$Externals['user_forcesync'])){ // A force sync was requested by something that modified the original UserModel object. // Keep the user logged in, but reload the data from the database. $_CurrentUserAccount = \UserModel::Construct(Session::Get('user')->get('id')); // And cache this updated user model back to the session. Session::Set('user', $_CurrentUserAccount); unset(Session::$Externals['user_forcesync']); } else{ $_CurrentUserAccount = Session::Get('user'); } } if($_CurrentUserAccount === null){ // No valid user found. $_CurrentUserAccount = new \UserModel(); } // If this is in multisite mode, blank out the access string cache too! // This is because siteA may have some groups, while siteB may have another. // We don't want a user going to a site they have full access to, hopping to another and having cached permissions! if(\Core::IsComponentAvailable('multisite') && class_exists('MultiSiteHelper') && \MultiSiteHelper::IsEnabled()){ $_CurrentUserAccount->clearAccessStringCache(); } // Did this user request sudo access for another user? if(Session::Get('user_sudo') !== null){ $sudo = Session::Get('user_sudo'); if($sudo instanceof \UserModel){ // It's a valid user! if($_CurrentUserAccount->checkAccess('p:/user/users/sudo')){ // This user can SUDO! // (only if the other user is < SA or current == SA). if($sudo->checkAccess('g:admin') && !$_CurrentUserAccount->checkAccess('g:admin')){ Session::UnsetKey('user_sudo'); \SystemLogModel::LogSecurityEvent('/user/sudo', 'Authorized but non-SA user requested sudo access to a system admin!', null, $sudo->get('id')); } else{ // Ok, everything is good. // Remap the current user over to this sudo'd account! $_CurrentUserAccount = $sudo; } } else{ // This user can NOT sudo!!! Session::UnsetKey('user_sudo'); \SystemLogModel::LogSecurityEvent('/user/sudo', 'Unauthorized user requested sudo access to another user!', null, $sudo->get('id')); } } else{ Session::UnsetKey('user_sudo'); } } return $_CurrentUserAccount; }
/** * Get the breakdown of recorded events and their time into the profiler operation. * * @return string */ public function getEventTimesFormatted(){ $out = ''; $ql = $this->getEvents(); $qls = sizeof($this->_events); foreach($ql as $i => $dat){ if($i > 1000){ $out .= 'Plus ' . ($qls - 1000) . ' more!' . "\n"; break; } $typecolor = ($dat['type'] == 'read') ? '#88F' : '#005'; $tpad = ($dat['type'] == 'read') ? ' ' : ' '; $type = $dat['type']; $time = str_pad(\Core\time_duration_format($dat['time'], 2), 9, '0', STR_PAD_LEFT); $query = $dat['query']; $caller = print_r($dat['caller'], true); if($dat['rows'] !== null){ $caller .= "\n" . 'Number of affected rows: ' . $dat['rows']; } $out .= sprintf( "<span title='%s'><span style='color:%s;'>[%s]</span>%s[%s] <code class='sql'>%s</code></span>\n", $caller, $typecolor, $type, $tpad, $time, htmlentities($query, ENT_QUOTES | ENT_HTML5) ); } // Purge the output. Session::UnsetKey('datamodel_profiler_events/*'); return $out; }