Overview

Packages

  • CONTENIDO
  • Core
    • Authentication
    • Backend
    • Cache
    • CEC
    • Chain
    • ContentType
    • Database
    • Debug
    • Exception
    • Frontend
      • Search
      • URI
      • Util
    • GenericDB
      • Model
    • GUI
      • HTML
    • I18N
    • LayoutHandler
    • Log
    • Security
    • Session
    • Util
    • Validation
    • Versioning
    • XML
  • Module
    • ContentSitemapHtml
    • ContentSitemapXml
    • ContentUserForum
    • NavigationTop
    • ScriptCookieDirective
  • mpAutoloaderClassMap
  • None
  • PHP
  • Plugin
    • ContentAllocation
    • CronjobOverview
    • FormAssistant
    • FrontendLogic
    • FrontendUsers
    • Linkchecker
    • ModRewrite
    • Newsletter
    • Repository
      • FrontendNavigation
      • KeywordDensity
    • SmartyWrapper
    • UrlShortener
    • UserForum
    • Workflow
  • PluginManager
  • Setup
    • Form
    • GUI
    • Helper
      • Environment
      • Filesystem
      • MySQL
      • PHP
    • UpgradeJob

Classes

  • cContentVersioning
  • cVersion
  • cVersionFile
  • cVersionLayout
  • cVersionModule
  • Overview
  • Package
  • Class
  • Tree
  • Deprecated
  • Todo
  1: <?php
  2: 
  3: /**
  4:  * This file contains the base version class.
  5:  *
  6:  * @package    Core
  7:  * @subpackage Versioning
  8:  * @author     Bilal Arslan, Timo Trautmann
  9:  * @copyright  four for business AG <www.4fb.de>
 10:  * @license    http://www.contenido.org/license/LIZENZ.txt
 11:  * @link       http://www.4fb.de
 12:  * @link       http://www.contenido.org
 13:  */
 14: 
 15: defined('CON_FRAMEWORK') || die('Illegal call: Missing framework initialization - request aborted.');
 16: 
 17: /**
 18:  * Base version class
 19:  *
 20:  * @package    Core
 21:  * @subpackage Versioning
 22:  */
 23: class cVersion {
 24: 
 25:     /**
 26:      * Id of Type
 27:      *
 28:      * @var string
 29:      */
 30:     protected $sType;
 31: 
 32:     /**
 33:      * md5 coded name of author
 34:      *
 35:      * @var string
 36:      */
 37:     protected $sAuthor;
 38: 
 39:     /**
 40:      * Time of created
 41:      *
 42:      * @var ???
 43:      */
 44:     protected $dCreated;
 45: 
 46:     /**
 47:      * Time of last modified
 48:      *
 49:      * @var unknown_type
 50:      */
 51:     protected $dLastModified;
 52: 
 53:     /**
 54:      * Body data of xml file
 55:      *
 56:      * @var string
 57:      */
 58:     protected $aBodyData;
 59: 
 60:     /**
 61:      * For init global variable
 62:      *
 63:      * @var array
 64:      */
 65:     protected $aCfg;
 66: 
 67:     /**
 68:      * For init global variable $cfgClient
 69:      *
 70:      * @var array
 71:      */
 72:     protected $aCfgClient;
 73: 
 74:     /**
 75:      * CONTENIDO database object
 76:      *
 77:      * @var cDb
 78:      */
 79:     protected $oDB;
 80: 
 81:     /**
 82:      * For init global variable $client
 83:      *
 84:      * @var int
 85:      */
 86:     protected $iClient;
 87: 
 88:     /**
 89:      * Revision files of current file
 90:      *
 91:      * @var array
 92:      */
 93:     public $aRevisionFiles;
 94: 
 95:     /**
 96:      * Number of Revision
 97:      *
 98:      * @var int
 99:      */
100:     protected $iRevisionNumber;
101: 
102:     /**
103:      * Timestamp
104:      *
105:      * @var array
106:      */
107:     protected $dTimestamp;
108: 
109:     /**
110:      * For init global variable $area
111:      *
112:      * @var array
113:      */
114:     protected $sArea;
115: 
116:     /**
117:      * For init global variable $frame
118:      *
119:      * @var int
120:      */
121:     protected $iFrame;
122: 
123:     /**
124:      * For init variables
125:      *
126:      * @var array
127:      */
128:     protected $aVarForm;
129: 
130:     /**
131:      * Identity the Id of Content Type
132:      *
133:      * @var int
134:      */
135:     protected $iIdentity;
136: 
137:     /**
138:      * @var string
139:      */
140:     protected $sDescripion;
141: 
142:     /**
143:      * @var string
144:      */
145:     protected $iVersion;
146: 
147:     /**
148:      * To take control versioning is switched off
149:      *
150:      * @var bool
151:      */
152:     private $bVersioningActive;
153: 
154:     /**
155:      * Timestamp
156:      *
157:      * @var int
158:      */
159:     protected $dActualTimestamp;
160: 
161:     /**
162:      * Alternative Path for save version files
163:      *
164:      * @var string
165:      */
166:     protected $sAlternativePath;
167: 
168:     /**
169:      * Displays Notification only onetimes per object
170:      *
171:      * @var int
172:      */
173:     public static $iDisplayNotification;
174: 
175:     /**
176:      * Constructor to create an instance of this class.
177:      *
178:      * Initializes class variables.
179:      *
180:      * @param array $aCfg
181:      * @param array $aCfgClient
182:      * @param cDb $oDB
183:      *         CONTENIDO database object
184:      * @param int $iClient
185:      * @param string $sArea
186:      * @param int $iFrame
187:      */
188:     public function __construct($aCfg, $aCfgClient, $oDB, $iClient, $sArea, $iFrame) {
189:         $this->aBodyData = array();
190:         $this->aRevisionFiles = array();
191:         $this->aCfg = $aCfg;
192: 
193:         $this->aCfgClient = $aCfgClient;
194: 
195:         $this->oDB = $oDB;
196:         $this->iClient = $iClient;
197:         $this->iRevisionNumber = 0;
198:         $this->sArea = $sArea;
199:         $this->iFrame = $iFrame;
200: 
201:         $this->dActualTimestamp = time();
202: 
203:         $this->aVarForm = array();
204: 
205:         self::$iDisplayNotification++;
206: 
207:         // Look if versioning is allowed, default is false
208:         if (function_exists('getEffectiveSetting')) {
209:             $this->bVersioningActive = getEffectiveSetting('versioning', 'activated', 'true');
210:             $this->sAlternativePath = getEffectiveSetting('versioning', 'path');
211: 
212:             if ($this->bVersioningActive == 'true') {
213:                 $this->bVersioningActive = true;
214:             } else {
215:                 $this->bVersioningActive = false;
216:             }
217:         } else {
218:             $this->bVersioningActive = true;
219:             $this->sAlternativePath = '';
220:         }
221: 
222:         if ($this->bVersioningActive == false) {
223:             return;
224:         }
225: 
226:         if (is_dir($this->sAlternativePath) == false) {
227:             // Alternative Path is not true or is not exist, we use the
228:             // frontendpath
229:             if ($this->sAlternativePath != '' and self::$iDisplayNotification < 2) {
230:                 $oNotification = new cGuiNotification();
231:                 $sNotification = i18n('Alternative path %s does not exist. Version was saved in frondendpath.');
232:                 $oNotification->displayNotification('warning', sprintf($sNotification, $this->sAlternativePath));
233:             }
234: 
235:             $this->sAlternativePath = '';
236:         }
237: 
238:         // Look if versioning is set alternative path to save
239:         $this->checkPaths();
240:     }
241: 
242:     /**
243:      * This function looks if maximum number of stored versions is achieved.
244:      * If true, it will be delete the first version.
245:      *
246:      * @throws cInvalidArgumentException
247:      */
248:     protected function prune() {
249:         $this->initRevisions();
250:         if (function_exists('getEffectiveSetting')) {
251:             $sVar = getEffectiveSetting('versioning', 'prune_limit', '0');
252:         } else {
253:             $sVar = 0;
254:         }
255: 
256:         $bDelete = true;
257: 
258:         while (count($this->aRevisionFiles) >= $sVar and $bDelete and (int) $sVar > 0) {
259:             $iIndex = end(array_keys($this->aRevisionFiles));
260:             $bDelete = $this->deleteFile($this->getFirstRevision());
261:             unset($this->aRevisionFiles[$iIndex]);
262:         }
263:     }
264: 
265:     /**
266:      * This function checks if needed version paths exists and were created if
267:      * necessary
268:      */
269:     protected function checkPaths() {
270:         $aPath = array(
271:             '/',
272:             'css/',
273:             'js/',
274:             'layout/',
275:             'module/',
276:             'templates/'
277:         );
278:         $sFrontEndPath = '';
279:         if ($this->sAlternativePath == '') {
280:             $sFrontEndPath = $this->aCfgClient[$this->iClient]['version']['path'];
281:         } else {
282:             $sFrontEndPath = $this->sAlternativePath . '/' . $this->iClient . '/';
283:         }
284: 
285:         foreach ($aPath as $sSubPath) {
286:             if (!is_dir($sFrontEndPath . $sSubPath)) {
287:                 mkdir($sFrontEndPath . $sSubPath, cDirHandler::getDefaultPermissions());
288:                 @chmod($sFrontEndPath . $sSubPath, cDirHandler::getDefaultPermissions());
289:             }
290:         }
291:     }
292: 
293:     /**
294:      * This function initialize the body node of xml file
295:      *
296:      * @param string $sKey
297:      * @param string $sValue
298:      * @return array
299:      *         returns an array for body node
300:      */
301:     public function setData($sKey, $sValue) {
302:         $this->aBodyData[$sKey] = $sValue;
303:     }
304: 
305:     /**
306:      * This function creats an xml file.
307:      * XML Writer helps for create this file.
308:      *
309:      * @param string $sDirectory
310:      * @param string $sFileName
311:      *         name of xml file to create
312:      *
313:      * @return bool
314:      *         true if saving file was successful, otherwise false
315:      * @throws cException
316:      */
317:     public function createNewXml($sDirectory, $sFileName) {
318:         $oWriter = new cXmlWriter();
319:         $oRootElement = $oWriter->addElement('version', '', NULL, array(
320:             'xml:lang' => 'de'
321:         ));
322:         $oHeadElement = $oWriter->addElement('head', '', $oRootElement);
323: 
324:         $oWriter->addElement('version_id', $this->iIdentity . '_' . $this->iVersion, $oHeadElement);
325:         $oWriter->addElement('type', $this->sType, $oHeadElement);
326:         $oWriter->addElement('date', date('Y-m-d H:i:s'), $oHeadElement);
327:         $oWriter->addElement('author', $this->sAuthor, $oHeadElement);
328:         $oWriter->addElement('client', $this->iClient, $oHeadElement);
329:         $oWriter->addElement('created', $this->dCreated, $oHeadElement);
330:         $oWriter->addElement('lastmodified', $this->dLastModified, $oHeadElement);
331: 
332:         $oBodyElement = $oWriter->addElement('body', '', $oRootElement);
333:         foreach ($this->aBodyData as $sKey => $sValue) {
334:             $oWriter->addElement($sKey, $sValue, $oBodyElement, array(), true);
335:         }
336: 
337:         return $oWriter->saveToFile($sDirectory, $sFileName);
338:     }
339: 
340:     /**
341:      * This function creates new version in right folder.
342:      *
343:      * @throws cException
344:      *         if new version could not be created
345:      * @return bool
346:      */
347:     public function createNewVersion() {
348:         if ($this->bVersioningActive == false) {
349:             return false;
350:         }
351: 
352:         // get version name
353:         $sRevisionName = $this->getRevision();
354: 
355:         if (!is_dir($this->getFilePath())) {
356:             mkdir($this->getFilePath(), cDirHandler::getDefaultPermissions());
357:             @chmod($this->getFilePath(), cDirHandler::getDefaultPermissions());
358:         }
359: 
360:         // Create xml version file
361:         $bCreate = $this->createNewXml($this->getFilePath(), $sRevisionName . '.xml');
362: 
363:         if ($bCreate == false) {
364:             throw new cException('Could not create new version.');
365:         }
366: 
367:         return $bCreate;
368:     }
369: 
370:     /**
371:      * This function inits version files.
372:      * Its filter also timestamp and version files
373:      *
374:      * @return array
375:      *         returns xml file names
376:      */
377:     protected function initRevisions() {
378:         $this->aRevisionFiles = array();
379:         $this->dTimestamp = array();
380:         // Open this Filepath and read then the content.
381:         $sDir = $this->getFilePath();
382:         if (is_dir($sDir)) {
383:             if (false !== ($handle = cDirHandler::read($sDir))) {
384:                 foreach ($handle as $file) {
385:                     if (false === cFileHandler::fileNameIsDot($file)) {
386:                         $aData = explode('.', $file);
387:                         $aValues = explode('_', $aData[0]);
388:                         if ($aValues[0] > $this->iRevisionNumber) {
389:                             $this->iRevisionNumber = $aValues[0];
390:                         }
391: 
392:                         $this->dTimestamp[$aValues[0]] = $aValues[1];
393:                         $this->aRevisionFiles[$aValues[0]] = $file;
394:                     }
395:                 }
396:             }
397:         }
398: 
399:         return krsort($this->aRevisionFiles);
400:     }
401: 
402:     /**
403:      * This function deletes files and the the folder, for given path.
404:      *
405:      * @param string $sFirstFile [optional]
406:      * @return bool
407:      *                           return true if successful
408:      * @throws cInvalidArgumentException
409:      */
410:     public function deleteFile($sFirstFile = '') {
411:         // Open this Filepath and read then the content.
412:         $sDir = $this->getFilePath();
413: 
414:         $bDelete = true;
415:         if (is_dir($sDir) and $sFirstFile == '') {
416:             if (false !== ($handle = cDirHandler::read($sDir))) {
417:                 foreach ($handle as $sFile) {
418:                     if (false === cFileHandler::fileNameIsDot($sFile)) {
419:                         // Delete the files
420:                         if (false === cFileHandler::remove($sDir . $sFile)) {
421:                             $bDelete = false;
422:                         }
423:                     }
424:                 }
425:                 // if the files be cleared, the delete the folder
426:                 if (true === $bDelete) {
427:                     $bDelete = cDirHandler::remove($sDir);
428:                 }
429:             }
430:         } else if ($sFirstFile != '') {
431:             $bDelete = cFileHandler::remove($sDir . $sFirstFile);
432:         }
433:         if ($bDelete) {
434:             return true;
435:         } else {
436:             return false;
437:         }
438:     }
439: 
440:     /**
441:      * Get the frontendpath to revision
442:      *
443:      * @return string
444:      *         returns path to revision file
445:      */
446:     public function getFilePath() {
447:         if ($this->sAlternativePath == '') {
448:             $sFrontEndPath = $this->aCfgClient[$this->iClient]['version']['path'];
449:         } else {
450:             $sFrontEndPath = $this->sAlternativePath . '/' . $this->iClient . '/';
451:         }
452:         return $sFrontEndPath . $this->sType . '/' . $this->iIdentity . '/';
453:     }
454: 
455:     /**
456:      * Get the last revision file
457:      *
458:      * @return array
459:      *         returns Last Revision
460:      */
461:     public function getLastRevision() {
462:         return reset($this->aRevisionFiles);
463:     }
464: 
465:     /**
466:      * Makes new and init Revision Name
467:      *
468:      * @return int
469:      *         returns number of Revison File
470:      */
471:     private function getRevision() {
472:         $this->iVersion = ($this->iRevisionNumber + 1) . '_' . $this->dActualTimestamp;
473:         return $this->iVersion;
474:     }
475: 
476:     /**
477:      * Inits the first element of revision files
478:      *
479:      * @return string
480:      *         the name of xml files
481:      */
482:     protected function getFirstRevision() {
483:         $this->initRevisions();
484:         $aKey = $this->aRevisionFiles;
485:         $sFirstRevision = '';
486: 
487:         // to take first element, we use right sort
488:         ksort($aKey);
489:         foreach ($aKey as $value) {
490:             return $sFirstRevision = $value;
491:         }
492:         return $sFirstRevision;
493:     }
494: 
495:     /**
496:      * Revision Files
497:      *
498:      * @return array
499:      *         returns all Revison File
500:      */
501:     public function getRevisionFiles() {
502:         return $this->aRevisionFiles;
503:     }
504: 
505:     /**
506:      * This function generate version names for select-box
507:      *
508:      * @return array
509:      *         returns an array of revision file names
510:      */
511:     public function getFormatTimestamp() {
512:         $aTimes = array();
513:         if (count($this->dTimestamp) > 0) {
514:             krsort($this->dTimestamp);
515:             foreach ($this->dTimestamp as $iKey => $sTimeValue) {
516:                 $aTimes[$this->aRevisionFiles[$iKey]] = date('d.m.Y H:i:s', $sTimeValue) . ' - Revision: ' . $iKey;
517:             }
518:         }
519: 
520:         return $aTimes;
521:     }
522: 
523:     /**
524:      * This function generate version names for select-box
525:      *
526:      * @param string $sKey
527:      * @param string $sValue
528:      * @return array
529:      *         returns an array of revision file names
530:      */
531:     public function setVarForm($sKey, $sValue) {
532:         $this->aVarForm[$sKey] = $sValue;
533:     }
534: 
535:     /**
536:      * The general SelectBox function for get Revision.
537:      *
538:      * @param string $sTableForm
539:      *                         The name of Table_Form class
540:      * @param string $sAddHeader
541:      *                         The Header Label of SelectBox Widget
542:      * @param string $sLabelOfSelectBox
543:      *                         The Label of SelectBox Widget
544:      * @param string $sIdOfSelectBox
545:      *                         Id of Select Box
546:      * @param bool   $disabled [optional]
547:      *                         If true, show disabled buttons for deleting
548:      *
549:      * @return string
550:      *         if is exists Revision, then returns HTML Code of full SelectBox
551:      *         else returns empty string
552:      * @throws cInvalidArgumentException
553:      */
554:     public function buildSelectBox($sTableForm, $sAddHeader, $sLabelOfSelectBox, $sIdOfSelectBox, $disabled = false) {
555:         $oForm = new cGuiTableForm($sTableForm);
556: 
557:         // if exists xml files
558:         if (count($this->dTimestamp) > 0) {
559: 
560:             foreach ($this->aVarForm as $sKey => $sValue) {
561:                 $oForm->setVar($sKey, $sValue);
562:             }
563:             $aMessage = $this->getMessages();
564:             $oForm->addHeader(i18n($sAddHeader));
565:             $oForm->add(i18n($sLabelOfSelectBox), $this->getSelectBox($this->getFormatTimestamp(), $sIdOfSelectBox));
566:             $oForm->setActionButton('clearhistory', 'images/delete' . (($disabled) ? '_inact' : '') . '.gif', $aMessage['alt'], 'c', 'history_truncate');
567:             if(!$disabled) {
568:                 $oForm->setConfirm('clearhistory', $aMessage['alt'], $aMessage['popup']);
569:             }
570:             $oForm->setActionButton('submit', 'images/but_refresh.gif', i18n('Refresh'), 's');
571:             $oForm->setTableID("version_selector");
572: 
573:             return $oForm->render();
574:         } else {
575:             return '';
576:         }
577:     }
578: 
579:     /**
580:      * Messagebox for build selectBox.
581:      * Dynamic allocation for type.
582:      *
583:      * @return array
584:      *         the attributes alt and poput returns
585:      */
586:     private function getMessages() {
587:         $aMessage = array();
588:         switch ($this->sType) {
589:             case 'layout':
590:                 $aMessage['alt'] = i18n('Clear layout history');
591:                 $aMessage['popup'] = i18n('Do you really want to clear layout history?') . '<br><br>' . i18n('Note: This only affects the current layout.');
592:                 break;
593:             case 'module':
594:                 $aMessage['alt'] = i18n('Clear module history');
595:                 $aMessage['popup'] = i18n('Do you really want to clear module history?') . '<br><br>' . i18n('Note: This only affects the current module.');
596:                 break;
597:             case 'css':
598:                 $aMessage['alt'] = i18n('Clear style history');
599:                 $aMessage['popup'] = i18n('Do you really want to clear style history?') . '<br><br>' . i18n('Note: This only affects the current style.');
600:                 break;
601:             case 'js':
602:                 $aMessage['alt'] = i18n('Clear Java-Script history');
603:                 $aMessage['popup'] = i18n('Do you really want to clear Java-Script history?') . '<br><br>' . i18n('Note: This only affects the current JavaScript.');
604:                 break;
605:             case 'templates':
606:                 $aMessage['alt'] = i18n('Clear HTML template history');
607:                 $aMessage['popup'] = i18n('Do you really want to clear HTML template history?') . '<br><br>' . i18n('Note: This only the affects current HTML template.');
608:                 break;
609:             default:
610:                 $aMessage['alt'] = i18n('Clear history');
611:                 $aMessage['popup'] = i18n('Do you really want to clear history?') . '<br><br>' . i18n('Note: This only affects the current history.');
612:                 break;
613:         }
614:         return $aMessage;
615:     }
616: 
617:     /**
618:      * A Class Function for fill version files
619:      *
620:      * @param string $sTableForm
621:      *         The name of Table_Form class
622:      * @param string $sAddHeader
623:      *         The Header Label of SelectBox Widget
624:      * @return string
625:      *         returns select-box with filled files
626:      */
627:     private function getSelectBox($aTempVesions, $sIdOfSelectBox) {
628:         $sSelected = $_POST[$sIdOfSelectBox];
629:         $oSelectMenue = new cHTMLSelectElement($sIdOfSelectBox);
630:         $oSelectMenue->autoFill($aTempVesions);
631: 
632:         if ($sSelected != '') {
633:             $oSelectMenue->setDefault($sSelected);
634:         }
635: 
636:         return $oSelectMenue->render();
637:     }
638: 
639:     /**
640:      * Build new Textarea with below parameters
641:      *
642:      * @param string $sName
643:      *         The name of Textarea.
644:      * @param string $sInitValue
645:      *         The value of Input Textarea
646:      * @param int $iWidth
647:      *         width of Textarea
648:      * @param int $iHeight
649:      *         height of Textarea
650:      * @param string $sId [optional]
651:      * @param bool $disabled [optional]
652:      *         Disabled Textarea
653:      * @return string
654:      *         HTML Code of Textarea
655:      */
656:     public function getTextarea($sName, $sInitValue, $iWidth, $iHeight, $sId = '', $disabled = false) {
657:         if ($sId != '') {
658:             $oHTMLTextarea = new cHTMLTextarea($sName, $sInitValue, $iWidth, $iHeight, $sId);
659:         } else {
660:             $oHTMLTextarea = new cHTMLTextarea($sName, $sInitValue, $iWidth, $iHeight);
661:         }
662: 
663:         if ($disabled) {
664:             $oHTMLTextarea->setDisabled('disabled');
665:         }
666: 
667:         $oHTMLTextarea->setStyle('font-family: monospace; width: 100%;');
668:         $oHTMLTextarea->updateAttributes(array(
669:             'wrap' => 'off'
670:         ));
671: 
672:         return $oHTMLTextarea->render();
673:     }
674: 
675:     /**
676:      * Build new Textfield with below parameters
677:      *
678:      * @param string $sName
679:      *         The name of Input Textfield.
680:      * @param string $sInitValue
681:      *         The value of Input Textfield
682:      * @param int $iWidth
683:      *         width of Input Textfield
684:      * @param bool $bDisabled [optional]
685:      *         Disabled TextBox
686:      * @return string
687:      *         HTML Code of Input Textfield
688:      */
689:     public function getTextBox($sName, $sInitValue, $iWidth, $bDisabled = false) {
690:         $oHTMLTextbox = new cHTMLTextbox($sName, conHtmlEntityDecode($sInitValue), $iWidth, '', '', $bDisabled);
691:         $oHTMLTextbox->setStyle('font-family:monospace; width:100%;');
692:         $oHTMLTextbox->updateAttributes(array(
693:             'wrap' => 'off'
694:         ));
695: 
696:         return $oHTMLTextbox->render();
697:     }
698: 
699:     /**
700:      * Displays your notification
701:      *
702:      * @param string $sOutPut
703:      */
704:     public function displayNotification($sOutPut) {
705:         if ($sOutPut != '') {
706:             print $sOutPut;
707:         }
708:     }
709: 
710:     /**
711:      * Set new node for xml file of description
712:      *
713:      * @param string $sDesc
714:      *         Content of node
715:      */
716:     public function setBodyNodeDescription($sDesc) {
717:         if ($sDesc != '') {
718:             $this->sDescripion = conHtmlentities($sDesc);
719:             $this->setData('description', $this->sDescripion);
720:         }
721:     }
722: 
723: }
724: 
CMS CONTENIDO 4.10.0 API documentation generated by ApiGen 2.8.0