ConLite/conlite/classes/class.version.php

641 Zeilen
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
?>