634 Zeilen
18 KiB
PHP
634 Zeilen
18 KiB
PHP
|
<?php
|
||
|
/**
|
||
|
* Project:
|
||
|
* Contenido Content Management System
|
||
|
*
|
||
|
* Description:
|
||
|
* Includes Mod Rewrite controller class.
|
||
|
*
|
||
|
* Requirements:
|
||
|
* @con_php_req 5.0
|
||
|
*
|
||
|
*
|
||
|
* @package Contenido Backend plugins
|
||
|
* @version 0.1
|
||
|
* @author Murat Purc <murat@purc.de>
|
||
|
* @copyright four for business AG <www.4fb.de>
|
||
|
* @license http://www.contenido.org/license/LIZENZ.txt
|
||
|
* @link http://www.4fb.de
|
||
|
* @link http://www.contenido.org
|
||
|
* @since file available since Contenido release 4.8.15
|
||
|
*
|
||
|
* {@internal
|
||
|
* created 2008-04-16
|
||
|
*
|
||
|
* $Id: class.modrewritecontroller.php 211 2013-01-25 09:30:14Z oldperl $:
|
||
|
* }}
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
|
||
|
defined('CON_FRAMEWORK') or die('Illegal call');
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Mod Rewrite controller class. Extracts url parts and sets some necessary globals like:
|
||
|
* - $idart
|
||
|
* - $idcat
|
||
|
* - $client
|
||
|
* - $changeclient
|
||
|
* - $lang
|
||
|
* - $changelang
|
||
|
*
|
||
|
* @author Murat Purc <murat@purc.de>
|
||
|
* @package Contenido Backend plugins
|
||
|
* @subpackage ModRewrite
|
||
|
*/
|
||
|
class ModRewriteController extends ModRewriteBase
|
||
|
{
|
||
|
|
||
|
/**
|
||
|
* Extracted request uri path parts by path separator '/'
|
||
|
*
|
||
|
* @var array
|
||
|
*/
|
||
|
private $_aParts;
|
||
|
|
||
|
/**
|
||
|
* Extracted article name from request uri
|
||
|
*
|
||
|
* @var string
|
||
|
*/
|
||
|
private $_sArtName;
|
||
|
|
||
|
/**
|
||
|
* Remaining path for path resolver (see $GLOBALS['path'])
|
||
|
*
|
||
|
* @var string
|
||
|
*/
|
||
|
private $_sPath;
|
||
|
|
||
|
/**
|
||
|
* Incomming URL
|
||
|
*
|
||
|
* @var string
|
||
|
*/
|
||
|
private $_sIncommingUrl;
|
||
|
|
||
|
/**
|
||
|
* Resolved URL
|
||
|
*
|
||
|
* @var string
|
||
|
*/
|
||
|
private $_sResolvedUrl;
|
||
|
|
||
|
/**
|
||
|
* Client id used by this class
|
||
|
*
|
||
|
* @var int
|
||
|
*/
|
||
|
private $_iClientMR;
|
||
|
|
||
|
/**
|
||
|
* Flag about occured errors
|
||
|
*
|
||
|
* @var bool
|
||
|
*/
|
||
|
private $_bError = false;
|
||
|
|
||
|
/**
|
||
|
* Flag about found routing definition
|
||
|
*
|
||
|
* @var bool
|
||
|
*/
|
||
|
private $_bRoutingFound = false;
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Constructor, sets several properties.
|
||
|
*
|
||
|
* @param string $incommingUrl Incomming URL
|
||
|
*/
|
||
|
public function __construct($incommingUrl)
|
||
|
{
|
||
|
$this->_sIncommingUrl = $incommingUrl;
|
||
|
$this->_aParts = array();
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Getter for overwritten client id (see $GLOBALS['client'])
|
||
|
*
|
||
|
* @return int Client id
|
||
|
*/
|
||
|
public function getClient()
|
||
|
{
|
||
|
return $GLOBALS['client'];
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Getter for overwritten change client id (see $GLOBALS['changeclient'])
|
||
|
*
|
||
|
* @return int Change client id
|
||
|
*/
|
||
|
public function getChangeClient()
|
||
|
{
|
||
|
return $GLOBALS['changeclient'];
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Getter for article id (see $GLOBALS['idart'])
|
||
|
*
|
||
|
* @return int Article id
|
||
|
*/
|
||
|
public function getIdArt()
|
||
|
{
|
||
|
return $GLOBALS['idart'];
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Getter for category id (see $GLOBALS['idcat'])
|
||
|
*
|
||
|
* @return int Category id
|
||
|
*/
|
||
|
public function getIdCat()
|
||
|
{
|
||
|
return $GLOBALS['idcat'];
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Getter for language id (see $GLOBALS['lang'])
|
||
|
*
|
||
|
* @return int Language id
|
||
|
*/
|
||
|
public function getLang()
|
||
|
{
|
||
|
return $GLOBALS['lang'];
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Getter for change language id (see $GLOBALS['change_lang'])
|
||
|
*
|
||
|
* @return int Change language id
|
||
|
*/
|
||
|
public function getChangeLang()
|
||
|
{
|
||
|
return $GLOBALS['change_lang'];
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Getter for path (see $GLOBALS['path'])
|
||
|
*
|
||
|
* @return string Path, used by path resolver
|
||
|
*/
|
||
|
public function getPath()
|
||
|
{
|
||
|
return $this->_sPath;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Getter for resolved url
|
||
|
*
|
||
|
* @return string Resolved url
|
||
|
*/
|
||
|
public function getResolvedUrl()
|
||
|
{
|
||
|
return $this->_sResolvedUrl;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Returns a flag about found routing definition
|
||
|
*
|
||
|
* return bool Flag about found routing
|
||
|
*/
|
||
|
public function getRoutingFoundState()
|
||
|
{
|
||
|
return $this->_bRoutingFound;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Getter for occured error state
|
||
|
*
|
||
|
* @return bool Flag for occured error
|
||
|
*/
|
||
|
public function errorOccured()
|
||
|
{
|
||
|
return $this->_bError;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Main function to call for mod rewrite related preprocessing jobs.
|
||
|
*
|
||
|
* Executes some private functions to extract request URI and to set needed membervariables
|
||
|
* (client, language, article id, category id, etc.)
|
||
|
*/
|
||
|
public function execute()
|
||
|
{
|
||
|
if (parent::isEnabled() == false) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
$this->_extractRequestUri();
|
||
|
|
||
|
$this->_initializeClientId();
|
||
|
|
||
|
$this->_setClientId();
|
||
|
|
||
|
mr_loadConfiguration($this->_iClientMR);
|
||
|
|
||
|
$this->_setLanguageId();
|
||
|
|
||
|
// second call after setting client and language
|
||
|
$this->_extractRequestUri(true);
|
||
|
|
||
|
$this->_setPathresolverSetting();
|
||
|
|
||
|
$this->_setIdart();
|
||
|
|
||
|
ModRewriteDebugger::add($this->_aParts, 'ModRewriteController::execute() _setIdart');
|
||
|
|
||
|
$this->_postValidation();
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Extracts request URI and sets member variables $this->_sArtName and $this->_aParts
|
||
|
*
|
||
|
* @param bool $secondCall Flag about second call of this function, is needed
|
||
|
* to re extract url if a routing definition was found
|
||
|
*/
|
||
|
private function _extractRequestUri($secondCall = false)
|
||
|
{
|
||
|
global $client;
|
||
|
|
||
|
// check for defined rootdir
|
||
|
if (parent::getConfig('rootdir') !== '/' && strpos($_SERVER['REQUEST_URI'], $this->_sIncommingUrl) === 0) {
|
||
|
$this->_sIncommingUrl = str_replace(parent::getConfig('rootdir'), '/', $this->_sIncommingUrl);
|
||
|
}
|
||
|
|
||
|
$aUrlComponents = $this->_parseUrl($this->_sIncommingUrl);
|
||
|
if (isset($aUrlComponents['path'])) {
|
||
|
if (parent::getConfig('rootdir') !== '/' && strpos($aUrlComponents['path'], parent::getConfig('rootdir')) === 0) {
|
||
|
$aUrlComponents['path'] = str_replace(parent::getConfig('rootdir'), '/', $aUrlComponents['path']);
|
||
|
}
|
||
|
|
||
|
if ($secondCall == true) {
|
||
|
|
||
|
// @todo: implement real redirect of old front_content.php style urls
|
||
|
|
||
|
// check for routing definition
|
||
|
$routings = parent::getConfig('routing');
|
||
|
if (is_array($routings) && isset($routings[$aUrlComponents['path']])) {
|
||
|
$aUrlComponents['path'] = $routings[$aUrlComponents['path']];
|
||
|
if (strpos($aUrlComponents['path'], 'front_content.php') !== false) {
|
||
|
// routing destination contains front_content.php
|
||
|
|
||
|
$this->_bRoutingFound = true;
|
||
|
|
||
|
// set client language, if not set before
|
||
|
mr_setClientLanguageId($client);
|
||
|
|
||
|
//rebuild URL
|
||
|
$url = mr_buildNewUrl($aUrlComponents['path']);
|
||
|
|
||
|
$aUrlComponents = $this->_parseUrl($url);
|
||
|
|
||
|
// add query parameter to superglobal _GET
|
||
|
if (isset($aUrlComponents['query'])) {
|
||
|
parse_str($aUrlComponents['query'], $vars);
|
||
|
$_GET = array_merge($_GET, $vars);
|
||
|
}
|
||
|
|
||
|
$this->_aParts = array();
|
||
|
}
|
||
|
} else {
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
$sPath = (parent::getConfig('use_lowercase_uri') == true)?strtolower($aUrlComponents['path']):$aUrlComponents['path'];
|
||
|
$aPaths = explode('/', $aUrlComponents['path']);
|
||
|
foreach ($aPaths as $p => $item) {
|
||
|
if (!empty($item)) {
|
||
|
// pathinfo would also work
|
||
|
$arr = explode('.', $item);
|
||
|
$count = count($arr);
|
||
|
if ($count > 0 && '.' . strtolower($arr[$count-1]) == parent::getConfig('file_extension')) {
|
||
|
array_pop($arr);
|
||
|
$this->_sArtName = implode('.', $arr);
|
||
|
} else {
|
||
|
$this->_aParts[] = $item;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ($secondCall == true) {
|
||
|
// reprocess extracting client and language
|
||
|
$this->_setClientId();
|
||
|
mr_loadConfiguration($this->_iClientMR);
|
||
|
$this->_setLanguageId();
|
||
|
}
|
||
|
|
||
|
}
|
||
|
ModRewriteDebugger::add($this->_aParts, 'ModRewriteController::_extractRequestUri() $this->_aParts');
|
||
|
|
||
|
// loop parts array and remove existing 'front_content.php'
|
||
|
if ($this->_hasPartArrayItems()) {
|
||
|
foreach($this->_aParts as $p => $item) {
|
||
|
if ($item == 'front_content.php') {
|
||
|
unset($this->_aParts[$p]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// set parts property top null, if needed
|
||
|
if ($this->_hasPartArrayItems() == false) {
|
||
|
$this->_aParts = null;
|
||
|
}
|
||
|
|
||
|
// set artname to null if needed
|
||
|
if (!isset($this->_sArtName) || empty($this->_sArtName) || strlen($this->_sArtName) == 0) {
|
||
|
$this->_sArtName = null;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Tries to initialize the client id
|
||
|
*/
|
||
|
private function _initializeClientId()
|
||
|
{
|
||
|
global $client, $changeclient, $load_client;
|
||
|
|
||
|
$iClient = (isset($client) && (int) $client > 0) ? $client : 0;
|
||
|
$iChangeClient = (isset($changeclient) && (int) $changeclient > 0) ? $changeclient : 0;
|
||
|
$iLoadClient = (isset($load_client) && (int) $load_client > 0) ? $load_client : 0;
|
||
|
|
||
|
$this->_iClientMR = 0;
|
||
|
if ($iClient > 0 && $iChangeClient == 0) {
|
||
|
$this->_iClientMR = $iClient;
|
||
|
} elseif ($iChangeClient > 0) {
|
||
|
$this->_iClientMR = $iChangeClient;
|
||
|
} else {
|
||
|
$this->_iClientMR = $iLoadClient;
|
||
|
}
|
||
|
|
||
|
if ((int) $this->_iClientMR > 0) {
|
||
|
// set global client variable
|
||
|
$client = (int) $this->_iClientMR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Sets client id
|
||
|
*/
|
||
|
private function _setClientId()
|
||
|
{
|
||
|
global $client, $changeclient, $load_client;
|
||
|
|
||
|
if ($this->_hasPartArrayItems() == false || parent::getConfig('use_client') !== 1) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
$iClient = (isset($client) && (int) $client > 0) ? $client : 0;
|
||
|
$iLoadClient = (isset($load_client) && (int) $load_client > 0) ? $load_client : 0;
|
||
|
|
||
|
if (parent::getConfig('use_client_name') == 1) {
|
||
|
$changeclient = ModRewrite::getClientId(array_shift($this->_aParts));
|
||
|
$this->_iClientMR = $changeclient;
|
||
|
} else {
|
||
|
$changeclient = (int) array_shift($this->_aParts);
|
||
|
$this->_iClientMR = $changeclient;
|
||
|
}
|
||
|
|
||
|
if (empty($changeclient) || (int) $changeclient <= 0) {
|
||
|
$changeclient = $iLoadClient;
|
||
|
}
|
||
|
if ($iClient > 0 && $changeclient !== $iClient) {
|
||
|
// overwrite existing client variable
|
||
|
$this->_iClientMR = $changeclient;
|
||
|
$client = $changeclient;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Sets language id
|
||
|
*/
|
||
|
private function _setLanguageId()
|
||
|
{
|
||
|
global $lang, $changelang;
|
||
|
|
||
|
if ($this->_hasPartArrayItems() == false || parent::getConfig('use_language') !== 1) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (parent::getConfig('use_language_name') == 1) {
|
||
|
// thanks to Nicolas Dickinson for multi Client/Language BugFix
|
||
|
$changelang = ModRewrite::getLanguageId(array_shift($this->_aParts) , $this->_iClientMR);
|
||
|
} else {
|
||
|
$changelang = (int) array_shift($this->_aParts);
|
||
|
}
|
||
|
|
||
|
if ((int) $changelang > 0) {
|
||
|
$lang = $changelang;
|
||
|
$changelang = $changelang;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Sets path resolver and category id
|
||
|
*/
|
||
|
private function _setPathresolverSetting()
|
||
|
{
|
||
|
global $client, $lang, $load_lang, $idcat;
|
||
|
|
||
|
if ($this->_hasPartArrayItems() == false) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
$this->_sPath = '/' . implode('/', $this->_aParts) . '/';
|
||
|
|
||
|
if (!isset($lang) || (int) $lang <= 0) {
|
||
|
if ((int) $load_lang > 0) {
|
||
|
// load_client is set in frontend/config.php
|
||
|
$lang = (int) $load_lang;
|
||
|
} else {
|
||
|
// get client id from table
|
||
|
cInclude('classes', 'contenido/class.clientslang.php');
|
||
|
$clCol = new cApiClientLanguageCollection();
|
||
|
$clCol->setWhere('idclient', $client);
|
||
|
$clCol->query();
|
||
|
if ($clItem = $clCol->next()) {
|
||
|
$lang = $clItem->get('idlang');
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$idcat = (int) ModRewrite::getCatIdByUrlPath($this->_sPath);
|
||
|
|
||
|
if ($idcat == 0) {
|
||
|
// category couldn't resolved
|
||
|
$this->_bError = true;
|
||
|
$idcat = null;
|
||
|
} else {
|
||
|
// unset $this->_sPath if $idcat could set, otherwhise it would be resolved again.
|
||
|
unset($this->_sPath);
|
||
|
}
|
||
|
|
||
|
ModRewriteDebugger::add($idcat, 'ModRewriteController->_setPathresolverSetting $idcat');
|
||
|
ModRewriteDebugger::add($this->_sPath, 'ModRewriteController->_setPathresolverSetting $this->_sPath');
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Sets article id
|
||
|
*/
|
||
|
private function _setIdart()
|
||
|
{
|
||
|
global $idcat, $idart, $lang;
|
||
|
|
||
|
// startarticle name in url
|
||
|
if (parent::getConfig('add_startart_name_to_url') && isset($this->_sArtName)) {
|
||
|
if ($this->_sArtName == parent::getConfig('default_startart_name')) {
|
||
|
// stored articlename is the default one, remove it ModRewrite::getArtIdByWebsafeName()
|
||
|
// will find the real article name
|
||
|
$this->_sArtName = null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$idcat = (isset($idcat) && (int) $idcat > 0) ? $idcat : null;
|
||
|
$idart = (isset($idart) && (int) $idart > 0) ? $idart : null;
|
||
|
|
||
|
if ($idcat !== null && $this->_sArtName && $idart == null) {
|
||
|
// existing idcat with article name and no idart
|
||
|
$idart = ModRewrite::getArtIdByWebsafeName($this->_sArtName, $idcat, $lang);
|
||
|
} elseif ($idcat > 0 && $this->_sArtName == null && $idart == null) {
|
||
|
|
||
|
if (parent::getConfig('add_startart_name_to_url') && parent::getConfig('default_startart_name') == '') {
|
||
|
|
||
|
// existing idcat without article name and idart
|
||
|
cInclude('classes', 'class.article.php');
|
||
|
$artColl = new ArticleCollection(array('idcat' => $idcat, 'start' => 1));
|
||
|
if ($artItem = $artColl->startArticle()) {
|
||
|
$idart = $artItem->get('idart');
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
} elseif ($idcat == null && $idart == null && isset($this->_sArtName)) {
|
||
|
// no idcat and idart but article name
|
||
|
$idart = ModRewrite::getArtIdByWebsafeName($this->_sArtName);
|
||
|
}
|
||
|
|
||
|
if ($idart !== null && (!$idart || (int) $idart == 0)) {
|
||
|
if (parent::getConfig('redirect_invalid_article_to_errorsite') == 1) {
|
||
|
$this->_bError = true;
|
||
|
$idart = null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ModRewriteDebugger::add($idart, 'ModRewriteController->_setIdart $idart');
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Does post validation of the extracted data.
|
||
|
*
|
||
|
* One main goal of this function is to prevent duplicated content, which could happen, if
|
||
|
* the configuration 'startfromroot' is activated.
|
||
|
*/
|
||
|
private function _postValidation()
|
||
|
{
|
||
|
global $idcat, $idart, $client;
|
||
|
|
||
|
if ($this->_bError || $this->_bRoutingFound || !$this->_hasPartArrayItems()) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (parent::getConfig('startfromroot') == 1 && parent::getConfig('prevent_duplicated_content') == 1) {
|
||
|
|
||
|
// prevention of duplicated content if '/firstcat/' is directly requested!
|
||
|
|
||
|
$idcat = (isset($idcat) && (int) $idcat > 0) ? $idcat : null;
|
||
|
$idart = (isset($idart) && (int) $idart > 0) ? $idart : null;
|
||
|
|
||
|
// compose new parameter
|
||
|
$param = '';
|
||
|
if ($idcat) {
|
||
|
$param .= 'idcat=' . (int) $idcat;
|
||
|
}
|
||
|
if ($idart) {
|
||
|
$param .= ($param !== '') ? '&idart=' . (int) $idart : 'idart=' . (int) $idart;
|
||
|
}
|
||
|
|
||
|
if ($param == '') {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// set client language, if not set before
|
||
|
mr_setClientLanguageId($client);
|
||
|
|
||
|
//rebuild url
|
||
|
$url = mr_buildNewUrl('front_content.php?' . $param);
|
||
|
|
||
|
$aUrlComponents = @parse_url($this->_sIncommingUrl);
|
||
|
$incommingUrl = (isset($aUrlComponents['path'])) ? $aUrlComponents['path'] : '';
|
||
|
|
||
|
ModRewriteDebugger::add($url, 'ModRewriteController->_postValidation validate url');
|
||
|
ModRewriteDebugger::add($incommingUrl, 'ModRewriteController->_postValidation incommingUrl');
|
||
|
|
||
|
// now the new generated uri should be identical with the request uri
|
||
|
if ($incommingUrl !== $url) {
|
||
|
$this->_bError = true;
|
||
|
$idcat = null;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Parses the url using defined separators
|
||
|
*
|
||
|
* @param string $url Incoming url
|
||
|
* @return string Parsed url
|
||
|
*/
|
||
|
private function _parseUrl($url)
|
||
|
{
|
||
|
$this->_sResolvedUrl = $url;
|
||
|
|
||
|
$oMrUrlUtil = ModRewriteUrlUtil::getInstance();
|
||
|
$url = $oMrUrlUtil->toContenidoUrl($url);
|
||
|
|
||
|
return @parse_url($url);
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Returns state of parts property.
|
||
|
*
|
||
|
* @return bool True if $this->_aParts propery is an array and contains items
|
||
|
* @access private
|
||
|
*/
|
||
|
function _hasPartArrayItems()
|
||
|
{
|
||
|
if (is_array($this->_aParts) && count($this->_aParts) > 0) {
|
||
|
return true;
|
||
|
} else {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|