641 Zeilen
Kein EOL
20 KiB
PHP
641 Zeilen
Kein EOL
20 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Project:
|
|
* Contenido Content Management System
|
|
*
|
|
* Description:
|
|
* We use super class Version to create a new Version.
|
|
*
|
|
* Requirements:
|
|
* @con_php_req 5.0
|
|
*
|
|
*
|
|
* @package Contenido Backend classes
|
|
* @version 1.0.2
|
|
* @author Bilal Arslan, Timo Trautmann
|
|
* @copyright four for business AG <info@contenido.org>
|
|
* @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.8
|
|
*
|
|
* {@internal
|
|
* created 2008-08-12
|
|
* modified 2009-11-06, Murat Purc, replaced deprecated functions (PHP 5.3 ready)
|
|
* modified 2011-02-07, Dominik Ziegler, fixed max number of revisions check and prevent displaying error and creating folders if versioning is not activated
|
|
*
|
|
* }}
|
|
*
|
|
*/
|
|
if (!defined('CON_FRAMEWORK')) {
|
|
die('Illegal call');
|
|
}
|
|
|
|
class Version {
|
|
|
|
/**
|
|
* Id of Type
|
|
* @access protected
|
|
*/
|
|
protected $sType;
|
|
|
|
/**
|
|
* md5 coded name of author
|
|
* @access protected
|
|
*/
|
|
protected $sAuthor;
|
|
|
|
/**
|
|
* Time of created
|
|
* @access protected
|
|
*/
|
|
protected $dCreated;
|
|
|
|
/**
|
|
* Time of last modified
|
|
* @access protected
|
|
*/
|
|
protected $dLastModified;
|
|
|
|
/**
|
|
* Body data of xml file
|
|
* @access protected
|
|
*/
|
|
protected $aBodyData = array();
|
|
|
|
/**
|
|
* For init global variable
|
|
* @access protected
|
|
*/
|
|
protected $aCfg;
|
|
|
|
/**
|
|
* For init global variable $cfgClient
|
|
* @access protected
|
|
*/
|
|
protected $aCfgClient;
|
|
|
|
/**
|
|
* Database object
|
|
* @access protected
|
|
*/
|
|
protected $oDB;
|
|
|
|
/**
|
|
* For init global variable $client
|
|
* @access protected
|
|
*/
|
|
protected $iClient;
|
|
|
|
/**
|
|
* Revision files of current file
|
|
* @access public
|
|
*/
|
|
public $aRevisionFiles = array();
|
|
|
|
/**
|
|
* Number of Revision
|
|
* @access private
|
|
*/
|
|
protected $iRevisionNumber;
|
|
|
|
/**
|
|
* Timestamp
|
|
* @access protected
|
|
*/
|
|
protected $dTimestamp;
|
|
|
|
/**
|
|
* For init global variable $area
|
|
* @access protected
|
|
*/
|
|
protected $sArea;
|
|
|
|
/**
|
|
* For init global variable $frame
|
|
* @access protected
|
|
*/
|
|
protected $iFrame;
|
|
|
|
/**
|
|
* For init variables
|
|
* @access protected
|
|
*/
|
|
protected $aVarForm;
|
|
|
|
/**
|
|
* Identity the Id of Content Type
|
|
* @access protected
|
|
*/
|
|
protected $iIdentity;
|
|
|
|
/**
|
|
* To take control versioning is switched off
|
|
* @access private
|
|
*/
|
|
private $bVersionCreatActive;
|
|
|
|
/**
|
|
* Timestamp
|
|
* @access protected
|
|
*/
|
|
protected $dActualTimestamp;
|
|
|
|
/**
|
|
* Alternative Path for save version files
|
|
* @access protected
|
|
*/
|
|
protected $sAlternativePath;
|
|
|
|
/**
|
|
* Displays Notification only onetimes per object
|
|
*
|
|
*/
|
|
public static $iDisplayNotification;
|
|
protected $_bPathError = false;
|
|
|
|
/**
|
|
* The Version object constructor, initializes class variables
|
|
*
|
|
* @param array $aCfg
|
|
* @param array $aCfgClient
|
|
* @param object $oDB
|
|
* @param integer $iClient
|
|
* @param object $sArea
|
|
* @param object $iFrame
|
|
*
|
|
* @return void
|
|
*/
|
|
public function __construct($aCfg, $aCfgClient, DB_ConLite $oDB, $iClient, $sArea, $iFrame) {
|
|
$this->aCfg = $aCfg;
|
|
$this->aCfgClient = $aCfgClient;
|
|
$this->oDB = $oDB;
|
|
$this->iClient = $iClient;
|
|
$this->iRevisionNumber = 0;
|
|
$this->sArea = $sArea;
|
|
$this->iFrame = $iFrame;
|
|
$this->dActualTimestamp = time();
|
|
$this->aVarForm = array();
|
|
|
|
self::$iDisplayNotification++;
|
|
|
|
// Look if versioning is allowed, default is false
|
|
if (function_exists('getEffectiveSetting')) {
|
|
$this->bVersionCreatActive = getEffectiveSetting('versioning', 'activated', 'true');
|
|
$this->sAlternativePath = getEffectiveSetting('versioning', 'path');
|
|
} else {
|
|
$this->bVersionCreatActive = true;
|
|
$this->sAlternativePath = "";
|
|
}
|
|
|
|
if ($this->bVersionCreatActive == "true") {
|
|
if (!is_dir($this->sAlternativePath)) {
|
|
// Alternative Path is not true or is not exist, we use the frontendpath
|
|
if ($this->sAlternativePath != "" AND self::$iDisplayNotification < 2) {
|
|
$oNotification = new Contenido_Notification();
|
|
$sNotification = i18n('Alternative path %s does not exist. Version was saved in frondendpath.');
|
|
$oNotification->displayNotification("warning", sprintf($sNotification, $this->sAlternativePath));
|
|
}
|
|
|
|
$this->sAlternativePath = "";
|
|
}
|
|
|
|
// Look if versioning is set alternative path to save
|
|
$this->_checkPaths();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This function looks if maximum number of stored versions is achieved. If true, it will be delete the first version.
|
|
*
|
|
* @return void
|
|
*/
|
|
protected function prune() {
|
|
$this->initRevisions();
|
|
if (function_exists('getEffectiveSetting')) {
|
|
$sVar = getEffectiveSetting('versioning', 'prune_limit', '0');
|
|
} else {
|
|
$sVar = 0;
|
|
}
|
|
|
|
$bDelete = true;
|
|
|
|
while (count($this->aRevisionFiles) >= $sVar AND $bDelete AND (int) $sVar > 0) {
|
|
$iIndex = end(array_keys($this->aRevisionFiles));
|
|
$bDelete = $this->deleteFile($this->getFirstRevision());
|
|
unset($this->aRevisionFiles[$iIndex]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This function checks if needed version paths exists and were created if neccessary
|
|
* @return boolean
|
|
*/
|
|
protected function _checkPaths() {
|
|
$aPath = array('', '/css', '/js', '/layout', '/module', '/templates');
|
|
$sFrontEndPath = "";
|
|
if ($this->sAlternativePath == "") {
|
|
$sFrontEndPath = $this->aCfgClient[$this->iClient]["path"]["frontend"] . "version";
|
|
} else {
|
|
$sFrontEndPath = $this->sAlternativePath . "/" . $this->iClient;
|
|
}
|
|
if (is_dir($sFrontEndPath) && is_writable($sFrontEndPath)) {
|
|
foreach ($aPath as $sSubPath) {
|
|
if (!is_dir($sFrontEndPath . $sSubPath)) {
|
|
mkdir($sFrontEndPath . $sSubPath, 0777);
|
|
chmod($sFrontEndPath . $sSubPath, 0777);
|
|
}
|
|
}
|
|
} else {
|
|
trigger_error("Version path " . $sFrontEndPath . " not writable in " . __FILE__ . " on line " . __LINE__, E_USER_WARNING);
|
|
$this->_bPathError = true;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* This function initialize the body node of xml file
|
|
*
|
|
* @param string $sKey
|
|
* @param string $sValue
|
|
*
|
|
* @return array returns an array for body node
|
|
*/
|
|
public function setData($sKey, $sValue) {
|
|
$this->aBodyData[$sKey] = $sValue;
|
|
}
|
|
|
|
/**
|
|
* This function creats an xml file. XML Writer helps for create this file.
|
|
*
|
|
* @return string returns content of xml file
|
|
*/
|
|
public function createNewXml() {
|
|
$oWriter = new cXmlWriter();
|
|
$oRootElement = $oWriter->addElement('version', '', NULL, array(
|
|
'xml:lang' => 'de'
|
|
));
|
|
$oHeadElement = $oWriter->addElement('head', '', $oRootElement);
|
|
|
|
$oWriter->addElement('version_id', $this->iIdentity . '_' . $this->iVersion, $oHeadElement);
|
|
$oWriter->addElement('type', $this->sType, $oHeadElement);
|
|
$oWriter->addElement('date', date('Y-m-d H:i:s'), $oHeadElement);
|
|
$oWriter->addElement('author', $this->sAuthor, $oHeadElement);
|
|
$oWriter->addElement('client', $this->iClient, $oHeadElement);
|
|
$oWriter->addElement('created', $this->dCreated, $oHeadElement);
|
|
$oWriter->addElement('lastmodified', $this->dLastModified, $oHeadElement);
|
|
|
|
$oBodyElement = $oWriter->addElement('body', '', $oRootElement);
|
|
foreach ($this->aBodyData as $sKey => $sValue) {
|
|
$oWriter->addElement($sKey, $sValue, $oBodyElement, array(), true);
|
|
}
|
|
|
|
return $oWriter->saveToString();
|
|
}
|
|
|
|
/**
|
|
* This function creats new version in right folder.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function createNewVersion() {
|
|
if ($this->_bPathError)
|
|
return false;
|
|
$bCreate = false;
|
|
if ($this->bVersionCreatActive == "true") {
|
|
try { // Get version Name
|
|
$sRevisionName = $this->getRevision();
|
|
|
|
// Create xml version file
|
|
$sXmlFile = $this->createNewXml();
|
|
|
|
if (!is_dir($this->getFilePath())) {
|
|
|
|
$bCreate = mkdir($this->getFilePath(), 0777);
|
|
chmod($this->getFilePath(), 0777);
|
|
}
|
|
|
|
$sHandle = fopen($this->getFilePath() . $sRevisionName . '.xml', "w");
|
|
fputs($sHandle, $sXmlFile);
|
|
$bCreate = fclose($sHandle);
|
|
|
|
if ($bCreate == false) {
|
|
throw new Exception('Couldnt Create New Version');
|
|
}
|
|
} catch (Exception $e) {
|
|
$bCreate = false;
|
|
echo '<br>Some error occured: ' . $e->getMessage() . ': ' . $e->getFile() . ' at line ' . $e->getLine() . ' (' . $e->getTraceAsString() . ')';
|
|
}
|
|
}
|
|
return $bCreate;
|
|
}
|
|
|
|
/**
|
|
* This function inits version files. Its filter also timestamp and version files
|
|
*
|
|
* @return array returns xml file names
|
|
*/
|
|
protected function initRevisions() {
|
|
$this->aRevisionFiles = array();
|
|
$this->dTimestamp = array();
|
|
|
|
// Open this Filepath and read then the content.
|
|
$sDir = $this->getFilePath();
|
|
if (is_dir($sDir)) {
|
|
if ($dh = opendir($sDir)) {
|
|
|
|
while (($file = readdir($dh)) !== false) {
|
|
if ($file != '.' && $file != '..') {
|
|
$aData = explode('.', $file);
|
|
$aValues = explode('_', $aData[0]);
|
|
if ($aValues[0] > $this->iRevisionNumber) {
|
|
$this->iRevisionNumber = $aValues[0];
|
|
}
|
|
|
|
$this->dTimestamp[$aValues[0]] = $aValues[1];
|
|
$this->aRevisionFiles[$aValues[0]] = $file;
|
|
}
|
|
}
|
|
closedir($dh);
|
|
}
|
|
}
|
|
return krsort($this->aRevisionFiles);
|
|
}
|
|
|
|
/**
|
|
* This function deletes files and the the folder, for given path.
|
|
*
|
|
* @return bool return true if successful
|
|
*/
|
|
public function deleteFile($sFirstFile = "") {
|
|
// Open this Filepath and read then the content.
|
|
$sDir = $this->getFilePath();
|
|
|
|
$bDelet = false;
|
|
if (is_dir($sDir) AND $sFirstFile == "") {
|
|
if ($dh = opendir($sDir)) {
|
|
while (($sFile = readdir($dh)) !== false) {
|
|
if ($sFile != "." && $sFile != "..") {
|
|
// Delete the files
|
|
$bDelete = unlink($sDir . $sFile);
|
|
}
|
|
}
|
|
// if the files be cleared, the delete the folder
|
|
$bDelete = rmdir($sDir);
|
|
}
|
|
} else if ($sFirstFile != "") {
|
|
$bDelete = unlink($sDir . $sFirstFile);
|
|
}
|
|
if ($bDelete) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the frontendpath to revision
|
|
*
|
|
* @return string returns path to revision file
|
|
*/
|
|
public function getFilePath() {
|
|
if ($this->sAlternativePath == "") {
|
|
$sFrontEndPath = $this->aCfgClient[$this->iClient]["path"]["frontend"] . "version/";
|
|
} else {
|
|
$sFrontEndPath = $this->sAlternativePath . "/" . $this->iClient . "/";
|
|
}
|
|
return $sFrontEndPath . $this->sType . '/' . $this->iIdentity . '/';
|
|
}
|
|
|
|
/**
|
|
* Get the last revision file
|
|
*
|
|
* @return array returns Last Revision
|
|
*/
|
|
public function getLastRevision() {
|
|
return reset($this->aRevisionFiles);
|
|
}
|
|
|
|
/**
|
|
* Makes new and init Revision Name
|
|
*
|
|
* @return integer returns number of Revison File
|
|
*/
|
|
private function getRevision() {
|
|
$this->iVersion = ($this->iRevisionNumber + 1 ) . '_' . $this->dActualTimestamp;
|
|
return $this->iVersion;
|
|
}
|
|
|
|
/**
|
|
* Inits the first element of revision files
|
|
*
|
|
* @return string the name of xml files
|
|
*/
|
|
protected function getFirstRevision() {
|
|
$aKey = array();
|
|
$this->initRevisions();
|
|
$aKey = $this->aRevisionFiles;
|
|
$sFirstRevision = "";
|
|
|
|
// to take first element, we use right sort
|
|
ksort($aKey);
|
|
foreach ($aKey as $value) {
|
|
return $sFirstRevision = $value;
|
|
}
|
|
return $sFirstRevision;
|
|
}
|
|
|
|
/**
|
|
* Revision Files
|
|
*
|
|
* @return array returns all Revison File
|
|
*/
|
|
public function getRevisionFiles() {
|
|
return $this->aRevisionFiles;
|
|
}
|
|
|
|
/**
|
|
* This function generate version names for select-box
|
|
*
|
|
* @return array returns an array of revision file names
|
|
*/
|
|
public function getFormatTimestamp() {
|
|
$aTimes = array();
|
|
if (count($this->dTimestamp) > 0) {
|
|
krsort($this->dTimestamp);
|
|
foreach ($this->dTimestamp as $iKey => $sTimeValue) {
|
|
$aTimes[$this->aRevisionFiles[$iKey]] = date('d.m.Y H:i:s', $sTimeValue) . " - Revision: " . $iKey;
|
|
}
|
|
}
|
|
|
|
return $aTimes;
|
|
}
|
|
|
|
/**
|
|
* This function generate version names for select-box
|
|
*
|
|
* @return array returns an array of revision file names
|
|
*/
|
|
public function setVarForm($sKey, $sValue) {
|
|
$this->aVarForm[$sKey] = $sValue;
|
|
}
|
|
|
|
/**
|
|
* The general SelectBox function for get Revision.
|
|
*
|
|
* @param string $sTableForm The name of Table_Form class
|
|
* @param string $sAddHeader The Header Label of SelectBox Widget
|
|
* @param string $sLabelOfSelectBox The Label of SelectBox Widget
|
|
* @param string $sIdOfSelectBox Id of Select Box
|
|
*
|
|
* return string if is exists Revision, then returns HTML Code of full SelectBox else returns empty string
|
|
*/
|
|
public function buildSelectBox($sTableForm, $sAddHeader, $sLabelOfSelectBox, $sIdOfSelectBox) {
|
|
$oForm = new UI_Table_Form("lay_history");
|
|
$aMessage = array();
|
|
// if exists xml files
|
|
if (count($this->dTimestamp) > 0) {
|
|
|
|
foreach ($this->aVarForm as $sKey => $sValue) {
|
|
$oForm->setVar($sKey, $sValue);
|
|
}
|
|
$aMessage = $this->getMessages();
|
|
$oForm->addHeader(i18n($sAddHeader));
|
|
$oForm->add(i18n($sLabelOfSelectBox), $this->getSelectBox($this->getFormatTimestamp(), $sIdOfSelectBox));
|
|
$oForm->setActionButton("clearhistory", "images/but_delete.gif", $aMessage["alt"], "c", "history_truncate");
|
|
$oForm->setConfirm("clearhistory", $aMessage["alt"], $aMessage["popup"]);
|
|
$oForm->setActionButton("submit", "images/but_refresh.gif", i18n("Refresh"), "s");
|
|
|
|
return $oForm->render() . '<div style="margin-top:20px;"></div>';
|
|
} else {
|
|
return '';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Messagebox for build selectBox. Dynamic allocation for type.
|
|
* return array the attributes alt and poput returns
|
|
*/
|
|
private function getMessages() {
|
|
$aMessage = array();
|
|
switch ($this->sType) {
|
|
case 'layout':
|
|
$aMessage["alt"] = i18n("Clear layout history");
|
|
$aMessage["popup"] = i18n("Do you really want to clear layout history?") . "<br><br>" . i18n("Note: This only affects the current layout.");
|
|
break;
|
|
case 'module':
|
|
$aMessage["alt"] = i18n("Clear module history");
|
|
$aMessage["popup"] = i18n("Do you really want to clear module history?") . "<br><br>" . i18n("Note: This only affects the current module.");
|
|
break;
|
|
case 'css':
|
|
$aMessage["alt"] = i18n("Clear style history");
|
|
$aMessage["popup"] = i18n("Do you really want to clear style history?") . "<br><br>" . i18n("Note: This only affects the current style.");
|
|
break;
|
|
case 'js':
|
|
$aMessage["alt"] = i18n("Clear Java-Script history");
|
|
$aMessage["popup"] = i18n("Do you really want to clear Java-Script history?") . "<br><br>" . i18n("Note: This only affects the current Java-Script.");
|
|
break;
|
|
case 'templates':
|
|
$aMessage["alt"] = i18n("Clear HTML-Template history");
|
|
$aMessage["popup"] = i18n("Do you really want to clear HTML-Template history?") . "<br><br>" . i18n("Note: This only the affects current HTML-Template.");
|
|
break;
|
|
default:
|
|
$aMessage["alt"] = i18n("Clear history");
|
|
$aMessage["popup"] = i18n("Do you really want to clear history?") . "<br><br>" . i18n("Note: This only affects the current history.");
|
|
break;
|
|
}
|
|
return $aMessage;
|
|
}
|
|
|
|
/**
|
|
* A Class Function for fill version files
|
|
*
|
|
* @param string $sTableForm The name of Table_Form class
|
|
* @param string $sAddHeader The Header Label of SelectBox Widget
|
|
*
|
|
* return string returns select-box with filled files
|
|
*/
|
|
private function getSelectBox($aTempVesions, $sIdOfSelectBox) {
|
|
$sSelected = $_POST[$sIdOfSelectBox];
|
|
$oSelectMenue = new cHTMLSelectElement($sIdOfSelectBox);
|
|
$oSelectMenue->autoFill($aTempVesions);
|
|
|
|
if ($sSelected != "") {
|
|
$oSelectMenue->setDefault($sSelected);
|
|
}
|
|
|
|
return $oSelectMenue->render();
|
|
}
|
|
|
|
/**
|
|
* Build new Textarea with below parameters
|
|
*
|
|
* @param string $sName The name of Textarea.
|
|
* @param string $sValue The value of Input Textarea
|
|
* @param integer $iWidth width of Textarea
|
|
* @param integer $iHeight height of Textarea
|
|
*
|
|
* @return string HTML Code of Textarea
|
|
*/
|
|
public function getTextarea($sName, $sInitValue, $iWidth, $iHeight, $sId = "") {
|
|
if ($sId != "") {
|
|
$oHTMLTextarea = new cHTMLTextarea($sName, $sInitValue, $iWidth, $iHeight, $sId);
|
|
} else {
|
|
$oHTMLTextarea = new cHTMLTextarea($sName, $sInitValue, $iWidth, $iHeight);
|
|
}
|
|
|
|
$oHTMLTextarea->setStyle("font-family: monospace; width: 100%;");
|
|
$oHTMLTextarea->updateAttributes(array("wrap" => "off"));
|
|
|
|
return $oHTMLTextarea->render();
|
|
}
|
|
|
|
/**
|
|
* Build new Textfield with below parameters
|
|
*
|
|
* @param string $sName The name of Input Textfield.
|
|
* @param string $sValue The value of Input Textfield
|
|
* @param integer $iWidth width of Input Textfield
|
|
*
|
|
* @return string HTML Code of Input Textfield
|
|
*/
|
|
public function getTextBox($sName, $sInitValue, $iWidth, $bDisabled = false) {
|
|
$oHTMLTextbox = new cHTMLTextbox($sName, clHtmlEntityDecode($sInitValue), $iWidth, "", "", $bDisabled);
|
|
$oHTMLTextbox->setStyle("font-family: monospace; width: 100%;");
|
|
$oHTMLTextbox->updateAttributes(array("wrap" => "off"));
|
|
|
|
return $oHTMLTextbox->render();
|
|
}
|
|
|
|
/**
|
|
* Displays your notification
|
|
*
|
|
* @param string $sOutPut
|
|
*
|
|
* @return void
|
|
*/
|
|
public function displayNotification($sOutPut) {
|
|
if ($sOutPut != "") {
|
|
print $sOutPut;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set new node for xml file of description
|
|
*
|
|
* @param string $sDesc Content of node
|
|
*
|
|
*/
|
|
public function setBodyNodeDescription($sDesc) {
|
|
if ($sDesc != "") {
|
|
$this->sDescripion = clHtmlEntities($sDesc);
|
|
$this->setData("description", $this->sDescripion);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// end of class
|
|
?>
|