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