/** * Checks if the given credentials are valid and the account has * actually be activiated. ID of the user is returned. * * @param string $identifier * @param string $password plain text password * @param string $method Username or Email Address * @return int */ public function checkCredentials($identifier, $password, $method = 'username') { $field = $method == 'username' ? 'username' : 'email'; $pdoSt = $this->_sql->prepare('SELECT u.id, u.username, m.value AS activate_code FROM {PREFIX}users AS u LEFT JOIN {PREFIX}users_meta AS m ON u.id = m.uid AND m.name = "activate_code" WHERE u.' . $field . ' = ? AND u.password = ?'); $pdoSt->execute(array($identifier, zula_hash($password))); $user = $pdoSt->fetch(PDO::FETCH_ASSOC); $pdoSt->closeCursor(); /** * Gather Remote address/ip and either update/insert the failed attempt, * or remove the login attempts due to successful login. */ $remoteAddr = zula_ip2long(zula_get_client_ip()); if (empty($user)) { $pdoSt = $this->_sql->prepare('INSERT INTO {PREFIX}mod_session (ip, attempts, blocked) VALUES (?, 1, UTC_TIMESTAMP()) ON DUPLICATE KEY UPDATE attempts = attempts+1, blocked = UTC_TIMESTAMP()'); $pdoSt->execute(array($remoteAddr)); throw new Session_InvalidCredentials(); } else { $pdoSt = $this->_sql->prepare('DELETE FROM {PREFIX}mod_session WHERE ip = ?'); $pdoSt->execute(array($remoteAddr)); } // Update everything needed to set the user has logged in. if ($user['activate_code']) { throw new Session_UserNotActivated('User "' . $user['username'] . '" is not yet activated'); } else { return $user['id']; } }
/** * hook: module_output_bottom * Show comments and comments form * * @param array $msc * @param int $contentType * @param string $sector * @param string $title * @return mixed */ public function hookModuleOutputBottom(array $mcs, $contentType, $sector, $title) { if ($sector == 'SC' && $contentType & Zula_ControllerBase::_OT_CONTENT_DYNAMIC && !($contentType & Zula_ControllerBase::_OT_CONFIG)) { $requestPath = $this->_router->getRequestPath(Router::_TRIM_ALL); $view = new View('display/linear.html', 'comments'); $view->assign(array('TITLE' => $title)); $view->assignHtml(array('COMMENTS' => $this->_model('comments', 'comments')->get($requestPath))); if ($this->_acl->check('comments_post')) { /** * Store the hash path as a valid comment path, then build the * form view and output both views */ $hashPath = zula_hash($requestPath); $_SESSION['mod']['comments'][$hashPath] = array('path' => $requestPath, 'siteType' => $this->_router->getSiteType()); $form = new View('form.html', 'comments'); $form->assign(array('comments' => array('hash' => $hashPath, 'name' => $this->_session->getUser('username'), 'website' => null, 'body' => null))); // Antispam/Captcha $antispam = new Antispam(); $form->assignHtml(array('CSRF' => $this->_input->createToken(true), 'ANTISPAM' => $antispam->create())); return $view->getOutput() . $form->getOutput(); } else { return $view->getOutput(); } } }
/** * Gets the latest versions of TangoCMS and compare * * @return string */ public function updateSection() { $this->setTitle(t('Update checker')); $this->setOutputType(self::_OT_INFORMATIVE); // Gather the latest stable and unstable versions $versions = array('stable' => t('Unknown'), 'unstable' => t('Unknown')); if (ini_get('allow_url_fopen')) { $stream = stream_context_create(array('http' => array('method' => 'GET', 'header' => 'X-TangoCMS-Version: ' . _PROJECT_VERSION . "\r\n" . 'X-TangoCMS-USI: ' . zula_hash($_SERVER['HTTP_HOST']) . "\r\n", 'timeout' => 6))); foreach ($versions as $type => $ver) { $tmpVer = @file_get_contents('http://releases.tangocms.org/latest/' . $type, false, $stream); if (isset($http_response_header[0]) && strpos($http_response_header[0], '200') !== false) { $versions[$type] = trim($tmpVer); } } file_put_contents($this->_zula->getDir('tmp') . '/sysinfo/versions', serialize($versions)); } $view = $this->loadView('index/update.html'); $view->assign(array('TCM_VERSION' => _PROJECT_VERSION, 'VERSION_TYPE' => zula_version_type(_PROJECT_VERSION), 'LATEST' => $versions)); return $view->getOutput(); }
/** * Compress all the needed JS files for TinyMCE into one, * and will return it back for TinyMCE to execute. * * The results of this are cached if all data matches up. * * @return string */ public function gzipSection() { $jsFile = 'tinymce-' . zula_hash(implode('|', $this->_input->getAll('get')), null, 'md5') . '.js'; // Build path and check if the cached version exists $jsFilePath = $this->_zula->getDir('tmp') . '/js/' . $jsFile; if (!file_exists($jsFilePath)) { if (!is_dir(dirname($jsFilePath))) { zula_make_dir(dirname($jsFilePath)); } try { $tinyMcePath = $this->_zula->getDir('js') . '/tinymce'; $tinyMceLang = $this->_input->get('languages'); $theme = $this->_input->get('themes'); // Array of all files that need to be merged together $neededFiles = array('/langs/' . $tinyMceLang . '.js', '/themes/' . $theme . '/editor_template.js', '/themes/' . $theme . '/langs/' . $tinyMceLang . '.js'); // Plugins foreach (explode(',', $this->_input->get('plugins')) as $plugin) { $neededFiles[] = '/plugins/' . $plugin . '/editor_plugin.js'; $neededFiles[] = '/plugins/' . $plugin . '/langs/' . $tinyMceLang . '.js'; } $content = ''; foreach ($neededFiles as $file) { $path = $tinyMcePath . $file; if (file_exists($path)) { $content .= file_get_contents($path); } } if ($this->_input->get('core') == true) { $content = file_get_contents($tinyMcePath . '/tiny_mce.js') . ' tinyMCE_GZ.start(); ' . $content . ' tinyMCE_GZ.end();'; } // Store the file so it can be used later on file_put_contents($jsFilePath, $content); } catch (Input_KeyNoExist $e) { trigger_error('compressor requires languags, themes, plugins and core input values', E_USER_ERROR); } } zula_readfile($jsFilePath, 'text/javascript'); return false; }
/** * Constructor * Calls the parent constructor to register the methods * * Also gathers the version file to get latest versions * * @return object */ public function __construct() { parent::__construct($this); $verFile = $this->_zula->getDir('tmp') . '/sysinfo/versions'; if (file_exists($verFile) && is_readable($verFile) && filemtime($verFile) + 60 * 60 * 8 > time()) { $this->versions = @unserialize(file_get_contents($verFile)); } else { // Attempt to re-read the versions if (ini_get('allow_url_fopen')) { $stream = stream_context_create(array('http' => array('method' => 'GET', 'header' => 'X-TangoCMS-Version: ' . _PROJECT_VERSION . "\r\n" . 'X-TangoCMS-USI: ' . zula_hash($_SERVER['HTTP_HOST']) . "\r\n", 'timeout' => 6))); foreach (array('stable', 'unstable') as $type) { $tmpVer = @file_get_contents('http://releases.tangocms.org/latest/' . $type, false, $stream); if (isset($http_response_header[0]) && strpos($http_response_header[0], '200') !== false) { $this->versions[$type] = trim($tmpVer); } } if (zula_make_dir($this->_zula->getDir('tmp') . '/sysinfo')) { file_put_contents($verFile, serialize($this->versions)); } } else { $this->_log->message('Sysinfo unable to get latest TangoCMS versions, allow_url_fopen disabled', Log::L_NOTICE); } } }
/** * Validates the password to ensure it is not the same as the previous * * @param string $value * @return bool|string */ public function validatePreviousPw($value) { if ($this->_session->getUser('password') == zula_hash($value)) { return t('Your new password can not be the same as the previous'); } return true; }
/** * Generates a unique token key, to help protect * against CSRF attacks * * @param bool $withHtml Can return the HTML input to be used * @return string */ public function createToken($withHtml = false) { do { $token = zula_hash(uniqid(session_id(), true)); } while (isset($_SESSION['csrf-tokens'][$token])); // Store the token and life of it $_SESSION['csrf-tokens'][$token] = time(); if ($withHtml == false) { return $token; } else { return '<div><input type="hidden" name="' . self::_CSRF_INAME . '" value="' . $token . '"></div>'; } }
/** * Deletes a cached item, or array of items * * @param string|array $key * @return int */ public function delete($key) { $delCount = 0; foreach (array_filter((array) $key) as $cacheKey) { $file = $this->cacheDir . '/' . zula_hash($cacheKey, null, 'md5'); if (file_exists($file) && unlink($file)) { unset($this->cached[$cacheKey]); ++$delCount; } } return $delCount; }
/** * Switches the currently identified user to another account * basically, 'logging in'. All session data will remain. * * @param int $uid * @param bool $remember * @return int|bool */ public function switchUser($uid, $remember = true) { $session = $_SESSION; $this->destroy(); # Destroy the current session/user first $this->start(); $_SESSION = $session; unset($_SESSION['auth']); // Create the needed unique keys for this session, if any $uid = abs($uid); if ($uid == Ugmanager::_GUEST_ID) { return $this->identify(); } else { $authKey = zula_hash(uniqid(mt_rand() . $uid . microtime(true), true)); $authFor = zula_hash($uid); $pdoSt = $this->_sql->prepare('INSERT INTO {PREFIX}sessions (uid, session_key, session_id) VALUES(?, ?, ?)'); $pdoSt->execute(array($uid, $authKey, session_id())); // Attempt to identify the user we are switching to if ($this->identify($authKey, $authFor) === $uid) { $this->_sql->query('UPDATE {PREFIX}users SET last_login = UNIX_TIMESTAMP() WHERE id = ' . $uid); $_SESSION['auth'] = array('remember' => (bool) $remember, 'key' => $authKey, 'for' => $authFor); if ($_SESSION['auth']['remember']) { // Set cookie for 28 days setcookie('zulaAuthKey', $authKey, time() + 2419200, _BASE_DIR, '', '', true); setcookie('zulaAuthFor', $authFor, time() + 2419200, _BASE_DIR, '', '', true); } return (int) $uid; } else { return false; } } }
/** * Returns the themes view output as a string. If a layout object has been * loaded, then all required controllers for said layout will be loaded into * the correct sector. * * @return string */ public function output() { if (!empty($this->loadedJsFiles)) { // Setup some vars to be used (as JS can not get at the Zula Framework) $this->addHead('js', array(), 'var zula_dir_base = "' . _BASE_DIR . '"; var zula_dir_assets = "' . $this->_zula->getDir('assets', true) . '"; var zula_dir_js = "' . $this->_zula->getDir('js', true) . '"; var zula_dir_cur_theme = "' . $this->_zula->getDir('themes', true) . '/' . $this->getDetail('name') . '"; var zula_dir_icon = zula_dir_cur_theme+"/icons"; var zula_theme_style = "' . $this->getDetail('style') . '";', true); } if ($this->jsAggregation) { // Add in all needed JavaScript files, those under 'merging' will be aggregated. foreach (array('system', 'merging', 'standalone') as $type) { if (empty($this->loadedJsFiles[$type])) { continue; # No JS files of this type. } else { if ($type == 'system' || $type == 'standalone') { foreach ($this->loadedJsFiles[$type] as $file) { $this->addHead('js', array('src' => $file)); } } else { /** * Merge all 'merging' JS files into 1, help reduce HTTP requests */ $tmpJsFile = 'js/' . zula_hash(implode('', $this->loadedJsFiles[$type]), null, 'md5') . '.js'; $tmpJsPath = $this->_zula->getDir('tmp') . '/' . $tmpJsFile; // Check if the aggregated file exists, if so - see if we need to expire it $hasFile = false; if (is_dir(dirname($tmpJsPath))) { if (file_exists($tmpJsPath)) { $hasFile = true; $lastModified = filemtime($tmpJsPath); foreach ($this->loadedJsFiles[$type] as $file) { if (filemtime($file) > $lastModified) { unlink($tmpJsPath); $hasFile = false; break; } } } } else { zula_make_dir(dirname($tmpJsPath)); } if ($hasFile === false) { // Create the new aggregation file $content = null; foreach ($this->loadedJsFiles[$type] as $file) { $content .= file_get_contents($file); } file_put_contents($tmpJsPath, $content); } $this->addHead('js', array('src' => $this->_zula->getDir('tmp', true) . '/' . $tmpJsFile)); } } } } if (!$this->isAssigned('HEAD')) { $this->assign(array('HEAD' => '')); } return $this->getOutput(); }
/** * Edits certain details about a comment * * @param int $commentId * @param array $details * @return bool */ public function edit($commentId, array $details) { $commentDetails = $this->getDetails($commentId); $query = 'UPDATE {PREFIX}mod_comments SET '; $execData = array(); foreach ($details as $key => $val) { $query .= $key . ' = ?, '; $execData[] = $val; } $query = rtrim($query, ', ') . ' WHERE id = ?'; $execData[] = $commentId; if ($this->_sql->prepare($query)->execute($execData)) { $this->_cache->delete('comments_' . zula_hash($commentDetails['url'])); $this->_cache->delete('comments'); return true; } else { return false; } }
/** * Adds a new user to a specified group with the provided * details (which can contain meta details) * * @param array $details * @return int|bool */ public function addUser($details) { if (!isset($details['group']) || !$this->groupExists($details['group'])) { throw new Ugmanager_GroupNoExist('could not add user to group as it does not exist'); } else { if ($details['group'] == self::_ROOT_GID || $details['group'] == self::_GUEST_GID) { throw new Ugmanager_InvalidGroup('users can not be added to the root or guest group'); } else { if ($this->userExists($details['username'], false)) { throw new Ugmanager_UserExists('could not add user as user already exists'); } } } if (isset($details['password'])) { $details['password'] = zula_hash($details['password']); } unset($details['joined'], $details['last_pw_change']); // First insert the standard data $addUserQ = 'INSERT INTO {PREFIX}users (%s,joined, last_pw_change) VALUES(%s,UTC_TIMESTAMP(), UTC_TIMESTAMP())'; $insertData = array(); foreach (array_intersect_key($details, array_flip($this->userKeys)) as $key => $val) { $insertData["`{$key}`"] = $val; } $addUserQ = sprintf($addUserQ, implode(',', array_keys($insertData)), rtrim(str_repeat('?,', count($insertData)), ',')); $pdoSt = $this->_sql->prepare($addUserQ); $pdoSt->execute(array_values($insertData)); if ($uid = $this->_sql->lastInsertId()) { /** * Insert the user meta data */ $pdoStMeta = $this->_sql->prepare('INSERT INTO {PREFIX}users_meta (uid, name, value) VALUES(:uid, :name, :value)'); foreach (array_diff_key($details, array_flip($this->userKeys)) as $key => $val) { $pdoStMeta->execute(array(':uid' => $uid, ':name' => $key, ':value' => $val)); } if (isset($this->userCount['*'])) { ++$this->userCount['*']; } if (isset($this->userCount[$details['group']])) { ++$this->userCount[$details['group']]; } $this->_cache->delete('ugmanager_users'); // Add the ID so hooks can use it. $details['id'] = $uid; Hooks::notifyAll('ugmanager_user_add', $details); return $details['id']; } else { return false; } }
/** * Validates the users password to ensure it is their * current one, to help with security. * * @param string $value * @return string|bool */ public function validatePassword($value) { if (zula_hash($value) == $this->_session->getUser('password')) { return true; } else { return t('Please enter your current user password'); } }