source: branches/2.0singleton/lib/PEdit.inc.php @ 128

Last change on this file since 128 was 128, checked in by scdev, 18 years ago

finished /lib folder

File size: 26.2 KB
Line 
1<?php
2/**
3 * PEdit:: provides a mechanism to store text in php variables
4 * which will be printed to the client browser under normal
5 * circumstances, but an authenticated user can 'edit' the document--
6 * data stored in vars will be shown in html form elements to be editied
7 * and saved. Posted data is stored in XML format in a specified data dir.
8 * A copy of the previous version is saved with the unix
9 * timestamp as part of the filename. This allows reverting to previous versions.
10 *
11 * To use, include this file, initialize variables,
12 * and call printing/editing functions where you want data and forms to
13 * show up. Below is an example of use:
14 
15 // Initialize PEdit object.
16 require_once 'codebase/lib/PEdit.inc.php';
17 $pedit = new PEdit(array(
18     'data_dir' => COMMON_BASE . '/html/_pedit_data',
19     'authorized' => true,
20 ));
21 
22 // Setup content data types.
23 $pedit->set('title');
24 $pedit->set('content', array('type' => 'textarea'));
25 
26 // After setting all parameters and data, load the data.
27 $pedit->start();
28 
29 // Print content.
30 echo $pedit->get('title');
31 echo $pedit->get('content');
32 
33 // Print additional PEdit functionality.
34 $pedit->formBegin();
35 $pedit->printAllForms();
36 $pedit->printVersions();
37 $pedit->formEnd();
38
39 * @author  Quinn Comendant <quinn@strangecode.com>
40 * @concept Beau Smith <beau@beausmith.com>
41 * @version 2.0
42 */
43class PEdit {
44
45    // PEdit object parameters.
46    var $_params = array(
47        'data_dir' => '',
48        'character_set' => 'utf-8',
49        'versions_min_qty' => 20,
50        'versions_min_days' => 10,
51    );
52
53    var $_data = array(); // Array to store loaded data.
54    var $_data_file = ''; // Full file path to the pedit data file.
55    var $_authorized = false; // User is authenticated to see extended functions.
56    var $_data_loaded = false;
57    var $op = '';
58
59    /**
60     * Constructs a new PEdit object. Initializes what file is being operated with
61     * (PHP_SELF) and what that operation is. The two
62     * operations that actually modify data (save, restore) are treated differently
63     * than view operations (versions, view, default). They die redirect so you see
64     * the page you just modified.
65     *
66     * @access public
67     * @param optional array $params  A hash containing connection parameters.
68     */
69    function PEdit($params)
70    {
71        $this->setParam($params);
72       
73        if ($this->getParam('authorized') === true) {
74            $this->_authorized = true;
75        }
76       
77        // Setup PEAR XML libraries.
78        require_once 'XML/Unserializer.php';
79        $this->xml_unserializer =& new XML_Unserializer(array(
80            XML_UNSERIALIZER_OPTION_COMPLEXTYPE => 'array',
81        ));
82        require_once 'XML/Serializer.php';
83        $this->xml_serializer =& new XML_Serializer(array(
84            XML_SERIALIZER_OPTION_INDENT        => '    ',
85            XML_SERIALIZER_OPTION_RETURN_RESULT => true
86        ));
87    }
88   
89    /**
90     * Set (or overwrite existing) parameters by passing an array of new parameters.
91     *
92     * @access public
93     * @param  array    $params     Array of parameters (key => val pairs).
94     */
95    function setParam($params)
96    {
97        $app =& App::getInstance();
98
99        if (isset($params) && is_array($params)) {
100            // Merge new parameters with old overriding only those passed.
101            $this->_params = array_merge($this->_params, $params);
102        } else {
103            $app->logMsg(sprintf('Parameters are not an array: %s', $params), LOG_WARNING, __FILE__, __LINE__);
104        }
105    }
106
107    /**
108     * Return the value of a parameter, if it exists.
109     *
110     * @access public
111     * @param string $param        Which parameter to return.
112     * @return mixed               Configured parameter value.
113     */
114    function getParam($param)
115    {
116        $app =& App::getInstance();
117
118        if (isset($this->_params[$param])) {
119            return $this->_params[$param];
120        } else {
121            $app->logMsg(sprintf('Parameter is not set: %s', $param), LOG_NOTICE, __FILE__, __LINE__);
122            return null;
123        }
124    }
125   
126    /*
127    * Load the pedit data and run automatic functions.
128    *
129    * @access   public
130    * @author   Quinn Comendant <quinn@strangecode.com>
131    * @since    12 Apr 2006 12:43:47
132    */
133    function start($initialize_data_file=false)
134    {
135        $app =& App::getInstance();
136
137        if (!is_dir($this->getParam('data_dir'))) {
138            trigger_error(sprintf('PEdit data directory not found: %s', $this->getParam('data_dir')), E_USER_WARNING);
139        }
140       
141        // The location of the data file. (i.e.: "COMMON_DIR/html/_pedit_data/news/index.xml")
142        $this->_data_file = sprintf('%s%s.xml', $this->getParam('data_dir'), $_SERVER['PHP_SELF']);
143
144        // op is used throughout the script to determine state.
145        $this->op = getFormData('op');
146
147        // Automatic functions based on state.
148        switch ($this->op) {
149        case 'Save' :
150            if ($this->_writeData()) {
151                $app->dieURL($_SERVER['PHP_SELF']);
152            }
153            break;
154        case 'Restore' :
155            if ($this->_restoreVersion(getFormData('version'))) {
156                $app->dieURL($_SERVER['PHP_SELF']);
157            }
158            break;
159        case 'View' :
160            $this->_data_file = sprintf('%s%s__%s.xml', $this->getParam('data_dir'), $_SERVER['PHP_SELF'], getFormData('version'));
161            $app->raiseMsg(sprintf(_("This is <em><strong>only a preview</strong></em> of version %s."), getFormData('version')), MSG_NOTICE, __FILE__, __LINE__);
162            break;
163        }
164       
165        // Load data.
166        $this->_loadDataFile();
167
168        if ($initialize_data_file === true) {
169            $this->_createVersion();
170            $this->_initializeDataFile();
171        }
172    }
173
174    /**
175     * Stores a variable in the pedit data array with the content name, and type of form.
176     *
177     * @access public
178     *
179     * @param string    $content         The variable containing the text to store.
180     * @param array     $options         Additional options to store with this data.
181     */
182    function set($name, $options=array())
183    {
184        $app =& App::getInstance();
185
186        $name = preg_replace('/\s/', '_', $name);
187        if (!isset($this->_data[$name])) {
188            $this->_data[$name] = array_merge(array('content' => ''), $options);
189        } else {
190            $app->logMsg(sprintf('Duplicate set data: %s', $name), LOG_NOTICE, __FILE__, __LINE__);
191        }
192    }
193
194    /**
195     * Returns the contents of a data variable. The variable must first be 'set'.
196     *
197     * @access public
198     * @param string $name   The name of the variable to return.
199     * @return string        The trimmed content of the named data.
200     */
201    function get($name)
202    {
203        $name = preg_replace('/\s/', '_', $name);
204        if ($this->op != 'Edit' && $this->op != 'Versions' && isset($this->_data[$name]['content'])) {
205            return $this->_data[$name]['content'];
206        } else {
207            return '';
208        }
209    }
210
211    /**
212     * Prints the beginning <form> HTML tag, as well as hidden input forms.
213     *
214     * @return bool  False if unauthorized or current page is a version.
215     */
216    function formBegin()
217    {
218        $app =& App::getInstance();
219
220        if (!$this->_authorized || empty($this->_data)) {
221            return false;
222        }
223        ?>       
224        <form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post" id="sc-pedit-form">
225        <input type="hidden" name="filename" value="<?php echo $_SERVER['PHP_SELF']; ?>" />
226        <input type="hidden" name="file_hash" value="<?php echo $this->_fileHash(); ?>" />
227        <?php
228        $app->printHiddenSession();
229        switch ($this->op) {
230        case 'Edit' :
231            ?>
232            <div class="sc-pedit-buttons">
233                <input type="submit" name="op" value="<?php echo _("Save"); ?>" title="<?php echo preg_replace('/^(\w)/i', '($1)', _("Save"))?>" accesskey="<?php echo substr(_("Save"), 0, 1) ?>" />
234                <input type="submit" name="op" value="<?php echo _("Cancel"); ?>" title="<?php echo preg_replace('/^(\w)/i', '($1)', _("Cancel"))?>" accesskey="<?php echo substr(_("Cancel"), 0, 1) ?>" />
235            </div>
236            <?php
237            break;
238        case 'View' :
239            ?>
240            <input type="hidden" name="version" value="<?php echo getFormData('version'); ?>" />
241            <?php
242            break;
243        }
244    }
245
246    /**
247     * Loops through the PEdit data array and prints all the HTML forms corresponding
248     * to all pedit variables, in the order in which they were 'set'.
249     *
250     * @access public
251     */
252    function printAllForms()
253    {
254        if ($this->_authorized && $this->op == 'Edit' && is_array($this->_data) && $this->_data_loaded) {
255            foreach ($this->_data as $name=>$d) {
256                $this->printForm($name);
257            }
258        }
259    }
260
261    /**
262     * Prints the HTML forms corresponding to pedit variables. Each variable
263     * must first be 'set'.
264     *
265     * @access public
266     * @param string $name      The name of the variable.
267     * @param string $type      Type of form to print. Currently only 'text' and 'textarea' supported.
268     */
269    function printForm($name, $type='text')
270    {
271        if ($this->_authorized && $this->op == 'Edit' && $this->_data_loaded) {       
272            ?>
273            <div class="sc-pedit-item">
274            <?php
275            $type = (isset($this->_data[$name]['type'])) ? $this->_data[$name]['type'] : $type;
276            // Print edit form.
277            switch ($type) {
278            case 'text' :
279            default :
280                ?>
281                <label><?php echo ucfirst(str_replace('_', ' ', $name)); ?></label>
282                <input type="text" name="_pedit_data[<?php echo $name; ?>]" id="sc-pedit-field-<?php echo $name; ?>" value="<?php echo oTxt($this->_data[$name]['content']); ?>" class="sc-full" />
283                <?php
284                break;
285            case 'textarea' :
286                ?>
287                <label><?php echo ucfirst(str_replace('_', ' ', $name)); ?></label>
288                <textarea name="_pedit_data[<?php echo $name; ?>]" id="sc-pedit-field-<?php echo $name; ?>" rows="" cols="" class="full sc-tall"><?php echo oTxt($this->_data[$name]['content']); ?></textarea>
289                <?php
290                break;
291            }
292            ?>
293            </div>
294            <?php
295        }
296    }
297
298    /**
299     * Prints the endig </form> HTML tag, as well as buttons used during
300     * different operations.
301     *
302     * @return bool  False if unauthorized or current page is a version.
303     */
304    function formEnd()
305    {
306        if (!$this->_authorized || empty($this->_data)) {
307            // Don't show form elements for versioned documents.
308            return false;
309        }
310        switch ($this->op) {
311        case 'Edit' :
312            ?>
313            <div class="sc-pedit-buttons">
314                <input type="submit" name="op" value="<?php echo _("Save"); ?>" title="<?php echo preg_replace('/^(\w)/i', '($1)', _("Save"))?>" accesskey="<?php echo substr(_("Save"), 0, 1) ?>" />
315                <input type="submit" name="op" value="<?php echo _("Cancel"); ?>" title="<?php echo preg_replace('/^(\w)/i', '($1)', _("Cancel"))?>" accesskey="<?php echo substr(_("Cancel"), 0, 1) ?>" />
316            </div>
317            </form>
318            <?php
319            break;
320        case 'Versions' :
321            ?>
322            <div class="sc-pedit-buttons">
323                <input type="submit" name="op" value="<?php echo _("Cancel"); ?>" title="<?php echo preg_replace('/^(\w)/i', '($1)', _("Cancel"))?>" accesskey="<?php echo substr(_("Cancel"), 0, 1) ?>" />
324            </div>
325            </form>
326            <?php
327            break;
328        case 'View' :
329            ?>
330            <div class="sc-pedit-buttons">
331                <input type="submit" name="op" value="<?php echo _("Restore"); ?>" title="<?php echo preg_replace('/^(\w)/i', '($1)', _("Restore"))?>" accesskey="<?php echo substr(_("Restore"), 0, 1) ?>" />
332                <input type="submit" name="op" value="<?php echo _("Versions"); ?>" title="<?php echo preg_replace('/^(\w)/i', '($1)', _("Versions"))?>" accesskey="<?php echo substr(_("Versions"), 0, 1) ?>" />
333                <input type="submit" name="op" value="<?php echo _("Cancel"); ?>" title="<?php echo preg_replace('/^(\w)/i', '($1)', _("Cancel"))?>" accesskey="<?php echo substr(_("Cancel"), 0, 1) ?>" />
334            </div>
335            </form>
336            <?php
337            break;
338        default :
339            ?>
340            <div class="sc-pedit-buttons">
341                <input type="submit" name="op" value="<?php echo _("Edit"); ?>" title="<?php echo preg_replace('/^(\w)/i', '($1)', _("Edit"))?>" accesskey="<?php echo substr(_("Edit"), 0, 1) ?>" />
342                <input type="submit" name="op" value="<?php echo _("Versions"); ?>" title="<?php echo preg_replace('/^(\w)/i', '($1)', _("Versions"))?>" accesskey="<?php echo substr(_("Versions"), 0, 1) ?>" />
343            </div>
344            </form>
345            <?php
346        }
347    }
348
349    /**
350     * Prints an HTML list of versions of current file, with the filesize
351     * and links to view and restore the file.
352     *
353     * @access public
354     */
355    function printVersions()
356    {
357        $app =& App::getInstance();
358
359        if ($this->_authorized && $this->op == 'Versions') {
360            // Print versions and commands to view/restore.
361            $version_files = $this->_getVersions();
362            ?><h1><?php printf(_("%s saved versions of %s"), sizeof($version_files), basename($_SERVER['PHP_SELF'])); ?></h1><?php
363            if (is_array($version_files) && !empty($version_files)) {
364                ?>
365                <table id="sc-pedit-versions-table">
366                <tr>
367                    <th><?php echo _("Date"); ?></th>
368                    <th><?php echo _("Time"); ?></th>
369                    <th><?php echo _("File size"); ?></th>
370                    <th><?php echo _("Version options"); ?></th>
371                </tr>
372                <?php
373                foreach ($version_files as $v) {
374                    ?>
375                    <tr>
376                        <td><?php echo date($app->getParam('date_format'), $v['unixtime']); ?></td>
377                        <td><?php echo date($app->getParam('time_format'), $v['unixtime']); ?></td>
378                        <td><?php echo humanFileSize($v['filesize']); ?></td>
379                        <td class="sc-nowrap"><a href="<?php echo $app->oHREF($_SERVER['PHP_SELF'] . '?op=View&version=' . $v['unixtime'] . '&file_hash=' . $this->_fileHash()); ?>"><?php echo _("View"); ?></a> <?php echo _("or"); ?> <a href="<?php echo $app->oHREF($_SERVER['PHP_SELF'] . '?op=Restore&version=' . $v['unixtime'] . '&file_hash=' . $this->_fileHash()); ?>"><?php echo _("Restore"); ?></a></td>
380                    </tr>
381                    <?php
382                }
383                ?>
384                </table>
385                <div class="sc-help"><?php printf(_("When there are more than %s versions, those over %s days old are deleted."), $this->getParam('versions_min_qty'), $this->getParam('versions_min_days')); ?></div>
386                <?php
387            }
388        }
389    }
390
391    /*
392    * Returns a secreat hash for the current file.
393    *
394    * @access   public
395    * @author   Quinn Comendant <quinn@strangecode.com>
396    * @since    12 Apr 2006 10:52:35
397    */
398    function _fileHash()
399    {
400        $app =& App::getInstance();
401
402        return md5($app->getParam('signing_key') . $_SERVER['PHP_SELF']);
403    }
404
405    /*
406    * Load the XML data file into $this->_data.
407    *
408    * @access   public
409    * @return   bool    false on error
410    * @author   Quinn Comendant <quinn@strangecode.com>
411    * @since    11 Apr 2006 20:36:26
412    */
413    function _loadDataFile()
414    {
415        $app =& App::getInstance();
416
417        if (!file_exists($this->_data_file)) {
418            if (!$this->_initializeDataFile()) {
419                $app->logMsg(sprintf('Initializing content file failed: %s', $this->_data_file), LOG_WARNING, __FILE__, __LINE__);
420                return false;
421            }
422        }
423        $xml_file_contents = file_get_contents($this->_data_file);
424        $status = $this->xml_unserializer->unserialize($xml_file_contents, false);   
425        if (PEAR::isError($status)) {
426            $app->logMsg(sprintf('XML_Unserialize error: %s', $status->getMessage()), LOG_WARNING, __FILE__, __LINE__);
427            return false;
428        }
429        $xml_file_data = $this->xml_unserializer->getUnserializedData();
430
431        // Only load data specified with set(), even though there may be more in the xml file.
432        foreach ($this->_data as $name => $initial_data) {
433            if (isset($xml_file_data[$name])) {
434                $this->_data[$name] = array_merge($initial_data, $xml_file_data[$name]);
435            } else {
436                $this->_data[$name] = $initial_data;
437            }
438        }
439
440        $this->_data_loaded = true;
441        return true;
442    }
443   
444    /*
445    * Start a new data file.
446    *
447    * @access   public
448    * @return   The success value of both xml_serializer->serialize() and _filePutContents()
449    * @author   Quinn Comendant <quinn@strangecode.com>
450    * @since    11 Apr 2006 20:53:42
451    */
452    function _initializeDataFile()
453    {
454        $app =& App::getInstance();
455
456        $app->logMsg(sprintf('Initializing data file: %s', $this->_data_file), LOG_INFO, __FILE__, __LINE__);
457        $xml_file_contents = $this->xml_serializer->serialize($this->_data);
458        return $this->_filePutContents($this->_data_file, $xml_file_contents);
459    }
460
461    /**
462     * Saves the POSTed data by overwriting the pedit variables in the
463     * current file.
464     *
465     * @access private
466     * @return bool  False if unauthorized or on failure. True on success.
467     */
468    function _writeData()
469    {
470        $app =& App::getInstance();
471
472        if (!$this->_authorized) {
473            return false;
474        }
475        if ($this->_fileHash() != getFormData('file_hash')) {
476            // Posted data is NOT for this file!
477            $app->logMsg(sprintf('File_hash does not match current file.', null), LOG_WARNING, __FILE__, __LINE__);
478            return false;
479        }
480
481        // Scrub incoming data. Escape tags?
482        $new_data = getFormData('_pedit_data');
483
484        if (is_array($new_data) && !empty($new_data)) {
485            // Make certain a version is created.
486            $this->_deleteOldVersions();
487            if (!$this->_createVersion()) {
488                $app->logMsg(sprintf('Failed creating new version of file.', null), LOG_NOTICE, __FILE__, __LINE__);
489                return false;
490            }
491           
492            // Collect posted data that is already specified in _data (by set()).
493            foreach ($new_data as $name => $content) {
494                if (isset($this->_data[$name])) {
495                    $this->_data[$name]['content'] = $content;
496                }
497            }
498           
499            if (is_array($this->_data) && !empty($this->_data)) {
500                $xml_file_contents = $this->xml_serializer->serialize($this->_data);
501                return $this->_filePutContents($this->_data_file, $xml_file_contents);
502            }
503        }
504    }
505   
506    /*
507    * Writes content to the specified file.
508    *
509    * @access   public
510    * @param    string  $filename   Path to file.
511    * @param    string  $content    Data to write into file.
512    * @return   bool                Success or failure.
513    * @author   Quinn Comendant <quinn@strangecode.com>
514    * @since    11 Apr 2006 22:48:30
515    */
516    function _filePutContents($filename, $content)
517    {
518        $app =& App::getInstance();
519
520        // Ensure requested filename is within the pedit data dir.
521        if (strpos($filename, $this->getParam('data_dir')) === false) {
522            $app->logMsg(sprintf('Failed writing file outside pedit _data_dir: %s', $filename), LOG_ERR, __FILE__, __LINE__);
523            return false;
524        }
525
526        // Recursively create directories.
527        $subdirs = preg_split('!/!', str_replace($this->getParam('data_dir'), '', dirname($filename)), -1, PREG_SPLIT_NO_EMPTY);
528        // Start with the pedit _data_dir base.
529        $curr_path = $this->getParam('data_dir');
530        while (!empty($subdirs)) {
531            $curr_path .= '/' . array_shift($subdirs);
532            if (!is_dir($curr_path)) {
533                if (!mkdir($curr_path)) {
534                    $app->logMsg(sprintf('Failed mkdir: %s', $curr_path), LOG_ERR, __FILE__, __LINE__);
535                    return false;
536                }
537            }
538        }
539
540        // Open file for writing and truncate to zero length.
541        if ($fp = fopen($filename, 'w')) {
542            if (flock($fp, LOCK_EX)) {
543                fwrite($fp, $content, strlen($content));
544                flock($fp, LOCK_UN);
545            } else {
546                $app->logMsg(sprintf('Could not lock file for writing: %s', $filename), LOG_ERR, __FILE__, __LINE__);
547                return false;
548            }
549            fclose($fp);
550            // Success!
551            $app->logMsg(sprintf('Wrote to file: %s', $filename), LOG_DEBUG, __FILE__, __LINE__);
552            return true;
553        } else {
554            $app->logMsg(sprintf('Could not open file for writing: %s', $filename), LOG_ERR, __FILE__, __LINE__);
555            return false;
556        }
557    }
558
559    /**
560     * Makes a copy of the current file with the unix timestamp appended to the
561     * filename.
562     *
563     * @access private
564     * @return bool  False on failure. True on success.
565     */
566    function _createVersion()
567    {
568        $app =& App::getInstance();
569
570        if (!$this->_authorized) {
571            return false;
572        }
573        if ($this->_fileHash() != getFormData('file_hash')) {
574            // Posted data is NOT for this file!
575            $app->logMsg(sprintf('File_hash does not match current file.', null), LOG_ERR, __FILE__, __LINE__);
576            return false;
577        }
578
579        // Ensure current data file exists.
580        if (!file_exists($this->_data_file)) {
581            $app->logMsg(sprintf('Data file does not yet exist: %s', $this->_data_file), LOG_NOTICE, __FILE__, __LINE__);
582            return false;
583        }
584
585        // Do the actual copy. File naming scheme must be consistent!
586        // filename.php.xml becomes filename.php__1124124128.xml
587        $version_file = sprintf('%s__%s.xml', preg_replace('/\.xml$/', '', $this->_data_file), time());
588        if (!copy($this->_data_file, $version_file)) {
589            $app->logMsg(sprintf('Failed copying new version: %s -> %s', $this->_data_file, $version_file), LOG_ERR, __FILE__, __LINE__);
590            return false;
591        }
592
593        return true;
594    }
595   
596    /*
597    * Delete all versions older than versions_min_days if there are more than versions_min_qty or 100.
598    *
599    * @access   public
600    * @return bool  False on failure. True on success.
601    * @author   Quinn Comendant <quinn@strangecode.com>
602    * @since    12 Apr 2006 11:08:11
603    */
604    function _deleteOldVersions()
605    {
606        $app =& App::getInstance();
607
608        $version_files = $this->_getVersions();
609        if (is_array($version_files) && sizeof($version_files) > $this->getParam('versions_min_qty')) {
610            // Pop oldest ones off bottom of array.
611            $oldest = array_pop($version_files);
612            // Loop while minimum X qty && minimum X days worth but never more than 100 qty.
613            while ((sizeof($version_files) > $this->getParam('versions_min_qty')
614            && $oldest['unixtime'] < mktime(date('H'), date('i'), date('s'), date('m'), date('d') - $this->getParam('versions_min_days'), date('Y')))
615            || sizeof($version_files) > 100) {
616                $del_file = dirname($this->_data_file) . '/' . $oldest['filename'];
617                if (!unlink($del_file)) {
618                    $app->logMsg(sprintf('Failed deleting version: %s', $del_file), LOG_ERR, __FILE__, __LINE__);
619                }
620                $oldest = array_pop($version_files);
621            }
622        }
623    }
624
625    /**
626     * Returns an array of all archived versions of the current file,
627     * sorted with newest versions at the top of the array.
628     *
629     * @access private
630     * @return array  Array of versions.
631     */
632    function _getVersions()
633    {
634        $version_files = array();
635        $dir_handle = opendir(dirname($this->_data_file));
636        $curr_file_preg_pattern = sprintf('/^%s__(\d+).xml$/', preg_quote(basename($_SERVER['PHP_SELF'])));
637        while ($dir_handle && ($version_file = readdir($dir_handle)) !== false) {
638            if (!preg_match('/^\./', $version_file) && !is_dir($version_file) && preg_match($curr_file_preg_pattern, $version_file, $time)) {
639                $version_files[] = array(
640                    'filename' => $version_file,
641                    'unixtime' => $time[1],
642                    'filesize' => filesize(dirname($this->_data_file) . '/' . $version_file)
643                );
644            }
645        }
646
647        if (is_array($version_files) && !empty($version_files)) {
648            array_multisort($version_files, SORT_DESC);
649            return $version_files;
650        } else {
651            return array();
652        }
653    }
654
655    /**
656     * Makes a version backup of the current file, then copies the specified
657     * archived version over the current file.
658     *
659     * @access private
660     * @param string $version    Unix timestamp of archived version to restore.
661     * @return bool  False on failure. True on success.
662     */
663    function _restoreVersion($version)
664    {
665        $app =& App::getInstance();
666
667        if (!$this->_authorized) {
668            return false;
669        }
670       
671        // The file to restore.
672        $version_file = sprintf('%s__%s.xml', preg_replace('/\.xml$/', '', $this->_data_file), $version);
673       
674        // Ensure specified version exists.
675        if (!file_exists($version_file)) {
676            $app->logMsg(sprintf('Cannot restore non-existant file: %s', $version_file), LOG_NOTICE, __FILE__, __LINE__);
677            return false;
678        }
679
680        // Make certain a version is created.
681        if (!$this->_createVersion()) {
682            $app->logMsg(sprintf('Failed creating new version of file.', null), LOG_ERR, __FILE__, __LINE__);
683            return false;
684        }
685
686        // Do the actual copy.
687        if (!copy($version_file, $this->_data_file)) {
688            $app->logMsg(sprintf('Failed copying old version: %s -> %s', $version_file, $this->_data_file), LOG_ERR, __FILE__, __LINE__);
689            return false;
690        }
691
692        // Success!
693        $app->raiseMsg(sprintf(_("Page has been restored to version %s."), $version), MSG_SUCCESS, __FILE__, __LINE__);
694        return true;
695    }
696
697} // End class.
698
699?>
Note: See TracBrowser for help on using the repository browser.