/** * Get is current user crawler * * @param string $agent if set, use this value instead HTTP_USER_AGENT * @return bool */ function isCrawler($agent = NULL) { return Rhymix\Framework\UA::isRobot($agent); }
public function procFileOutput() { // Get requsted file info $oFileModel = getModel('file'); $file_srl = Context::get('file_srl'); $file_key = Context::get('file_key'); $columnList = array('source_filename', 'uploaded_filename', 'file_size'); $file_obj = $oFileModel->getFile($file_srl, $columnList); $filesize = $file_obj->file_size; $filename = $file_obj->source_filename; $etag = md5($file_srl . $file_key . $_SERVER['HTTP_USER_AGENT']); // Check file key if (strlen($file_key) != 32 || !isset($_SESSION['__XE_FILE_KEY__']) || !is_string($_SESSION['__XE_FILE_KEY__'])) { return $this->stop('msg_invalid_request'); } $file_key_data = $file_srl . $file_obj->file_size . $file_obj->uploaded_filename . $_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT']; $file_key_compare = substr(hash_hmac('sha256', $file_key_data, $_SESSION['__XE_FILE_KEY__']), 0, 32); if ($file_key !== $file_key_compare) { return $this->stop('msg_invalid_request'); } // Check if file exists $uploaded_filename = $file_obj->uploaded_filename; if (!file_exists($uploaded_filename)) { return $this->stop('msg_file_not_found'); } // If client sent an If-None-Match header with the correct ETag, do not download again if (isset($_SERVER['HTTP_IF_NONE_MATCH']) && trim(trim($_SERVER['HTTP_IF_NONE_MATCH']), '\'"') === $etag) { header('HTTP/1.1 304 Not Modified'); exit; } // If client sent an If-Modified-Since header with a recent modification date, do not download again if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) > filemtime($uploaded_filename)) { header('HTTP/1.1 304 Not Modified'); exit; } // Encode the filename. $filename_param = Rhymix\Framework\UA::encodeFilenameForDownload($filename); // Close context to prevent blocking the session Context::close(); // Open file $fp = fopen($uploaded_filename, 'rb'); if (!$fp) { return $this->stop('msg_file_not_found'); } // Take care of pause and resume if (isset($_SERVER['HTTP_RANGE']) && preg_match('/^bytes=(\\d+)-(\\d+)?/', $_SERVER['HTTP_RANGE'], $matches)) { $range_start = $matches[1]; $range_end = $matches[2] ? $matches[2] : $filesize - 1; $range_length = $range_end - $range_start + 1; if ($range_length < 1 || $range_start < 0 || $range_start >= $filesize || $range_end >= $filesize) { header('HTTP/1.1 416 Requested Range Not Satisfiable'); fclose($fp); exit; } fseek($fp, $range_start); header('HTTP/1.1 206 Partial Content'); header('Content-Range: bytes ' . $range_start . '-' . $range_end . '/' . $filesize); } else { $range_start = 0; $range_length = $filesize - $range_start; } // Clear buffer while (ob_get_level()) { ob_end_clean(); } // Set headers header("Cache-Control: private; max-age=3600"); header("Pragma: "); header("Content-Type: application/octet-stream"); header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); header('Content-Disposition: attachment; ' . $filename_param); header('Content-Transfer-Encoding: binary'); header('Content-Length: ' . $range_length); header('Accept-Ranges: bytes'); header('Etag: "' . $etag . '"'); // Print the file contents for ($offset = 0; $offset < $range_length; $offset += 4096) { $buffer_size = min(4096, $range_length - $offset); echo fread($fp, $buffer_size); flush(); } exit; }
/** * Check if user-agent is a tablet PC as iPad or Andoid tablet. * * @return bool TRUE for tablet, and FALSE for else. */ public static function isMobilePadCheckByAgent() { return Rhymix\Framework\UA::isTablet(); }
/** * Single Sign On (SSO) * * @return bool True : Module handling is necessary in the control path of current request , False : Otherwise */ public function checkSSO() { // pass if it's not GET request or XE is not yet installed if (!config('use_sso') || Rhymix\Framework\UA::isRobot()) { return TRUE; } $checkActList = array('rss' => 1, 'atom' => 1); if (self::getRequestMethod() != 'GET' || !self::isInstalled() || isset($checkActList[self::get('act')])) { return TRUE; } // pass if default URL is not set $default_url = trim($this->db_info->default_url); if (!$default_url) { return TRUE; } if (substr_compare($default_url, '/', -1) !== 0) { $default_url .= '/'; } // Get current site information (only the base URL, not the full URL) $current_site = self::getRequestUri(); // Step 1: if the current site is not the default site, send SSO validation request to the default site if ($default_url !== $current_site && !self::get('sso_response') && $_COOKIE['sso'] !== md5($current_site)) { // Set sso cookie to prevent multiple simultaneous SSO validation requests setcookie('sso', md5($current_site), 0, '/'); // Redirect to the default site $sso_request = Rhymix\Framework\Security::encrypt(Rhymix\Framework\URL::getCurrentURL()); $redirect_url = $default_url . '?sso_request=' . urlencode($sso_request); header('Location:' . $redirect_url); return false; } // Step 2: receive and process SSO validation request at the default site if ($default_url === $current_site && self::get('sso_request')) { // Get the URL of the origin site $sso_request = Rhymix\Framework\Security::decrypt(self::get('sso_request')); if (!$sso_request || !preg_match('!^https?://!', $sso_request)) { self::displayErrorPage('SSO Error', 'Invalid SSO Request', 400); return false; } // Check that the origin site is a valid site in this XE installation (to prevent open redirect vuln) if (!getModel('module')->getSiteInfoByDomain(rtrim($url, '/'))->site_srl) { self::displayErrorPage('SSO Error', 'Invalid SSO Request', 400); return false; } // Redirect back to the origin site $sso_response = Rhymix\Framework\Security::encrypt(session_id()); header('Location: ' . Rhymix\Framework\URL::modifyURL($sso_request, array('sso_response' => $sso_response))); return false; } // Step 3: back at the origin site, set session ID to be the same as the default site if ($default_url !== $current_site && self::get('sso_response')) { // Check SSO response $sso_response = Rhymix\Framework\Security::decrypt(self::get('sso_response')); if ($sso_response === false) { self::displayErrorPage('SSO Error', 'Invalid SSO Response', 400); return false; } // Check that the response was given by the default site (to prevent session fixation CSRF) if (isset($_SERVER['HTTP_REFERER']) && strpos($_SERVER['HTTP_REFERER'], $default_url) !== 0) { self::displayErrorPage('SSO Error', 'Invalid SSO Response', 400); return false; } // Set session ID setcookie(session_name(), $sso_response); // Finally, redirect to the originally requested URL header('Location: ' . Rhymix\Framework\URL::getCurrentURL(array('sso_response' => null))); return false; } // If none of the conditions above apply, proceed normally return TRUE; }
/** * get a module instance and execute an action * @return ModuleObject executed module instance * */ public function procModule() { $oModuleModel = getModel('module'); $display_mode = Mobile::isFromMobilePhone() ? 'mobile' : 'view'; // If error occurred while preparation, return a message instance if ($this->error) { self::_setInputErrorToContext(); $oMessageObject = self::getModuleInstance('message', $display_mode); $oMessageObject->setError(-1); $oMessageObject->setMessage($this->error); $oMessageObject->dispMessage(); if ($this->httpStatusCode) { $oMessageObject->setHttpStatusCode($this->httpStatusCode); } return $oMessageObject; } // Get action information with conf/module.xml $xml_info = $oModuleModel->getModuleActionXml($this->module); // If not installed yet, modify act if ($this->module == "install") { if (!$this->act || !$xml_info->action->{$this->act}) { $this->act = $xml_info->default_index_act; } } // if act exists, find type of the action, if not use default index act if (!$this->act) { $this->act = $xml_info->default_index_act; } // still no act means error if (!$this->act) { $this->error = 'msg_module_is_not_exists'; $this->httpStatusCode = '404'; self::_setInputErrorToContext(); $oMessageObject = self::getModuleInstance('message', $display_mode); $oMessageObject->setError(-1); $oMessageObject->setMessage($this->error); $oMessageObject->dispMessage(); if ($this->httpStatusCode) { $oMessageObject->setHttpStatusCode($this->httpStatusCode); } return $oMessageObject; } // get type, kind $type = $xml_info->action->{$this->act}->type; $ruleset = $xml_info->action->{$this->act}->ruleset; $kind = stripos($this->act, 'admin') !== FALSE ? 'admin' : ''; if (!$kind && $this->module == 'admin') { $kind = 'admin'; } // check REQUEST_METHOD in controller if ($type == 'controller') { $allowedMethod = $xml_info->action->{$this->act}->method; if (!$allowedMethod) { $allowedMethodList[0] = 'POST'; } else { $allowedMethodList = explode('|', strtoupper($allowedMethod)); } if (!in_array(strtoupper($_SERVER['REQUEST_METHOD']), $allowedMethodList)) { $this->error = "msg_invalid_request"; $oMessageObject = self::getModuleInstance('message', $display_mode); $oMessageObject->setError(-1); $oMessageObject->setMessage($this->error); $oMessageObject->dispMessage(); return $oMessageObject; } } // check CSRF for non-GET (POST, PUT, etc.) actions if (Context::getRequestMethod() !== 'GET' && Context::isInstalled()) { if ($xml_info->action->{$this->act} && $xml_info->action->{$this->act}->check_csrf !== 'false' && !checkCSRF()) { $this->_setInputErrorToContext(); $this->error = 'msg_invalid_request'; $oMessageObject = ModuleHandler::getModuleInstance('message', $display_mode); $oMessageObject->setError(-1); $oMessageObject->setMessage($this->error); $oMessageObject->dispMessage(); return $oMessageObject; } } if ($this->module_info->use_mobile != "Y") { Mobile::setMobile(FALSE); } $logged_info = Context::get('logged_info'); // if(type == view, and case for using mobilephone) if ($type == "view" && Mobile::isFromMobilePhone() && Context::isInstalled()) { $orig_type = "view"; $type = "mobile"; // create a module instance $oModule = self::getModuleInstance($this->module, $type, $kind); if (!is_object($oModule) || !method_exists($oModule, $this->act)) { $type = $orig_type; Mobile::setMobile(FALSE); $oModule = self::getModuleInstance($this->module, $type, $kind); } } else { // create a module instance $oModule = self::getModuleInstance($this->module, $type, $kind); } if (!is_object($oModule)) { self::_setInputErrorToContext(); $oMessageObject = self::getModuleInstance('message', $display_mode); $oMessageObject->setError(-1); $oMessageObject->setMessage($this->error); $oMessageObject->dispMessage(); if ($this->httpStatusCode) { $oMessageObject->setHttpStatusCode($this->httpStatusCode); } return $oMessageObject; } // If there is no such action in the module object if (!isset($xml_info->action->{$this->act}) || !method_exists($oModule, $this->act)) { if (!Context::isInstalled()) { self::_setInputErrorToContext(); $this->error = 'msg_invalid_request'; $oMessageObject = self::getModuleInstance('message', $display_mode); $oMessageObject->setError(-1); $oMessageObject->setMessage($this->error); $oMessageObject->dispMessage(); if ($this->httpStatusCode) { $oMessageObject->setHttpStatusCode($this->httpStatusCode); } return $oMessageObject; } $forward = NULL; // 1. Look for the module with action name if (preg_match('/^([a-z]+)([A-Z])([a-z0-9\\_]+)(.*)$/', $this->act, $matches)) { $module = strtolower($matches[2] . $matches[3]); $xml_info = $oModuleModel->getModuleActionXml($module); if ($xml_info->action->{$this->act} && (stripos($this->act, 'admin') !== FALSE || $xml_info->action->{$this->act}->standalone != 'false')) { $forward = new stdClass(); $forward->module = $module; $forward->type = $xml_info->action->{$this->act}->type; $forward->ruleset = $xml_info->action->{$this->act}->ruleset; $forward->act = $this->act; } else { $this->error = 'msg_invalid_request'; $oMessageObject = self::getModuleInstance('message', $display_mode); $oMessageObject->setError(-1); $oMessageObject->setMessage($this->error); $oMessageObject->dispMessage(); return $oMessageObject; } } if (!$forward) { $forward = $oModuleModel->getActionForward($this->act); } if ($forward->module && $forward->type && $forward->act && $forward->act == $this->act) { $kind = stripos($forward->act, 'admin') !== FALSE ? 'admin' : ''; $type = $forward->type; $ruleset = $forward->ruleset; $tpl_path = $oModule->getTemplatePath(); $orig_module = $oModule; $xml_info = $oModuleModel->getModuleActionXml($forward->module); // SECISSUE also check foward act method // check REQUEST_METHOD in controller if ($type == 'controller') { $allowedMethod = $xml_info->action->{$forward->act}->method; if (!$allowedMethod) { $allowedMethodList[0] = 'POST'; } else { $allowedMethodList = explode('|', strtoupper($allowedMethod)); } if (!in_array(strtoupper($_SERVER['REQUEST_METHOD']), $allowedMethodList)) { $this->error = "msg_invalid_request"; $oMessageObject = self::getModuleInstance('message', $display_mode); $oMessageObject->setError(-1); $oMessageObject->setMessage($this->error); $oMessageObject->dispMessage(); return $oMessageObject; } } // check CSRF for non-GET (POST, PUT, etc.) actions if (Context::getRequestMethod() !== 'GET' && Context::isInstalled()) { if ($xml_info->action->{$this->act} && $xml_info->action->{$this->act}->check_csrf !== 'false' && !checkCSRF()) { $this->_setInputErrorToContext(); $this->error = 'msg_invalid_request'; $oMessageObject = ModuleHandler::getModuleInstance('message', $display_mode); $oMessageObject->setError(-1); $oMessageObject->setMessage($this->error); $oMessageObject->dispMessage(); return $oMessageObject; } } if ($type == "view" && Mobile::isFromMobilePhone()) { $orig_type = "view"; $type = "mobile"; // create a module instance $oModule = self::getModuleInstance($forward->module, $type, $kind); if (!is_object($oModule) || !method_exists($oModule, $this->act)) { $type = $orig_type; Mobile::setMobile(FALSE); $oModule = self::getModuleInstance($forward->module, $type, $kind); } } else { $oModule = self::getModuleInstance($forward->module, $type, $kind); } if (!is_object($oModule)) { self::_setInputErrorToContext(); $oMessageObject = self::getModuleInstance('message', $display_mode); $oMessageObject->setError(-1); $oMessageObject->setMessage('msg_module_is_not_exists'); $oMessageObject->dispMessage(); if ($this->httpStatusCode) { $oMessageObject->setHttpStatusCode($this->httpStatusCode); } return $oMessageObject; } if ($this->module == "admin" && $type == "view") { if ($logged_info->is_admin == 'Y') { if ($this->act != 'dispLayoutAdminLayoutModify') { $oAdminView = getAdminView('admin'); $oAdminView->makeGnbUrl($forward->module); $oModule->setLayoutPath("./modules/admin/tpl"); $oModule->setLayoutFile("layout.html"); } } else { self::_setInputErrorToContext(); $this->error = 'admin.msg_is_not_administrator'; $oMessageObject = self::getModuleInstance('message', $display_mode); $oMessageObject->setError(-1); $oMessageObject->setMessage($this->error); $oMessageObject->dispMessage(); return $oMessageObject; } } if ($kind == 'admin') { $grant = $oModuleModel->getGrant($this->module_info, $logged_info); if (!$grant->manager) { self::_setInputErrorToContext(); $this->error = 'admin.msg_is_not_administrator'; $oMessageObject = self::getModuleInstance('message', $display_mode); $oMessageObject->setError(-1); $oMessageObject->setMessage($this->error); $oMessageObject->dispMessage(); return $oMessageObject; } else { if (!$grant->is_admin && $this->module != $this->orig_module->module && $xml_info->permission->{$this->act} != 'manager') { self::_setInputErrorToContext(); $this->error = 'admin.msg_is_not_administrator'; $oMessageObject = self::getModuleInstance('message', $display_mode); $oMessageObject->setError(-1); $oMessageObject->setMessage($this->error); $oMessageObject->dispMessage(); return $oMessageObject; } } } } else { if ($xml_info->default_index_act && method_exists($oModule, $xml_info->default_index_act)) { $this->act = $xml_info->default_index_act; } else { $this->error = 'msg_invalid_request'; $oModule->setError(-1); $oModule->setMessage($this->error); return $oModule; } } } // ruleset check... if (!empty($ruleset)) { $rulesetModule = $forward->module ? $forward->module : $this->module; $rulesetFile = $oModuleModel->getValidatorFilePath($rulesetModule, $ruleset, $this->mid); if (!empty($rulesetFile)) { if ($_SESSION['XE_VALIDATOR_ERROR_LANG']) { $errorLang = $_SESSION['XE_VALIDATOR_ERROR_LANG']; foreach ($errorLang as $key => $val) { Context::setLang($key, $val); } unset($_SESSION['XE_VALIDATOR_ERROR_LANG']); } $Validator = new Validator($rulesetFile); $result = $Validator->validate(); if (!$result) { $lastError = $Validator->getLastError(); $returnUrl = Context::get('error_return_url'); $errorMsg = $lastError['msg'] ? $lastError['msg'] : 'validation error'; //for xml response $oModule->setError(-1); $oModule->setMessage($errorMsg); //for html redirect $this->error = $errorMsg; $_SESSION['XE_VALIDATOR_ERROR'] = -1; $_SESSION['XE_VALIDATOR_MESSAGE'] = $this->error; $_SESSION['XE_VALIDATOR_MESSAGE_TYPE'] = 'error'; $_SESSION['XE_VALIDATOR_RETURN_URL'] = $returnUrl; $_SESSION['XE_VALIDATOR_ID'] = Context::get('xe_validator_id'); self::_setInputValueToSession(); return $oModule; } } } $oModule->setAct($this->act); $this->module_info->module_type = $type; $oModule->setModuleInfo($this->module_info, $xml_info); $skipAct = array('dispEditorConfigPreview' => 1, 'dispLayoutPreviewWithModule' => 1); $db_use_mobile = Mobile::isMobileEnabled(); $tablet_use = Rhymix\Framework\UA::isTablet(); $config_tablet_use = config('mobile.tablets'); if ($type == "view" && $this->module_info->use_mobile == "Y" && Mobile::isMobileCheckByAgent() && !isset($skipAct[Context::get('act')]) && $db_use_mobile === true && ($tablet_use === true && $config_tablet_use === false) === false) { global $lang; $header = '<style>div.xe_mobile{opacity:0.7;margin:1em 0;padding:.5em;background:#333;border:1px solid #666;border-left:0;border-right:0}p.xe_mobile{text-align:center;margin:1em 0}a.xe_mobile{color:#ff0;font-weight:bold;font-size:24px}@media only screen and (min-width:500px){a.xe_mobile{font-size:15px}}</style>'; $footer = '<div class="xe_mobile"><p class="xe_mobile"><a class="xe_mobile" href="' . getUrl('m', '1') . '">' . $lang->msg_pc_to_mobile . '</a></p></div>'; Context::addHtmlHeader($header); Context::addHtmlFooter($footer); } if ($type == "view" && $kind != 'admin') { $module_config = $oModuleModel->getModuleConfig('module'); if ($module_config->htmlFooter) { Context::addHtmlFooter($module_config->htmlFooter); } if ($module_config->siteTitle) { if (!Context::getBrowserTitle()) { Context::setBrowserTitle($module_config->siteTitle); } } } // if failed message exists in session, set context self::_setInputErrorToContext(); $procResult = $oModule->proc(); $methodList = array('XMLRPC' => 1, 'JSON' => 1, 'JS_CALLBACK' => 1); if (!$oModule->stop_proc && !isset($methodList[Context::getRequestMethod()])) { $error = $oModule->getError(); $message = $oModule->getMessage(); $messageType = $oModule->getMessageType(); $redirectUrl = $oModule->getRedirectUrl(); if (!$procResult) { $this->error = $message; if (!$redirectUrl && Context::get('error_return_url')) { $redirectUrl = Context::get('error_return_url'); } self::_setInputValueToSession(); } if ($error != 0) { $_SESSION['XE_VALIDATOR_ERROR'] = $error; } if ($validator_id = Context::get('xe_validator_id')) { $_SESSION['XE_VALIDATOR_ID'] = $validator_id; } if ($message != 'success') { $_SESSION['XE_VALIDATOR_MESSAGE'] = $message; $_SESSION['XE_VALIDATOR_MESSAGE_TYPE'] = $messageType; } if (Context::get('xeVirtualRequestMethod') != 'xml' && $redirectUrl) { $_SESSION['XE_VALIDATOR_RETURN_URL'] = $redirectUrl; } } unset($logged_info); return $oModule; }