Файл: contao-3.5.8/system/modules/core/classes/Backend.php
Строк: 914
<?php
/**
* Contao Open Source CMS
*
* Copyright (c) 2005-2016 Leo Feyer
*
* @license LGPL-3.0+
*/
namespace Contao;
/**
* Provide methods to manage back end controllers.
*
* @property Ajax $objAjax
*
* @author Leo Feyer <https://github.com/leofeyer>
*/
abstract class Backend extends Controller
{
/**
* Load the database object
*/
protected function __construct()
{
parent::__construct();
$this->import('Database');
$this->setStaticUrls();
}
/**
* Return the current theme as string
*
* @return string The name of the theme
*/
public static function getTheme()
{
if (Config::get('coreOnlyMode'))
{
return 'default'; // see #6505
}
$theme = Config::get('backendTheme');
if ($theme != '' && $theme != 'default' && is_dir(TL_ROOT . '/system/themes/' . $theme))
{
return $theme;
}
return 'default';
}
/**
* Return the back end themes as array
*
* @return array An array of available back end themes
*/
public static function getThemes()
{
$arrReturn = array();
$arrThemes = scan(TL_ROOT . '/system/themes');
foreach ($arrThemes as $strTheme)
{
if (strncmp($strTheme, '.', 1) === 0 || !is_dir(TL_ROOT . '/system/themes/' . $strTheme))
{
continue;
}
$arrReturn[$strTheme] = $strTheme;
}
return $arrReturn;
}
/**
* Return the TinyMCE language
*
* @return string
*/
public static function getTinyMceLanguage()
{
$lang = $GLOBALS['TL_LANGUAGE'];
if ($lang == '')
{
return 'en';
}
$lang = str_replace('-', '_', $lang);
// The translation exists
if (file_exists(TL_ROOT . '/assets/tinymce4/langs/' . $lang . '.js'))
{
return $lang;
}
if (($short = substr($GLOBALS['TL_LANGUAGE'], 0, 2)) != $lang)
{
// Try the short tag, e.g. "de" instead of "de_CH"
if (file_exists(TL_ROOT . '/assets/tinymce4/langs/' . $short . '.js'))
{
return $short;
}
}
elseif (($long = $short . '_' . strtoupper($short)) != $lang)
{
// Try the long tag, e.g. "fr_FR" instead of "fr" (see #6952)
if (file_exists(TL_ROOT . '/assets/tinymce4/langs/' . $long . '.js'))
{
return $long;
}
}
// Fallback to English
return 'en';
}
/**
* Get the Ace code editor type from a file extension
*
* @param string $ext
*
* @return string
*/
public static function getAceType($ext)
{
switch ($ext)
{
case 'css':
case 'diff':
case 'html':
case 'ini':
case 'java':
case 'json':
case 'less':
case 'php':
case 'scss':
case 'mysql':
case 'sql':
case 'xml':
case 'yaml':
return $ext;
break;
case 'js':
case 'javascript':
return 'javascript';
break;
case 'md':
case 'markdown':
return 'markdown';
break;
case 'cgi':
case 'pl':
return 'perl';
break;
case 'py':
return 'python';
break;
case 'txt':
return 'text';
break;
case 'c': case 'cc': case 'cpp': case 'c++':
case 'h': case 'hh': case 'hpp': case 'h++':
return 'c_cpp';
break;
case 'html5':
case 'xhtml':
return 'php';
break;
case 'svg':
case 'svgz':
return 'xml';
break;
default:
return 'text';
break;
}
}
/**
* Return a list of TinyMCE templates as JSON string
*
* @return string
*/
public static function getTinyTemplates()
{
$strDir = Config::get('uploadPath') . '/tiny_templates';
if (!is_dir(TL_ROOT . '/' . $strDir))
{
return '';
}
$arrFiles = array();
$arrTemplates = scan(TL_ROOT . '/' . $strDir);
foreach ($arrTemplates as $strFile)
{
if (strncmp('.', $strFile, 1) !== 0 && is_file(TL_ROOT . '/' . $strDir . '/' . $strFile))
{
$arrFiles[] = '{ title: "' . $strFile . '", url: "' . $strDir . '/' . $strFile . '" }';
}
}
return implode(",n", $arrFiles) . "n";
}
/**
* Add the request token to the URL
*
* @param string $strRequest
* @param boolean $blnAddRef
* @param array $arrUnset
*
* @return string
*/
public static function addToUrl($strRequest, $blnAddRef=true, $arrUnset=array())
{
// Unset the "no back button" flag
$arrUnset[] = 'nb';
return parent::addToUrl($strRequest . (($strRequest != '') ? '&' : '') . 'rt=' . REQUEST_TOKEN, $blnAddRef, $arrUnset);
}
/**
* Handle "runonce" files
*
* @throws Exception
*/
protected function handleRunOnce()
{
$this->import('Files');
$arrFiles = array('system/runonce.php');
// Always scan all folders and not just the active modules (see #4200)
foreach (scan(TL_ROOT . '/system/modules') as $strModule)
{
if (strncmp($strModule, '.', 1) === 0 || !is_dir(TL_ROOT . '/system/modules/' . $strModule))
{
continue;
}
$arrFiles[] = 'system/modules/' . $strModule . '/config/runonce.php';
}
// Check whether a runonce file exists
foreach ($arrFiles as $strFile)
{
if (file_exists(TL_ROOT . '/' . $strFile))
{
try
{
include TL_ROOT . '/' . $strFile;
}
catch (Exception $e) {}
if (!$this->Files->delete($strFile))
{
throw new Exception("The $strFile file cannot be deleted. Please remove the file manually and correct the file permission settings on your server.");
}
$this->log("File $strFile ran once and has then been removed successfully", __METHOD__, TL_GENERAL);
}
}
}
/**
* Open a back end module and return it as HTML
*
* @param string $module
*
* @return string
*/
protected function getBackendModule($module)
{
$arrModule = array();
foreach ($GLOBALS['BE_MOD'] as &$arrGroup)
{
if (isset($arrGroup[$module]))
{
$arrModule =& $arrGroup[$module];
break;
}
}
$arrInactiveModules = ModuleLoader::getDisabled();
// Check whether the module is active
if (is_array($arrInactiveModules) && in_array($module, $arrInactiveModules))
{
$this->log('Attempt to access the inactive back end module "' . $module . '"', __METHOD__, TL_ACCESS);
$this->redirect('contao/main.php?act=error');
}
$this->import('BackendUser', 'User');
// Dynamically add the "personal data" module (see #4193)
if (Input::get('do') == 'login')
{
$arrModule = array('tables'=>array('tl_user'), 'callback'=>'ModuleUser');
}
// Check whether the current user has access to the current module
elseif ($module != 'undo' && !$this->User->hasAccess($module, 'modules'))
{
$this->log('Back end module "' . $module . '" was not allowed for user "' . $this->User->username . '"', __METHOD__, TL_ERROR);
$this->redirect('contao/main.php?act=error');
}
$arrTables = (array) $arrModule['tables'];
$strTable = Input::get('table') ?: $arrTables[0];
$id = (!Input::get('act') && Input::get('id')) ? Input::get('id') : $this->Session->get('CURRENT_ID');
// Store the current ID in the current session
if ($id != $this->Session->get('CURRENT_ID'))
{
$this->Session->set('CURRENT_ID', $id);
}
define('CURRENT_ID', (Input::get('table') ? $id : Input::get('id')));
$this->Template->headline = $GLOBALS['TL_LANG']['MOD'][$module][0];
// Add the module style sheet
if (isset($arrModule['stylesheet']))
{
foreach ((array) $arrModule['stylesheet'] as $stylesheet)
{
$GLOBALS['TL_CSS'][] = $stylesheet;
}
}
// Add module javascript
if (isset($arrModule['javascript']))
{
foreach ((array) $arrModule['javascript'] as $javascript)
{
$GLOBALS['TL_JAVASCRIPT'][] = $javascript;
}
}
$dc = null;
// Redirect if the current table does not belong to the current module
if ($strTable != '')
{
if (!in_array($strTable, $arrTables))
{
$this->log('Table "' . $strTable . '" is not allowed in module "' . $module . '"', __METHOD__, TL_ERROR);
$this->redirect('contao/main.php?act=error');
}
// Load the language and DCA file
System::loadLanguageFile($strTable);
$this->loadDataContainer($strTable);
// Include all excluded fields which are allowed for the current user
if ($GLOBALS['TL_DCA'][$strTable]['fields'])
{
foreach ($GLOBALS['TL_DCA'][$strTable]['fields'] as $k=>$v)
{
if ($v['exclude'])
{
if ($this->User->hasAccess($strTable.'::'.$k, 'alexf'))
{
if ($strTable == 'tl_user_group')
{
$GLOBALS['TL_DCA'][$strTable]['fields'][$k]['orig_exclude'] = $GLOBALS['TL_DCA'][$strTable]['fields'][$k]['exclude'];
}
$GLOBALS['TL_DCA'][$strTable]['fields'][$k]['exclude'] = false;
}
}
}
}
// Fabricate a new data container object
if ($GLOBALS['TL_DCA'][$strTable]['config']['dataContainer'] == '')
{
$this->log('Missing data container for table "' . $strTable . '"', __METHOD__, TL_ERROR);
trigger_error('Could not create a data container object', E_USER_ERROR);
}
$dataContainer = 'DC_' . $GLOBALS['TL_DCA'][$strTable]['config']['dataContainer'];
/** @var DataContainer $dc */
$dc = new $dataContainer($strTable, $arrModule);
}
// AJAX request
if ($_POST && Environment::get('isAjaxRequest'))
{
$this->objAjax->executePostActions($dc);
}
// Trigger the module callback
elseif (class_exists($arrModule['callback']))
{
/** @var Module $objCallback */
$objCallback = new $arrModule['callback']($dc);
$this->Template->main .= $objCallback->generate();
}
// Custom action (if key is not defined in config.php the default action will be called)
elseif (Input::get('key') && isset($arrModule[Input::get('key')]))
{
$objCallback = new $arrModule[Input::get('key')][0]();
$this->Template->main .= $objCallback->{$arrModule[Input::get('key')][1]}($dc);
// Add the name of the parent element
if (isset($_GET['table']) && in_array(Input::get('table'), $arrTables) && Input::get('table') != $arrTables[0])
{
if ($GLOBALS['TL_DCA'][$strTable]['config']['ptable'] != '')
{
$objRow = $this->Database->prepare("SELECT * FROM " . $GLOBALS['TL_DCA'][$strTable]['config']['ptable'] . " WHERE id=?")
->limit(1)
->execute(CURRENT_ID);
if ($objRow->title != '')
{
$this->Template->headline .= ' » ' . $objRow->title;
}
elseif ($objRow->name != '')
{
$this->Template->headline .= ' » ' . $objRow->name;
}
}
}
// Add the name of the submodule
$this->Template->headline .= ' » ' . sprintf($GLOBALS['TL_LANG'][$strTable][Input::get('key')][1], Input::get('id'));
}
// Default action
elseif (is_object($dc))
{
$act = Input::get('act');
if ($act == '' || $act == 'paste' || $act == 'select')
{
$act = ($dc instanceof listable) ? 'showAll' : 'edit';
}
switch ($act)
{
case 'delete':
case 'show':
case 'showAll':
case 'undo':
if (!$dc instanceof listable)
{
$this->log('Data container ' . $strTable . ' is not listable', __METHOD__, TL_ERROR);
trigger_error('The current data container is not listable', E_USER_ERROR);
}
break;
case 'create':
case 'cut':
case 'cutAll':
case 'copy':
case 'copyAll':
case 'move':
case 'edit':
if (!$dc instanceof editable)
{
$this->log('Data container ' . $strTable . ' is not editable', __METHOD__, TL_ERROR);
trigger_error('The current data container is not editable', E_USER_ERROR);
}
break;
}
$strFirst = null;
$strSecond = null;
// Handle child child tables (e.g. tl_style)
if (isset($GLOBALS['TL_DCA'][$strTable]['config']['ptable']))
{
$ptable = $GLOBALS['TL_DCA'][$strTable]['config']['ptable'];
if (in_array($ptable, $arrTables))
{
$this->loadDataContainer($ptable);
if (isset($GLOBALS['TL_DCA'][$ptable]['config']['ptable']))
{
$ftable = $GLOBALS['TL_DCA'][$ptable]['config']['ptable'];
if (in_array($ftable, $arrTables))
{
$strFirst = $ftable;
$strSecond = $ptable;
}
}
}
}
// Build the breadcrumb trail
if ($strFirst !== null && $strSecond !== null)
{
if (!isset($_GET['act']) || Input::get('act') == 'paste' && Input::get('mode') == 'create' || Input::get('act') == 'select' || Input::get('act') == 'editAll' || Input::get('act') == 'overrideAll')
{
if ($strTable == $strSecond)
{
$strQuery = "SELECT * FROM $strFirst WHERE id=?";
}
else
{
$strQuery = "SELECT * FROM $strFirst WHERE id=(SELECT pid FROM $strSecond WHERE id=?)";
}
}
else
{
if ($strTable == $strSecond)
{
$strQuery = "SELECT * FROM $strFirst WHERE id=(SELECT pid FROM $strSecond WHERE id=?)";
}
else
{
$strQuery = "SELECT * FROM $strFirst WHERE id=(SELECT pid FROM $strSecond WHERE id=(SELECT pid FROM $strTable WHERE id=?))";
}
}
// Add the first level name
$objRow = $this->Database->prepare($strQuery)
->limit(1)
->execute($dc->id);
if ($objRow->title != '')
{
$this->Template->headline .= ' » ' . $objRow->title;
}
elseif ($objRow->name != '')
{
$this->Template->headline .= ' » ' . $objRow->name;
}
if (isset($GLOBALS['TL_LANG']['MOD'][$strSecond]))
{
$this->Template->headline .= ' » ' . $GLOBALS['TL_LANG']['MOD'][$strSecond];
}
// Add the second level name
$objRow = $this->Database->prepare("SELECT * FROM $strSecond WHERE id=?")
->limit(1)
->execute(CURRENT_ID);
if ($objRow->title != '')
{
$this->Template->headline .= ' » ' . $objRow->title;
}
elseif ($objRow->name != '')
{
$this->Template->headline .= ' » ' . $objRow->name;
}
}
else
{
// Add the name of the parent element
if ($strTable && in_array($strTable, $arrTables) && $strTable != $arrTables[0])
{
if ($GLOBALS['TL_DCA'][$strTable]['config']['ptable'] != '')
{
$objRow = $this->Database->prepare("SELECT * FROM " . $GLOBALS['TL_DCA'][$strTable]['config']['ptable'] . " WHERE id=?")
->limit(1)
->execute(CURRENT_ID);
if ($objRow->title != '')
{
$this->Template->headline .= ' » ' . $objRow->title;
}
elseif ($objRow->name != '')
{
$this->Template->headline .= ' » ' . $objRow->name;
}
}
}
// Add the name of the submodule
if ($strTable && isset($GLOBALS['TL_LANG']['MOD'][$strTable]))
{
$this->Template->headline .= ' » ' . $GLOBALS['TL_LANG']['MOD'][$strTable];
}
}
// Add the current action
if (Input::get('act') == 'editAll')
{
$this->Template->headline .= ' » ' . $GLOBALS['TL_LANG']['MSC']['all'][0];
}
elseif (Input::get('act') == 'overrideAll')
{
$this->Template->headline .= ' » ' . $GLOBALS['TL_LANG']['MSC']['all_override'][0];
}
else
{
if (Input::get('id'))
{
if (Input::get('do') == 'files' || Input::get('do') == 'tpl_editor')
{
// Handle new folders (see #7980)
if (strpos(Input::get('id'), '__new__') !== false)
{
$this->Template->headline .= ' » ' . dirname(Input::get('id')) . ' » ' . $GLOBALS['TL_LANG'][$strTable]['new'][1];
}
else
{
$this->Template->headline .= ' » ' . Input::get('id');
}
}
elseif (is_array($GLOBALS['TL_LANG'][$strTable][$act]))
{
$this->Template->headline .= ' » ' . sprintf($GLOBALS['TL_LANG'][$strTable][$act][1], Input::get('id'));
}
}
elseif (Input::get('pid'))
{
if (Input::get('do') == 'files' || Input::get('do') == 'tpl_editor')
{
$this->Template->headline .= ' » ' . Input::get('pid');
}
elseif (is_array($GLOBALS['TL_LANG'][$strTable][$act]))
{
$this->Template->headline .= ' » ' . sprintf($GLOBALS['TL_LANG'][$strTable][$act][1], Input::get('pid'));
}
}
}
return $dc->$act();
}
return null;
}
/**
* Get all searchable pages and return them as array
*
* @param integer $pid
* @param string $domain
* @param boolean $blnIsSitemap
*
* @return array
*/
public static function findSearchablePages($pid=0, $domain='', $blnIsSitemap=false)
{
$time = Date::floorToMinute();
$objDatabase = Database::getInstance();
// Get published pages
$objPages = $objDatabase->prepare("SELECT * FROM tl_page WHERE pid=? AND (start='' OR start<='$time') AND (stop='' OR stop>'" . ($time + 60) . "') AND published='1' ORDER BY sorting")
->execute($pid);
if ($objPages->numRows < 1)
{
return array();
}
// Fallback domain
if ($domain == '')
{
$domain = Environment::get('base');
}
$arrPages = array();
$objRegistry = ModelRegistry::getInstance();
// Recursively walk through all subpages
while ($objPages->next())
{
$objPage = $objRegistry->fetch('tl_page', $objPages->id);
if ($objPage === null)
{
$objPage = new PageModel($objPages);
}
if ($objPage->type == 'regular')
{
// Searchable and not protected
if ((!$objPage->noSearch || $blnIsSitemap) && (!$objPage->protected || Config::get('indexProtected') && (!$blnIsSitemap || $objPage->sitemap == 'map_always')) && (!$blnIsSitemap || $objPage->sitemap != 'map_never'))
{
// Published
if ($objPage->published && ($objPage->start == '' || $objPage->start <= $time) && ($objPage->stop == '' || $objPage->stop > ($time + 60)))
{
$feUrl = $objPage->getFrontendUrl();
if (strncmp($feUrl, 'http://', 7) !== 0 && strncmp($feUrl, 'https://', 8) !== 0)
{
$feUrl = $domain . $feUrl;
}
$arrPages[] = $feUrl;
// Get articles with teaser
$objArticles = $objDatabase->prepare("SELECT * FROM tl_article WHERE pid=? AND (start='' OR start<='$time') AND (stop='' OR stop>'" . ($time + 60) . "') AND published='1' AND showTeaser='1' ORDER BY sorting")
->execute($objPages->id);
if ($objArticles->numRows)
{
$feUrl = $objPage->getFrontendUrl('/articles/%s');
if (strncmp($feUrl, 'http://', 7) !== 0 && strncmp($feUrl, 'https://', 8) !== 0)
{
$feUrl = $domain . $feUrl;
}
while ($objArticles->next())
{
$arrPages[] = sprintf($feUrl, (($objArticles->alias != '' && !Config::get('disableAlias')) ? $objArticles->alias : $objArticles->id));
}
}
}
}
}
// Get subpages
if ((!$objPage->protected || Config::get('indexProtected')) && ($arrSubpages = static::findSearchablePages($objPage->id, $domain, $blnIsSitemap)) != false)
{
$arrPages = array_merge($arrPages, $arrSubpages);
}
}
return $arrPages;
}
/**
* Add the file meta information to the request
*
* @param string $strUuid
* @param string $strPtable
* @param integer $intPid
*/
public static function addFileMetaInformationToRequest($strUuid, $strPtable, $intPid)
{
$objFile = FilesModel::findByUuid($strUuid);
if ($objFile === null)
{
return;
}
$arrMeta = deserialize($objFile->meta);
if (empty($arrMeta))
{
return;
}
$objPage = null;
$db = Database::getInstance();
switch ($strPtable)
{
case 'tl_article':
$objPage = $db->prepare("SELECT * FROM tl_page WHERE id=(SELECT pid FROM tl_article WHERE id=?)")
->execute($intPid);
break;
case 'tl_news':
$objPage = $db->prepare("SELECT * FROM tl_page WHERE id=(SELECT jumpTo FROM tl_news_archive WHERE id=(SELECT pid FROM tl_news WHERE id=?))")
->execute($intPid);
break;
case 'tl_news_archive':
$objPage = $db->prepare("SELECT * FROM tl_page WHERE id=(SELECT jumpTo FROM tl_news_archive WHERE id=?)")
->execute($intPid);
break;
case 'tl_calendar_events':
$objPage = $db->prepare("SELECT * FROM tl_page WHERE id=(SELECT jumpTo FROM tl_calendar WHERE id=(SELECT pid FROM tl_calendar_events WHERE id=?))")
->execute($intPid);
break;
case 'tl_calendar':
$objPage = $db->prepare("SELECT * FROM tl_page WHERE id=(SELECT jumpTo FROM tl_calendar WHERE id=?)")
->execute($intPid);
break;
case 'tl_faq_category':
$objPage = $db->prepare("SELECT * FROM tl_page WHERE id=(SELECT jumpTo FROM tl_faq_category WHERE id=?)")
->execute($intPid);
break;
default:
// HOOK: support custom modules
if (isset($GLOBALS['TL_HOOKS']['addFileMetaInformationToRequest']) && is_array($GLOBALS['TL_HOOKS']['addFileMetaInformationToRequest']))
{
foreach ($GLOBALS['TL_HOOKS']['addFileMetaInformationToRequest'] as $callback)
{
if (($val = System::importStatic($callback[0])->{$callback[1]}($strPtable, $intPid)) !== false)
{
$objPage = $val;
}
}
}
break;
}
if ($objPage === null || $objPage->numRows < 1)
{
return;
}
$objModel = new PageModel();
$objModel->setRow($objPage->row());
$objModel->loadDetails();
// Convert the language to a locale (see #5678)
$strLanguage = str_replace('-', '_', $objModel->rootLanguage);
if (isset($arrMeta[$strLanguage]))
{
if (Input::post('alt') == '' && !empty($arrMeta[$strLanguage]['title']))
{
Input::setPost('alt', $arrMeta[$strLanguage]['title']);
}
if (Input::post('caption') == '' && !empty($arrMeta[$strLanguage]['caption']))
{
Input::setPost('caption', $arrMeta[$strLanguage]['caption']);
}
}
}
/**
* Add a breadcrumb menu to the page tree
*
* @param string $strKey
*
* @throws RuntimeException
*/
public static function addPagesBreadcrumb($strKey='tl_page_node')
{
$objSession = Session::getInstance();
// Set a new node
if (isset($_GET['node']))
{
// Check the path (thanks to Arnaud Buchoux)
if (Validator::isInsecurePath(Input::get('node', true)))
{
throw new RuntimeException('Insecure path ' . Input::get('node', true));
}
$objSession->set($strKey, Input::get('node', true));
Controller::redirect(preg_replace('/&node=[^&]*/', '', Environment::get('request')));
}
$intNode = $objSession->get($strKey);
if ($intNode < 1)
{
return;
}
// Check the path (thanks to Arnaud Buchoux)
if (Validator::isInsecurePath($intNode))
{
throw new RuntimeException('Insecure path ' . $intNode);
}
$arrIds = array();
$arrLinks = array();
$objUser = BackendUser::getInstance();
// Generate breadcrumb trail
if ($intNode)
{
$intId = $intNode;
$objDatabase = Database::getInstance();
do
{
$objPage = $objDatabase->prepare("SELECT * FROM tl_page WHERE id=?")
->limit(1)
->execute($intId);
if ($objPage->numRows < 1)
{
// Currently selected page does not exits
if ($intId == $intNode)
{
$objSession->set($strKey, 0);
return;
}
break;
}
$arrIds[] = $intId;
// No link for the active page
if ($objPage->id == $intNode)
{
$arrLinks[] = Backend::addPageIcon($objPage->row(), '', null, '', true) . ' ' . $objPage->title;
}
else
{
$arrLinks[] = Backend::addPageIcon($objPage->row(), '', null, '', true) . ' <a href="' . Controller::addToUrl('node='.$objPage->id) . '" title="'.specialchars($GLOBALS['TL_LANG']['MSC']['selectNode']).'">' . $objPage->title . '</a>';
}
// Do not show the mounted pages
if (!$objUser->isAdmin && $objUser->hasAccess($objPage->id, 'pagemounts'))
{
break;
}
$intId = $objPage->pid;
}
while ($intId > 0 && $objPage->type != 'root');
}
// Check whether the node is mounted
if (!$objUser->hasAccess($arrIds, 'pagemounts'))
{
$objSession->set($strKey, 0);
System::log('Page ID '.$intNode.' was not mounted', __METHOD__, TL_ERROR);
Controller::redirect('contao/main.php?act=error');
}
// Limit tree
$GLOBALS['TL_DCA']['tl_page']['list']['sorting']['root'] = array($intNode);
// Add root link
$arrLinks[] = '<img src="' . TL_FILES_URL . 'system/themes/' . Backend::getTheme() . '/images/pagemounts.gif" width="18" height="18" alt=""> <a href="' . Controller::addToUrl('node=0') . '" title="'.specialchars($GLOBALS['TL_LANG']['MSC']['selectAllNodes']).'">' . $GLOBALS['TL_LANG']['MSC']['filterAll'] . '</a>';
$arrLinks = array_reverse($arrLinks);
// Insert breadcrumb menu
$GLOBALS['TL_DCA']['tl_page']['list']['sorting']['breadcrumb'] .= '
<ul id="tl_breadcrumb">
<li>' . implode(' > </li><li>', $arrLinks) . '</li>
</ul>';
}
/**
* Add an image to each page in the tree
*
* @param array $row
* @param string $label
* @param DataContainer $dc
* @param string $imageAttribute
* @param boolean $blnReturnImage
* @param boolean $blnProtected
*
* @return string
*/
public static function addPageIcon($row, $label, DataContainer $dc=null, $imageAttribute='', $blnReturnImage=false, $blnProtected=false)
{
if ($blnProtected)
{
$row['protected'] = true;
}
$image = Controller::getPageStatusIcon((object) $row);
$imageAttribute = trim($imageAttribute . ' data-icon="' . Controller::getPageStatusIcon((object) array_merge($row, array('published'=>'1'))) . '" data-icon-disabled="' . Controller::getPageStatusIcon((object) array_merge($row, array('published'=>''))) . '"');
// Return the image only
if ($blnReturnImage)
{
return Image::getHtml($image, '', $imageAttribute);
}
// Mark root pages
if ($row['type'] == 'root' || Input::get('do') == 'article')
{
$label = '<strong>' . $label . '</strong>';
}
// Add the breadcrumb link
$label = '<a href="' . Controller::addToUrl('node='.$row['id']) . '" title="'.specialchars($GLOBALS['TL_LANG']['MSC']['selectNode']).'">' . $label . '</a>';
// Return the image
return '<a href="contao/main.php?do=feRedirect&page='.$row['id'].'" title="'.specialchars($GLOBALS['TL_LANG']['MSC']['view']).'"' . (($dc->table != 'tl_page') ? ' class="tl_gray"' : '') . ' target="_blank">'.Image::getHtml($image, '', $imageAttribute).'</a> '.$label;
}
/**
* Add a breadcrumb menu to the file tree
*
* @param string $strKey
*
* @throws RuntimeException
*/
public static function addFilesBreadcrumb($strKey='tl_files_node')
{
$objSession = Session::getInstance();
// Set a new node
if (isset($_GET['node']))
{
// Check the path (thanks to Arnaud Buchoux)
if (Validator::isInsecurePath(Input::get('node', true)))
{
throw new RuntimeException('Insecure path ' . Input::get('node', true));
}
$objSession->set($strKey, Input::get('node', true));
Controller::redirect(preg_replace('/(&|?)node=[^&]*/', '', Environment::get('request')));
}
$strNode = $objSession->get($strKey);
if ($strNode == '')
{
return;
}
// Check the path (thanks to Arnaud Buchoux)
if (Validator::isInsecurePath($strNode))
{
throw new RuntimeException('Insecure path ' . $strNode);
}
// Currently selected folder does not exist
if (!is_dir(TL_ROOT . '/' . $strNode))
{
$objSession->set($strKey, '');
return;
}
$objUser = BackendUser::getInstance();
$strPath = Config::get('uploadPath');
$arrNodes = explode('/', preg_replace('/^' . preg_quote(Config::get('uploadPath'), '/') . '//', '', $strNode));
$arrLinks = array();
// Add root link
$arrLinks[] = '<img src="' . TL_FILES_URL . 'system/themes/' . Backend::getTheme() . '/images/filemounts.gif" width="18" height="18" alt=""> <a href="' . Controller::addToUrl('node=') . '" title="'.specialchars($GLOBALS['TL_LANG']['MSC']['selectAllNodes']).'">' . $GLOBALS['TL_LANG']['MSC']['filterAll'] . '</a>';
// Generate breadcrumb trail
foreach ($arrNodes as $strFolder)
{
$strPath .= '/' . $strFolder;
// Do not show pages which are not mounted
if (!$objUser->hasAccess($strPath, 'filemounts'))
{
continue;
}
// No link for the active folder
if ($strPath == $strNode)
{
$arrLinks[] = '<img src="' . TL_FILES_URL . 'system/themes/' . Backend::getTheme() . '/images/folderC.gif" width="18" height="18" alt=""> ' . $strFolder;
}
else
{
$arrLinks[] = '<img src="' . TL_FILES_URL . 'system/themes/' . Backend::getTheme() . '/images/folderC.gif" width="18" height="18" alt=""> <a href="' . Controller::addToUrl('node='.$strPath) . '" title="'.specialchars($GLOBALS['TL_LANG']['MSC']['selectNode']).'">' . $strFolder . '</a>';
}
}
// Check whether the node is mounted
if (!$objUser->hasAccess($strNode, 'filemounts'))
{
$objSession->set($strKey, '');
System::log('Folder ID '.$strNode.' was not mounted', __METHOD__, TL_ERROR);
Controller::redirect('contao/main.php?act=error');
}
// Limit tree
$GLOBALS['TL_DCA']['tl_files']['list']['sorting']['root'] = array($strNode);
// Insert breadcrumb menu
$GLOBALS['TL_DCA']['tl_files']['list']['sorting']['breadcrumb'] .= '
<ul id="tl_breadcrumb">
<li>' . implode(' > </li><li>', $arrLinks) . '</li>
</ul>';
}
/**
* Get all allowed pages and return them as string
*
* @return string
*/
public function createPageList()
{
$this->import('BackendUser', 'User');
if ($this->User->isAdmin)
{
return $this->doCreatePageList();
}
$return = '';
$processed = array();
foreach ($this->eliminateNestedPages($this->User->pagemounts) as $page)
{
$objPage = PageModel::findWithDetails($page);
// Root page mounted
if ($objPage->type == 'root')
{
$title = $objPage->title;
$start = $objPage->id;
}
// Regular page mounted
else
{
$title = $objPage->rootTitle;
$start = $objPage->rootId;
}
// Do not process twice
if (in_array($start, $processed))
{
continue;
}
// Skip websites that run under a different domain (see #2387)
if ($objPage->domain && $objPage->domain != Environment::get('host'))
{
continue;
}
$processed[] = $start;
$return .= '<optgroup label="' . $title . '">' . $this->doCreatePageList($start) . '</optgroup>';
}
return $return;
}
/**
* Recursively get all allowed pages and return them as string
*
* @param integer $intId
* @param integer $level
*
* @return string
*/
protected function doCreatePageList($intId=0, $level=-1)
{
$objPages = $this->Database->prepare("SELECT id, title, type, dns FROM tl_page WHERE pid=? ORDER BY sorting")
->execute($intId);
if ($objPages->numRows < 1)
{
return '';
}
++$level;
$strOptions = '';
while ($objPages->next())
{
if ($objPages->type == 'root')
{
// Skip websites that run under a different domain
if ($objPages->dns && $objPages->dns != Environment::get('host'))
{
continue;
}
$strOptions .= '<optgroup label="' . $objPages->title . '">';
$strOptions .= $this->doCreatePageList($objPages->id, -1);
$strOptions .= '</optgroup>';
}
else
{
$strOptions .= sprintf('<option value="{{link_url::%s}}"%s>%s%s</option>', $objPages->id, (('{{link_url::' . $objPages->id . '}}' == Input::get('value')) ? ' selected="selected"' : ''), str_repeat(' ', $level), specialchars($objPages->title));
$strOptions .= $this->doCreatePageList($objPages->id, $level);
}
}
return $strOptions;
}
/**
* Get all allowed files and return them as string
*
* @param string $strFilter
* @param boolean $filemount
*
* @return string
*/
public function createFileList($strFilter='', $filemount=false)
{
// Backwards compatibility
if ($strFilter === true)
{
$strFilter = 'gif,jpg,jpeg,png';
}
$this->import('BackendUser', 'User');
if ($this->User->isAdmin)
{
return $this->doCreateFileList(Config::get('uploadPath'), -1, $strFilter);
}
$return = '';
$processed = array();
// Set custom filemount
if ($filemount)
{
$this->User->filemounts = array($filemount);
}
// Limit nodes to the filemounts of the user
foreach ($this->eliminateNestedPaths($this->User->filemounts) as $path)
{
if (in_array($path, $processed))
{
continue;
}
$processed[] = $path;
$return .= $this->doCreateFileList($path, -1, $strFilter);
}
return $return;
}
/**
* Recursively get all allowed files and return them as string
*
* @param string $strFolder
* @param integer $level
* @param string $strFilter
*
* @return string
*/
protected function doCreateFileList($strFolder=null, $level=-1, $strFilter='')
{
// Backwards compatibility
if ($strFilter === true)
{
$strFilter = 'gif,jpg,jpeg,png';
}
$arrPages = scan(TL_ROOT . '/' . $strFolder);
// Empty folder
if (empty($arrPages))
{
return '';
}
// Protected folder
if (array_search('.htaccess', $arrPages) !== false)
{
return '';
}
++$level;
$strFolders = '';
$strFiles = '';
// Recursively list all files and folders
foreach ($arrPages as $strFile)
{
if (strncmp($strFile, '.', 1) === 0)
{
continue;
}
// Folders
if (is_dir(TL_ROOT . '/' . $strFolder . '/' . $strFile))
{
$strFolders .= $this->doCreateFileList($strFolder . '/' . $strFile, $level, $strFilter);
}
// Files
else
{
// Filter images
if ($strFilter != '' && !preg_match('/.(' . str_replace(',', '|', $strFilter) . ')$/i', $strFile))
{
continue;
}
$strFiles .= sprintf('<option value="%s"%s>%s</option>', $strFolder . '/' . $strFile, (($strFolder . '/' . $strFile == Input::get('value')) ? ' selected="selected"' : ''), specialchars($strFile));
}
}
if (strlen($strFiles))
{
return '<optgroup label="' . specialchars($strFolder) . '">' . $strFiles . $strFolders . '</optgroup>';
}
return $strFiles . $strFolders;
}
}