Файл: contao-3.5.8/system/modules/core/drivers/DC_File.php
Строк: 331
<?php
/**
* Contao Open Source CMS
*
* Copyright (c) 2005-2016 Leo Feyer
*
* @license LGPL-3.0+
*/
namespace Contao;
/**
* Provide methods to edit the local configuration file.
*
* @author Leo Feyer <https://github.com/leofeyer>
*/
class DC_File extends DataContainer implements editable
{
/**
* Initialize the object
*
* @param string $strTable
*/
public function __construct($strTable)
{
parent::__construct();
$this->intId = Input::get('id');
// Check whether the table is defined
if ($strTable == '' || !isset($GLOBALS['TL_DCA'][$strTable]))
{
$this->log('Could not load data container configuration for "' . $strTable . '"', __METHOD__, TL_ERROR);
trigger_error('Could not load data container configuration', E_USER_ERROR);
}
// Build object from global configuration array
$this->strTable = $strTable;
// Call onload_callback (e.g. to check permissions)
if (is_array($GLOBALS['TL_DCA'][$this->strTable]['config']['onload_callback']))
{
foreach ($GLOBALS['TL_DCA'][$this->strTable]['config']['onload_callback'] as $callback)
{
if (is_array($callback))
{
$this->import($callback[0]);
$this->{$callback[0]}->{$callback[1]}($this);
}
elseif (is_callable($callback))
{
$callback($this);
}
}
}
}
/**
* Automatically switch to edit mode
*
* @return string
*/
public function create()
{
return $this->edit();
}
/**
* Automatically switch to edit mode
*
* @return string
*/
public function cut()
{
return $this->edit();
}
/**
* Automatically switch to edit mode
*
* @return string
*/
public function copy()
{
return $this->edit();
}
/**
* Automatically switch to edit mode
*
* @return string
*/
public function move()
{
return $this->edit();
}
/**
* Auto-generate a form to edit the local configuration file
*
* @return string
*/
public function edit()
{
$return = '';
$ajaxId = null;
if (Environment::get('isAjaxRequest'))
{
$ajaxId = func_get_arg(1);
}
// Build an array from boxes and rows
$this->strPalette = $this->getPalette();
$boxes = trimsplit(';', $this->strPalette);
$legends = array();
if (!empty($boxes))
{
foreach ($boxes as $k=>$v)
{
$boxes[$k] = trimsplit(',', $v);
foreach ($boxes[$k] as $kk=>$vv)
{
if (preg_match('/^[.*]$/', $vv))
{
continue;
}
if (preg_match('/^{.*}$/', $vv))
{
$legends[$k] = substr($vv, 1, -1);
unset($boxes[$k][$kk]);
}
elseif ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$vv]['exclude'] || !is_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$vv]))
{
unset($boxes[$k][$kk]);
}
}
// Unset a box if it does not contain any fields
if (empty($boxes[$k]))
{
unset($boxes[$k]);
}
}
// Render boxes
$class = 'tl_tbox';
$fs = $this->Session->get('fieldset_states');
$blnIsFirst = true;
foreach ($boxes as $k=>$v)
{
$strAjax = '';
$blnAjax = false;
$key = '';
$cls = '';
$legend = '';
if (isset($legends[$k]))
{
list($key, $cls) = explode(':', $legends[$k]);
$legend = "n" . '<legend onclick="AjaxRequest.toggleFieldset(this, '' . $key . '', '' . $this->strTable . '')">' . (isset($GLOBALS['TL_LANG'][$this->strTable][$key]) ? $GLOBALS['TL_LANG'][$this->strTable][$key] : $key) . '</legend>';
}
if (isset($fs[$this->strTable][$key]))
{
$class .= ($fs[$this->strTable][$key] ? '' : ' collapsed');
}
else
{
$class .= (($cls && $legend) ? ' ' . $cls : '');
}
$return .= "nn" . '<fieldset' . ($key ? ' id="pal_'.$key.'"' : '') . ' class="' . $class . ($legend ? '' : ' nolegend') . '">' . $legend;
// Build rows of the current box
foreach ($v as $vv)
{
if ($vv == '[EOF]')
{
if ($blnAjax && Environment::get('isAjaxRequest'))
{
return $strAjax . '<input type="hidden" name="FORM_FIELDS[]" value="'.specialchars($this->strPalette).'">';
}
$blnAjax = false;
$return .= "n " . '</div>';
continue;
}
if (preg_match('/^[.*]$/', $vv))
{
$thisId = 'sub_' . substr($vv, 1, -1);
$blnAjax = ($ajaxId == $thisId && Environment::get('isAjaxRequest')) ? true : false;
$return .= "n " . '<div id="'.$thisId.'">';
continue;
}
$this->strField = $vv;
$this->strInputName = $vv;
$this->varValue = Config::get($this->strField);
// Handle entities
if ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$this->strField]['inputType'] == 'text' || $GLOBALS['TL_DCA'][$this->strTable]['fields'][$this->strField]['inputType'] == 'textarea')
{
if ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$this->strField]['eval']['multiple'])
{
$this->varValue = deserialize($this->varValue);
}
if (!is_array($this->varValue))
{
$this->varValue = htmlspecialchars($this->varValue);
}
else
{
foreach ($this->varValue as $k=>$v)
{
$this->varValue[$k] = htmlspecialchars($v);
}
}
}
// Autofocus the first field
if ($blnIsFirst && $GLOBALS['TL_DCA'][$this->strTable]['fields'][$this->strField]['inputType'] == 'text')
{
$GLOBALS['TL_DCA'][$this->strTable]['fields'][$this->strField]['eval']['autofocus'] = 'autofocus';
$blnIsFirst = false;
}
// Call load_callback
if (is_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$this->strField]['load_callback']))
{
foreach ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$this->strField]['load_callback'] as $callback)
{
if (is_array($callback))
{
$this->import($callback[0]);
$this->varValue = $this->{$callback[0]}->{$callback[1]}($this->varValue, $this);
}
elseif (is_callable($callback))
{
$this->varValue = $callback($this->varValue, $this);
}
}
}
// Build row
$blnAjax ? $strAjax .= $this->row() : $return .= $this->row();
}
$class = 'tl_box';
$return .= "n" . '</fieldset>';
}
}
$this->import('Files');
// Check whether the target file is writeable
if (!$this->Files->is_writeable('system/config/localconfig.php'))
{
Message::addError(sprintf($GLOBALS['TL_LANG']['ERR']['notWriteable'], 'system/config/localconfig.php'));
}
// Submit buttons
$arrButtons = array();
$arrButtons['save'] = '<input type="submit" name="save" id="save" class="tl_submit" accesskey="s" value="'.specialchars($GLOBALS['TL_LANG']['MSC']['save']).'">';
$arrButtons['saveNclose'] = '<input type="submit" name="saveNclose" id="saveNclose" class="tl_submit" accesskey="c" value="'.specialchars($GLOBALS['TL_LANG']['MSC']['saveNclose']).'">';
// Call the buttons_callback (see #4691)
if (is_array($GLOBALS['TL_DCA'][$this->strTable]['edit']['buttons_callback']))
{
foreach ($GLOBALS['TL_DCA'][$this->strTable]['edit']['buttons_callback'] as $callback)
{
if (is_array($callback))
{
$this->import($callback[0]);
$arrButtons = $this->{$callback[0]}->{$callback[1]}($arrButtons, $this);
}
elseif (is_callable($callback))
{
$arrButtons = $callback($arrButtons, $this);
}
}
}
// Add the buttons and end the form
$return .= '
</div>
<div class="tl_formbody_submit">
<div class="tl_submit_container">
' . implode(' ', $arrButtons) . '
</div>
</div>
</form>
<script>
window.addEvent('domready', function() {
Theme.focusInput("'.$this->strTable.'");
});
</script>';
// Begin the form (-> DO NOT CHANGE THIS ORDER -> this way the onsubmit attribute of the form can be changed by a field)
$return = '
<div id="tl_buttons">
<a href="'.$this->getReferer(true).'" class="header_back" title="'.specialchars($GLOBALS['TL_LANG']['MSC']['backBTTitle']).'" accesskey="b" onclick="Backend.getScrollOffset()">'.$GLOBALS['TL_LANG']['MSC']['backBT'].'</a>
</div>
'.Message::generate().'
<form action="'.ampersand(Environment::get('request'), true).'" id="'.$this->strTable.'" class="tl_form" method="post"'.(!empty($this->onsubmit) ? ' onsubmit="'.implode(' ', $this->onsubmit).'"' : '').'>
<div class="tl_formbody_edit">
<input type="hidden" name="FORM_SUBMIT" value="'.specialchars($this->strTable).'">
<input type="hidden" name="REQUEST_TOKEN" value="'.REQUEST_TOKEN.'">
<input type="hidden" name="FORM_FIELDS[]" value="'.specialchars($this->strPalette).'">'.($this->noReload ? '
<p class="tl_error">'.$GLOBALS['TL_LANG']['ERR']['general'].'</p>' : '').$return;
// Reload the page to prevent _POST variables from being sent twice
if (Input::post('FORM_SUBMIT') == $this->strTable && !$this->noReload)
{
// Call onsubmit_callback
if (is_array($GLOBALS['TL_DCA'][$this->strTable]['config']['onsubmit_callback']))
{
foreach ($GLOBALS['TL_DCA'][$this->strTable]['config']['onsubmit_callback'] as $callback)
{
if (is_array($callback))
{
$this->import($callback[0]);
$this->{$callback[0]}->{$callback[1]}($this);
}
elseif (is_callable($callback))
{
$callback($this);
}
}
}
// Reload
if (Input::post('saveNclose'))
{
Message::reset();
System::setCookie('BE_PAGE_OFFSET', 0, 0);
$this->redirect($this->getReferer());
}
$this->reload();
}
// Set the focus if there is an error
if ($this->noReload)
{
$return .= '
<script>
window.addEvent('domready', function() {
Backend.vScrollTo(($('' . $this->strTable . '').getElement('label.error').getPosition().y - 20));
});
</script>';
}
return $return;
}
/**
* Save the current value
*
* @param mixed $varValue
*/
protected function save($varValue)
{
if (Input::post('FORM_SUBMIT') != $this->strTable)
{
return;
}
$arrData = $GLOBALS['TL_DCA'][$this->strTable]['fields'][$this->strField];
// Make sure that checkbox values are boolean
if ($arrData['inputType'] == 'checkbox' && !$arrData['eval']['multiple'])
{
$varValue = $varValue ? true : false;
}
if ($varValue != '')
{
// Convert binary UUIDs (see #6893)
if ($arrData['inputType'] == 'fileTree')
{
$varValue = deserialize($varValue);
if (!is_array($varValue))
{
$varValue = StringUtil::binToUuid($varValue);
}
else
{
$varValue = serialize(array_map('StringUtil::binToUuid', $varValue));
}
}
// Convert date formats into timestamps
if ($varValue != '' && in_array($arrData['eval']['rgxp'], array('date', 'time', 'datim')))
{
$objDate = new Date($varValue, Date::getFormatFromRgxp($arrData['eval']['rgxp']));
$varValue = $objDate->tstamp;
}
// Handle entities
if ($arrData['inputType'] == 'text' || $arrData['inputType'] == 'textarea')
{
$varValue = deserialize($varValue);
if (!is_array($varValue))
{
$varValue = StringUtil::restoreBasicEntities($varValue);
}
else
{
$varValue = serialize(array_map('StringUtil::restoreBasicEntities', $varValue));
}
}
}
// Trigger the save_callback
if (is_array($arrData['save_callback']))
{
foreach ($arrData['save_callback'] as $callback)
{
if (is_array($callback))
{
$this->import($callback[0]);
$varValue = $this->{$callback[0]}->{$callback[1]}($varValue, $this);
}
elseif (is_callable($callback))
{
$varValue = $callback($varValue, $this);
}
}
}
$strCurrent = $this->varValue;
// Handle arrays and strings
if (is_array($strCurrent))
{
$strCurrent = serialize($strCurrent);
}
elseif (is_string($strCurrent))
{
$strCurrent = html_entity_decode($this->varValue, ENT_QUOTES, Config::get('characterSet'));
}
// Save the value if there was no error
if ((strlen($varValue) || !$arrData['eval']['doNotSaveEmpty']) && $strCurrent != $varValue)
{
Config::persist($this->strField, $varValue);
$deserialize = deserialize($varValue);
$prior = is_bool(Config::get($this->strField)) ? (Config::get($this->strField) ? 'true' : 'false') : Config::get($this->strField);
// Add a log entry
if (!is_array(deserialize($prior)) && !is_array($deserialize))
{
if ($arrData['inputType'] == 'password' || $arrData['inputType'] == 'textStore')
{
$this->log('The global configuration variable "'.$this->strField.'" has been changed', __METHOD__, TL_CONFIGURATION);
}
else
{
$this->log('The global configuration variable "'.$this->strField.'" has been changed from "'.$prior.'" to "'.$varValue.'"', __METHOD__, TL_CONFIGURATION);
}
}
// Set the new value so the input field can show it
$this->varValue = $deserialize;
Config::set($this->strField, $deserialize);
}
}
/**
* Return the name of the current palette
*
* @return string
*/
public function getPalette()
{
$palette = 'default';
$strPalette = $GLOBALS['TL_DCA'][$this->strTable]['palettes'][$palette];
// Check whether there are selector fields
if (!empty($GLOBALS['TL_DCA'][$this->strTable]['palettes']['__selector__']))
{
$sValues = array();
$subpalettes = array();
foreach ($GLOBALS['TL_DCA'][$this->strTable]['palettes']['__selector__'] as $name)
{
$trigger = Config::get($name);
// Overwrite the trigger if the page is not reloaded
if (Input::post('FORM_SUBMIT') == $this->strTable)
{
$key = (Input::get('act') == 'editAll') ? $name.'_'.$this->intId : $name;
if (!$GLOBALS['TL_DCA'][$this->strTable]['fields'][$name]['eval']['submitOnChange'])
{
$trigger = Input::post($key);
}
}
if ($trigger != '')
{
if ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$name]['inputType'] == 'checkbox' && !$GLOBALS['TL_DCA'][$this->strTable]['fields'][$name]['eval']['multiple'])
{
$sValues[] = $name;
// Look for a subpalette
if (strlen($GLOBALS['TL_DCA'][$this->strTable]['subpalettes'][$name]))
{
$subpalettes[$name] = $GLOBALS['TL_DCA'][$this->strTable]['subpalettes'][$name];
}
}
else
{
$sValues[] = $trigger;
$key = $name .'_'. $trigger;
// Look for a subpalette
if (strlen($GLOBALS['TL_DCA'][$this->strTable]['subpalettes'][$key]))
{
$subpalettes[$name] = $GLOBALS['TL_DCA'][$this->strTable]['subpalettes'][$key];
}
}
}
}
// Build possible palette names from the selector values
if (!count($sValues))
{
$names = array('default');
}
elseif (count($sValues) > 1)
{
$names = $this->combiner($sValues);
}
else
{
$names = array($sValues[0]);
}
// Get an existing palette
foreach ($names as $paletteName)
{
if (strlen($GLOBALS['TL_DCA'][$this->strTable]['palettes'][$paletteName]))
{
$strPalette = $GLOBALS['TL_DCA'][$this->strTable]['palettes'][$paletteName];
break;
}
}
// Include subpalettes
foreach ($subpalettes as $k=>$v)
{
$strPalette = preg_replace('/b'. preg_quote($k, '/').'b/i', $k.',['.$k.'],'.$v.',[EOF]', $strPalette);
}
}
return $strPalette;
}
}