Commit ea5b645c authored by tino.goratsch@hotmail.com's avatar [email protected]

many bug fixes and refactorings

parent f637d980
......@@ -2,6 +2,7 @@
namespace ACP3;
use ACP3\Core\FrontController;
use ACP3\Core\Modules;
use ACP3\Core\Modules\Controller;
use ACP3\Core\Registry;
......@@ -203,54 +204,6 @@ class Application
$dumper = new PhpDumper($this->container);
file_put_contents($file, $dumper->dump(array('class' => 'ACP3ServiceContainer')));
}
Registry::set('services', $this->container);
}
/**
* Überprüft die URI auf einen möglichen URI-Alias und
* macht im Erfolgsfall einen Redirect darauf
*
* @return void
*/
private function _checkForUriAlias()
{
$request = $this->container->get('core.request');
// Nur ausführen, falls URI-Aliase aktiviert sind
if ($request->area !== 'admin') {
// Falls für Query ein Alias existiert, zu diesem weiterleiten
if ($this->container->get('core.router.aliases')->uriAliasExists($request->query) === true) {
$this->container->get('core.redirect')->permanent($request->query); // URI-Alias wird von uri::route() erzeugt
}
$probableQuery = $request->query;
// Annehmen, dass ein URI Alias mit zusätzlichen Parametern übergeben wurde
if (preg_match('/^([a-z]{1}[a-z\d\-]*\/)+(([a-z\d\-]+)_(.+)\/)+$/', $request->query)) {
$query = preg_split('=/=', $request->query, -1, PREG_SPLIT_NO_EMPTY);
// Keine entsprechende Module-Action gefunden -> muss Alias sein
if ($this->container->get('core.modules')->actionExists($request->area . '/' . $query[0] . '/' . $query[1]) === false) {
$length = 0;
foreach ($query as $row) {
if (strpos($row, '_') === false) {
$length += strlen($row) + 1;
} else {
break;
}
}
$params = substr($request->query, $length);
$probableQuery = substr($request->query, 0, $length);
}
}
// Nachschauen, ob ein URI-Alias für die aktuelle Seite festgelegt wurde
$alias = $this->container->get('core.db')->fetchAssoc('SELECT uri FROM ' . DB_PRE . 'seo WHERE alias = ?', array(substr($probableQuery, 0, -1)));
if (!empty($alias)) {
$request->query = $alias['uri'] . (!empty($params) ? $params : '');
}
}
return;
}
/**
......@@ -260,15 +213,13 @@ class Application
{
$this->_checkForMaintenanceMode();
$this->_checkForUriAlias();
$request = $this->container->get('core.request');
$redirect = $this->container->get('core.redirect');
try {
$serviceId = $request->mod . '.controller.' . $request->area . '.' . $request->controller;
$frontController = new FrontController($this->container);
$errorsServiceId = 'errors.controller.frontend.index';
$this->dispatch($serviceId, $request->file);
try {
$frontController->dispatch();
} catch (Core\Exceptions\ResultNotExists $e) {
if ($e->getMessage()) {
Core\Logger::error('404', $e);
......@@ -276,9 +227,9 @@ class Application
Core\Logger::error('404', 'Could not find any results for request: ' . $request->query);
}
$redirect->temporary('errors/index/404');
$frontController->dispatch($errorsServiceId, '404');
} catch (Core\Exceptions\UnauthorizedAccess $e) {
$redirect->temporary('errors/index/401');
$frontController->dispatch($errorsServiceId, '401');
} catch (Core\Exceptions\ControllerActionNotFound $e) {
Core\Logger::error('404', 'Request: ' . $request->query);
Core\Logger::error('404', $e);
......@@ -287,7 +238,7 @@ class Application
$errorMessage = $e->getMessage();
$this->_renderApplicationException($errorMessage);
} else {
$redirect->temporary('errors/index/404');
$frontController->dispatch($errorsServiceId, '404');
}
} catch (\Exception $e) {
Core\Logger::error('exception', $e);
......@@ -296,43 +247,25 @@ class Application
$errorMessage = $e->getMessage();
$this->_renderApplicationException($errorMessage);
} else {
$redirect->temporary('errors/index/500');
$frontController->dispatch($errorsServiceId, '500');
}
}
}
/**
* @param $serviceId
* @param $action
* @throws Core\Exceptions\ControllerActionNotFound
* @param Container $container
*/
public function dispatch($serviceId, $action)
public function setContainer(Container $container)
{
if ($this->container->has($serviceId)) {
/** @var Controller $controller */
$controller = $this->container->get($serviceId);
$action = 'action' . str_replace('_', '', $action);
if (method_exists($controller, $action) === true) {
$controller->setContainer($this->container);
$controller->preDispatch();
$controller->$action();
$controller->display();
} else {
throw new Core\Exceptions\ControllerActionNotFound('Controller action ' . get_class($controller) . '::' . $action . '() was not found!');
}
} else {
throw new Core\Exceptions\ControllerActionNotFound('Service-Id ' . $serviceId . ' was not found!');
}
$this->container = $container;
}
/**
* @param Container $container
* @return Container
*/
public function setContainer(Container $container)
public function getContainer()
{
$this->container = $container;
return $this->container;
}
/**
......@@ -342,6 +275,7 @@ class Application
private function _renderApplicationException($errorMessage)
{
$view = $this->container->get('core.view');
$view->assign('ROOT_DIR', ROOT_DIR);
$view->assign('PAGE_TITLE', CONFIG_SEO_TITLE);
$view->assign('CONTENT', $errorMessage);
$view->displayTemplate('system/maintenance.tpl');
......
......@@ -45,36 +45,41 @@ class Auth
* @var string
*/
public $language = CONFIG_LANG;
/**
* @var array
*/
protected $userInfo = array();
/**
* @var Session
*/
protected $session;
/**
* @var \ACP3\Modules\Users\Model
*/
protected $userModel;
protected $usersModel;
/**
* @var Secure
*/
protected $secureHelper;
/**
* Findet heraus, falls der ACP3_AUTH Cookie gesetzt ist, ob der
* Seitenbesucher auch wirklich ein registrierter Benutzer des ACP3 ist
*/
function __construct(\Doctrine\DBAL\Connection $db, Session $session)
function __construct(
\Doctrine\DBAL\Connection $db,
Session $session,
Secure $secureHelper)
{
$this->session = $session;
$this->userModel = new Users\Model($db);
$this->usersModel = new Users\Model($db);
$this->secureHelper = $secureHelper;
if (isset($_COOKIE[self::COOKIE_NAME])) {
$cookie = base64_decode($_COOKIE[self::COOKIE_NAME]);
$cookieData = explode('|', $cookie);
$user = $this->userModel->getOneActiveUserByNickname($cookieData[0]);
$user = $this->usersModel->getOneActiveUserByNickname($cookieData[0]);
if (!empty($user)) {
$dbPassword = substr($user['pwd'], 0, 40);
if ($dbPassword === $cookieData[1]) {
......@@ -119,7 +124,7 @@ class Auth
if (empty($this->userInfo[$userId])) {
$countries = Lang::worldCountries();
$info = $this->userModel->getOneById($userId);
$info = $this->usersModel->getOneById($userId);
if (!empty($info)) {
$info['country_formatted'] = !empty($info['country']) && isset($countries[$info['country']]) ? $countries[$info['country']] : '';
$this->userInfo[$userId] = $info;
......@@ -172,7 +177,7 @@ class Auth
*/
public function login($username, $password, $expiry)
{
$user = $this->userModel->getOneByNickname($username);
$user = $this->usersModel->getOneByNickname($username);
if (!empty($user)) {
// Useraccount ist gesperrt
......@@ -186,14 +191,13 @@ class Auth
// Hash für eingegebenes Passwort generieren
$salt = substr($user['pwd'], 41, 53);
$securityHelper = new Secure();
$formPasswordHash = $securityHelper->generateSaltedPassword($salt, $password);
$formPasswordHash = $this->secureHelper->generateSaltedPassword($salt, $password);
// Wenn beide Hashwerte gleich sind, Benutzer authentifizieren
if ($dbHash === $formPasswordHash) {
// Login-Fehler zurücksetzen
if ($user['login_errors'] > 0) {
$this->userModel->update(array('login_errors' => 0), (int)$user['id']);
$this->usersModel->update(array('login_errors' => 0), (int)$user['id']);
}
$this->setCookie($username, $dbHash, $expiry);
......@@ -207,7 +211,7 @@ class Auth
return 1;
} else { // Beim dritten falschen Login den Account sperren
$loginErrors = $user['login_errors'] + 1;
$this->userModel->update(array('login_errors' => $loginErrors), (int)$user['id']);
$this->usersModel->update(array('login_errors' => $loginErrors), (int)$user['id']);
if ($loginErrors === 3) {
return -1;
}
......
......@@ -17,6 +17,10 @@ class Admin extends Frontend
* @var \ACP3\Core\Session
*/
protected $session;
/**
* @var Core\Router\Aliases
*/
protected $aliases;
public function __construct(
Core\Auth $auth,
......@@ -28,12 +32,14 @@ class Admin extends Frontend
Core\Breadcrumb $breadcrumb,
Core\SEO $seo,
Core\Validate $validate,
Core\Session $session)
Core\Session $session,
Core\Router\Aliases $aliases)
{
parent::__construct($auth, $lang, $modules, $request, $router, $view, $breadcrumb, $seo);
$this->validate = $validate;
$this->session = $session;
$this->aliases = $aliases;
}
/**
......@@ -52,4 +58,9 @@ class Admin extends Frontend
return $this->validate;
}
public function getAliases()
{
return $this->aliases;
}
}
\ No newline at end of file
<?php
namespace ACP3\Core;
use Symfony\Component\DependencyInjection\Container;
class FrontController
{
/**
* @var Request
*/
protected $request;
/**
* @var Redirect
*/
protected $redirect;
/**
* @var Router\Aliases
*/
protected $routerAliases;
/**
* @var Container
*/
protected $container;
public function __construct(Container $container)
{
$this->request = $container->get('core.request');
$this->redirect = $container->get('core.redirect');
$this->routerAliases = $container->get('core.router.aliases');
$this->container = $container;
}
/**
* Überprüft die URI auf einen möglichen URI-Alias und
* macht im Erfolgsfall einen Redirect darauf
*
* @return void
*/
private function _checkForUriAlias()
{
// Nur ausführen, falls URI-Aliase aktiviert sind
if ($this->request->area !== 'admin') {
// Falls für Query ein Alias existiert, zu diesem weiterleiten
if ($this->routerAliases->uriAliasExists($this->request->query) === true &&
$this->request->originalQuery !== $this->routerAliases->getUriAlias($this->request->query) . '/') {
$this->redirect->permanent($this->request->query); // URI-Alias wird von Router::route() erzeugt
}
}
return;
}
/**
* @param $serviceId
* @param $action
* @throws Exceptions\ControllerActionNotFound
*/
public function dispatch($serviceId = '', $action = '')
{
$this->_checkForUriAlias();
if (empty($serviceId)) {
$serviceId = $this->request->mod . '.controller.' . $this->request->area . '.' . $this->request->controller;
}
if ($this->container->has($serviceId)) {
/** @var Modules\Controller $controller */
$controller = $this->container->get($serviceId);
if (empty($action)) {
$action = $this->request->file;
}
$action = 'action' . str_replace('_', '', $action);
if (method_exists($controller, $action) === true) {
$controller->setContainer($this->container);
$controller->preDispatch();
$controller->$action();
$controller->display();
} else {
throw new Exceptions\ControllerActionNotFound('Controller action ' . get_class($controller) . '::' . $action . '() was not found!');
}
} else {
throw new Exceptions\ControllerActionNotFound('Service-Id ' . $serviceId . ' was not found!');
}
}
}
\ No newline at end of file
......@@ -34,7 +34,7 @@ class RedirectMessages
}
/**
* Holt sich die von setRedirectMessage() erzeugte Redirect Nachricht
* Gets the generated redirect message from setMessage()
*/
public function getMessage()
{
......
<?php
namespace ACP3\Core\Helpers;
use ACP3\Core;
/**
* Class Secure
* @package ACP3\Core\Helpers
*/
class Secure
{
/**
* @var Core\View
*/
protected $view;
public function __construct(Core\View $view)
{
$this->view = $view;
}
/**
* Generiert ein gesalzenes Passwort
*
......@@ -59,4 +71,42 @@ class Secure
return $scriptTagOnly === true ? $var : htmlentities($var, ENT_QUOTES, 'UTF-8');
}
/**
* Generiert für ein Formular ein Securitytoken
*
* @param string $path
* Optionaler ACP3 interner URI Pfad, für welchen das Token gelten soll
*/
public function generateFormToken($path)
{
$tokenName = Core\Session::XSRF_TOKEN_NAME;
if (!isset($_SESSION[$tokenName]) || is_array($_SESSION[$tokenName]) === false) {
$_SESSION[$tokenName] = array();
}
$path = $path . (!preg_match('/\/$/', $path) ? '/' : '');
if (empty($_SESSION[$tokenName][$path])) {
$_SESSION[$tokenName][$path] = sha1(uniqid(mt_rand(), true));
}
$this->view->assign('form_token', '<input type="hidden" name="' . $tokenName . '" value="' . $_SESSION[$tokenName][$path] . '" />');
}
/**
* Entfernt das Securitytoken aus der Session
*/
public function unsetFormToken($path, $token = '')
{
$tokenName = Core\Session::XSRF_TOKEN_NAME;
if (empty($token) && isset($_POST[$tokenName])) {
$token = $_POST[$tokenName];
}
if (!empty($token) && is_array($_SESSION[$tokenName]) === true) {
if (isset($_SESSION[$tokenName][$path])) {
unset($_SESSION[$tokenName][$path]);
}
}
}
}
\ No newline at end of file
......@@ -4,9 +4,8 @@ namespace ACP3\Core;
use ACP3\Modules\System;
/**
* Klasse für die Module
*
* @author Tino Goratsch
* Class Modules
* @package ACP3\Core
*/
class Modules
{
......@@ -39,7 +38,11 @@ class Modules
*/
protected $systemModel;
public function __construct(\Doctrine\DBAL\Connection $db, ACL $acl, Lang $lang)
public function __construct(
\Doctrine\DBAL\Connection $db,
ACL $acl,
Lang $lang
)
{
$this->db = $db;
$this->acl = $acl;
......
......@@ -18,6 +18,10 @@ abstract class Admin extends Core\Modules\Controller\Frontend
* @var Core\Validate
*/
protected $validate;
/**
* @var Core\Router\Aliases
*/
protected $aliases;
public function __construct(Core\Context\Admin $adminContext)
{
......@@ -25,6 +29,7 @@ abstract class Admin extends Core\Modules\Controller\Frontend
$this->validate = $adminContext->getValidate();
$this->session = $adminContext->getSession();
$this->aliases = $adminContext->getAliases();
}
/**
......@@ -35,7 +40,7 @@ abstract class Admin extends Core\Modules\Controller\Frontend
{
if ($this->auth->isUser() === false) {
$redirectUri = base64_encode('acp/' . $this->request->query);
$this->request->redirect('users/index/login/redirect_' . $redirectUri);
$this->redirect()->temporary('users/index/login/redirect_' . $redirectUri);
}
return parent::preDispatch();
......
......@@ -61,6 +61,7 @@ class Redirect
$response = new JsonResponse($return);
$response->send();
exit;
}
}
......@@ -99,6 +100,7 @@ class Redirect
$response = new RedirectResponse($url, $status);
$response->send();
exit;
}
}
\ No newline at end of file
......@@ -11,6 +11,14 @@ class Request
{
const ADMIN_PANEL_PATTERN = '=^acp/=';
/**
* @var \Doctrine\DBAL\Connection
*/
protected $db;
/**
* @var Modules
*/
protected $modules;
/**
* Array, welches die URI Parameter enthält
*
......@@ -24,12 +32,19 @@ class Request
* @var string
*/
public $query = '';
/**
* @var string
*/
public $originalQuery = '';
/**
* Zerlegt u.a. die übergebenen Parameter in der URI in ihre Bestandteile
*/
function __construct()
public function __construct(\Doctrine\DBAL\Connection $db, Modules $modules)
{
$this->db = $db;
$this->modules = $modules;
$this->preprocessUriQuery();
// Set the user defined homepage of the website
......@@ -37,6 +52,7 @@ class Request
$this->query = CONFIG_HOMEPAGE;
}
$this->checkForUriAlias();
$this->setUriParameters();
}
......@@ -81,8 +97,10 @@ class Request
*/
protected function preprocessUriQuery()
{
$this->query = substr(str_replace(PHP_SELF, '', htmlentities($_SERVER['PHP_SELF'], ENT_QUOTES)), 1);
$this->query .= !preg_match('/\/$/', $this->query) ? '/' : '';
$this->originalQuery = substr(str_replace(PHP_SELF, '', htmlentities($_SERVER['PHP_SELF'], ENT_QUOTES)), 1);
$this->originalQuery .= !preg_match('/\/$/', $this->originalQuery) ? '/' : '';
$this->query = $this->originalQuery;
// Definieren, dass man sich im Administrationsbereich befindet
if (preg_match(self::ADMIN_PANEL_PATTERN, $this->query)) {
......@@ -96,6 +114,39 @@ class Request
return;
}
protected function checkForUriAlias()
{
// Nur ausführen, falls URI-Aliase aktiviert sind
if ($this->area !== 'admin') {
$probableQuery = $this->query;
// Annehmen, dass ein URI Alias mit zusätzlichen Parametern übergeben wurde
if (preg_match('/^([a-z]{1}[a-z\d\-]*\/)+(([a-z\d\-]+)_(.+)\/)+$/', $this->query)) {
$query = preg_split('=/=', $this->query, -1, PREG_SPLIT_NO_EMPTY);
// Keine entsprechende Module-Action gefunden -> muss Alias sein
if ($this->modules->actionExists($this->area . '/' . $query[0] . '/' . $query[1]) === false) {
$length = 0;
foreach ($query as $row) {
if (strpos($row, '_') === false) {
$length += strlen($row) + 1;
} else {
break;
}
}
$params = substr($this->query, $length);
$probableQuery = substr($this->query, 0, $length);
}
}
// Nachschauen, ob ein URI-Alias für die aktuelle Seite festgelegt wurde
$alias = $this->db->fetchColumn('SELECT uri FROM ' . DB_PRE . 'seo WHERE alias = ?', array(substr($probableQuery, 0, -1)));
if (!empty($alias)) {
$this->query = $alias . (!empty($params) ? $params : '');
}
}
return;
}
/**
* @return bool
*/
......@@ -115,7 +166,7 @@ class Request
*
* @return void
*/
protected function setUriParameters()
public function setUriParameters()
{
$query = preg_split('=/=', $this->query, -1, PREG_SPLIT_NO_EMPTY);
......
......@@ -40,21 +40,9 @@ class Session
*/
protected $db;
/**
* @var \ACP3\Core\Request
*/
protected $request;
/**
* @var \ACP3\Core\View
*/
protected $view;
public function __construct(\Doctrine\DBAL\Connection $db, Request $request, View $view)
public function __construct(\Doctrine\DBAL\Connection $db)
{
$this->db = $db;
$this->request = $request;
$this->view = $view;
// php.ini Session Einstellungen konfigurieren
ini_set('session.name', self::SESSION_NAME);
......@@ -198,42 +186,4 @@ class Session
return true;
}
/**
* Generiert für ein Formular ein Securitytoken
*
* @param string $path
* Optionaler ACP3 interner URI Pfad, für welchen das Token gelten soll
*/
public function generateFormToken($path = '')
{
$tokenName = self::XSRF_TOKEN_NAME;
if (!isset($_SESSION[$tokenName]) || is_array($_SESSION[$tokenName]) === false) {
$_SESSION[$tokenName] = array();
}
$path = !empty($path) ? $path . (!preg_match('/\/$/', $path) ? '/' : '') : $this->request->query;
if (empty($_SESSION[$tokenName][$path])) {
$_SESSION[$tokenName][$path] = sha1(uniqid(mt_rand(), true));
}
$this->view->assign('form_token', '<input type="hidden" name="' . $tokenName . '" value="' . $_SESSION[$tokenName][$path] . '" />');
}
/**
* Entfernt das Securitytoken aus der Session
*/
public function unsetFormToken($token = '')
{
$tokenName = self::XSRF_TOKEN_NAME;
if (empty($token) && isset($_POST[$tokenName])) {
$token = $_POST[$tokenName];
}
if (!empty($token) && is_array($_SESSION[$tokenName]) === true) {
if (isset($_SESSION[$tokenName][$this->request->query])) {
unset($_SESSION[$tokenName][$this->request->query]);
}
}
}
}
<?php
namespace ACP3\Core\View\Renderer\Smarty;
use ACP3\Application;
use ACP3\Core\FrontController;
use ACP3\Core\Modules;