[1] | 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. On save, a mass search and replace is complated to inssert the new |
---|
| 8 | * data into the old file. 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. |
---|
| 16 | * include 'PEdit.inc.php'; |
---|
| 17 | * $p = new PEdit($auth->hasClearance('pedit')); |
---|
| 18 | * |
---|
| 19 | * $title = <<<P_E_D_I_T_title |
---|
| 20 | * Using Burritos to Improve Student Learnin' |
---|
| 21 | * P_E_D_I_T_title; |
---|
| 22 | * $p->set($title, 'title', 'textbox'); |
---|
| 23 | * |
---|
| 24 | * // Begin content. Include a header or something right here. |
---|
| 25 | * $p->printContent('title'); |
---|
| 26 | * |
---|
| 27 | * // Prints beginning form tags and special hidden forms. (Only happens if page is NOT a archived version.) |
---|
| 28 | * $p->formBegin(); |
---|
| 29 | * |
---|
| 30 | * // Print editing form elements. (Only happens if op == Edit.) |
---|
| 31 | * $p->printForm('title'); |
---|
| 32 | * |
---|
| 33 | * // Print versions list. (Only happens if op == Versions.) |
---|
| 34 | * $p->printVersions(); |
---|
| 35 | * |
---|
| 36 | * // Prints ending form tags and command buttons.(Only happens if page is NOT a archived version.) |
---|
| 37 | * $p->formEnd(); |
---|
| 38 | * |
---|
| 39 | * @author Quinn Comendant <quinn@strangecode.com> |
---|
| 40 | * @concept Beau Smith <beau@beausmith.com> |
---|
| 41 | * @version 1.1 |
---|
| 42 | */ |
---|
| 43 | class PEdit |
---|
| 44 | { |
---|
| 45 | var $_data = array(); // Array to store editable data. |
---|
| 46 | var $_filename = ''; // Full file path to current file. |
---|
| 47 | var $_authorized = false; // User is authenticated to see extended functions. |
---|
| 48 | var $versions_min_qty = 20; // Keep at least this many versions of each file. |
---|
| 49 | var $versions_min_days = 10;// Keep ALL versions within this many days, even if MORE than versions_min_qty. |
---|
| 50 | |
---|
| 51 | // Tags that are not stripped from the POSTed data. |
---|
| 52 | var $allowed_tags = '<p><h1><h2><h3><h4><h5><h6><div><br><hr><a><img><i><em><b><strong><small><blockquote><ul><ol><li><dl><dt><dd><map><area><table><tr><td>'; |
---|
| 53 | |
---|
| 54 | |
---|
| 55 | /** |
---|
| 56 | * Constructs a new PEdit object. Initializes what file is being operated on |
---|
| 57 | * (SCRIPT_FILENAME) and what that operation is. The two |
---|
| 58 | * operations that actually modify data (save, restore) are treated differently |
---|
| 59 | * than view operations (versions, '' - default). They die redirect so you see |
---|
| 60 | * the page you just modified. |
---|
| 61 | * |
---|
| 62 | * @access public |
---|
| 63 | * |
---|
| 64 | * @param optional array $params A hash containing connection parameters. |
---|
| 65 | */ |
---|
| 66 | function PEdit($authorized=false) |
---|
| 67 | { |
---|
| 68 | if ($authorized === true) { |
---|
| 69 | $this->_authorized = true; |
---|
| 70 | } |
---|
| 71 | |
---|
| 72 | $this->_filename = $_SERVER['SCRIPT_FILENAME']; |
---|
| 73 | if (empty($this->_filename)) { |
---|
| 74 | logMsg(sprintf('PEdit error: server variable SCRIPT_FILENAME must be defined.', null), LOG_WARNING, __FILE__, __LINE__); |
---|
| 75 | die; |
---|
| 76 | } |
---|
| 77 | |
---|
| 78 | $this->op = getFormData('op'); |
---|
| 79 | |
---|
| 80 | switch ($this->op) { |
---|
| 81 | case 'Save' : |
---|
| 82 | if ($this->_writeData()) { |
---|
| 83 | dieURL($_SERVER['PHP_SELF']); |
---|
| 84 | } |
---|
| 85 | break; |
---|
| 86 | case 'Restore' : |
---|
| 87 | if ($this->_restoreVersion(getFormData('with_file'))) { |
---|
| 88 | dieURL($_SERVER['PHP_SELF']); |
---|
| 89 | } |
---|
| 90 | break; |
---|
| 91 | } |
---|
| 92 | } |
---|
| 93 | |
---|
| 94 | /** |
---|
| 95 | * Stores a variable in the pedit data array with the content name, and type of form. |
---|
| 96 | * |
---|
| 97 | * @access public |
---|
| 98 | * |
---|
| 99 | * @param string $content The variable containing the text to store. |
---|
| 100 | * @param string $name The name of the variable. |
---|
| 101 | * @param string $type The type of form element to use. |
---|
| 102 | * @param optional int $form_size The size of the form element. |
---|
| 103 | */ |
---|
| 104 | function set($content, $name, $type, $form_size=null) |
---|
| 105 | { |
---|
| 106 | $this->_data[$name] = array( |
---|
| 107 | 'type' => $type, |
---|
| 108 | 'content' => $content, |
---|
| 109 | 'form_size' => $form_size |
---|
| 110 | ); |
---|
| 111 | } |
---|
| 112 | |
---|
| 113 | /** |
---|
| 114 | * Stores a checkbox variable in the pedit data array with the content name, and type of form. |
---|
| 115 | * |
---|
| 116 | * @access public |
---|
| 117 | * |
---|
| 118 | * @param string $content The variable containing the text to store. |
---|
| 119 | * @param string $name The name of the variable. |
---|
| 120 | * @param string $corresponding_text The text that corresponds to this checkbox. |
---|
| 121 | */ |
---|
| 122 | function setCheckbox($content, $name, $corresponding_text) |
---|
| 123 | { |
---|
| 124 | if (isset($content) && isset($name) && isset($corresponding_text)) { |
---|
| 125 | $this->_data[$name] = array( |
---|
| 126 | 'type' => 'checkbox', |
---|
| 127 | 'content' => $content, |
---|
| 128 | 'corresponding_text' => $corresponding_text |
---|
| 129 | ); |
---|
| 130 | } |
---|
| 131 | } |
---|
| 132 | |
---|
| 133 | /** |
---|
| 134 | * Tests if we are should display page contents. |
---|
| 135 | * |
---|
| 136 | * @access public |
---|
| 137 | * |
---|
| 138 | * @return bool true if we are displaying page normally, false if editing page, or viewing versions. |
---|
| 139 | */ |
---|
| 140 | function displayMode() |
---|
| 141 | { |
---|
| 142 | if ($this->op != 'Edit' && $this->op != 'Versions' && isset($this->_data[$name]['content'])) { |
---|
| 143 | return true; |
---|
| 144 | } |
---|
| 145 | } |
---|
| 146 | |
---|
| 147 | |
---|
| 148 | /** |
---|
| 149 | * Prints an HTML list of versions of current file, with the filesize |
---|
| 150 | * and links to view and restore the file. |
---|
| 151 | * |
---|
| 152 | * @access public |
---|
| 153 | */ |
---|
| 154 | function printVersions() |
---|
| 155 | { |
---|
| 156 | if ($this->_authorized && $this->op == 'Versions') { |
---|
| 157 | // Print versions and commands to view/restore. |
---|
| 158 | $versions = $this->_getVersions(); |
---|
| 159 | ?><h1><?php printf(_("%s saved versions of %s"), sizeof($versions), basename($this->_filename)); ?></h1><?php |
---|
| 160 | if (is_array($versions) && !empty($versions)) { |
---|
| 161 | ?><table border="0" cellspacing="0" cellpadding="4"><?php |
---|
| 162 | foreach ($versions as $v) { |
---|
| 163 | ?> |
---|
| 164 | <tr> |
---|
| 165 | <td valign="top" nowrap="nowrap"><p><?php echo date('r', $v['unixtime']); ?></p></td> |
---|
| 166 | <td valign="top" nowrap="nowrap"><p> <?php printf(_("%s bytes"), $v['filesize']); ?></p></td> |
---|
| 167 | <td valign="top" nowrap="nowrap"><p> [<a href="<?php echo ohref(dirname($_SERVER['PHP_SELF']) . (preg_match('!/$!', dirname($_SERVER['PHP_SELF'])) ? '' : '/') . $v['filename']); ?>" target="_blank"><?php echo _("view"); ?></a>]</p></td> |
---|
| 168 | <td valign="top" nowrap="nowrap"><p> [<a href="<?php echo ohref($_SERVER['PHP_SELF'] . '?op=Restore&with_file=' . $v['filename'] . '&file_hash=' . md5('frog_guts' . $this->_filename)); ?>"><?php echo _("restore"); ?></a>]</p></td> |
---|
| 169 | </tr> |
---|
| 170 | <?php |
---|
| 171 | } |
---|
| 172 | ?></table><?php |
---|
| 173 | ?><div class="help"><?php printf(_("When there are more than %s versions, those over %s days old are deleted."), $this->versions_min_qty, $this->versions_min_days); ?></div><?php |
---|
| 174 | } |
---|
| 175 | } |
---|
| 176 | } |
---|
| 177 | |
---|
| 178 | /** |
---|
| 179 | * Returns the contents of a data variable. The variable must first be 'set'. |
---|
| 180 | * |
---|
| 181 | * @access public |
---|
| 182 | * |
---|
| 183 | * @param string $name The name of the variable to return. |
---|
| 184 | * |
---|
| 185 | * @return string The trimmed content of the named data. |
---|
| 186 | */ |
---|
| 187 | function getContent($name, $preserve_html=true) |
---|
| 188 | { |
---|
| 189 | if ($this->op != 'Edit' && $this->op != 'Versions' && isset($this->_data[$name]['content'])) { |
---|
| 190 | // Print content. |
---|
| 191 | switch ($this->_data[$name]['type']) { |
---|
| 192 | case 'checkbox' : |
---|
| 193 | return 'off' == $this->_data[$name]['content'] ? '' : oTxt($this->_data[$name]['corresponding_text'], $preserve_html); |
---|
| 194 | default : |
---|
| 195 | return trim(oTxt($this->_data[$name]['content'], $preserve_html)); |
---|
| 196 | } |
---|
| 197 | } |
---|
| 198 | } |
---|
| 199 | |
---|
| 200 | /** |
---|
| 201 | * Prints the contents of a data variable. The variable must first be 'set'. |
---|
| 202 | * |
---|
| 203 | * @access public |
---|
| 204 | * |
---|
| 205 | * @param string $name The name of the variable to print. |
---|
| 206 | */ |
---|
| 207 | function printContent($name, $preserve_html=true) |
---|
| 208 | { |
---|
| 209 | echo $this->getContent($name, $preserve_html); |
---|
| 210 | } |
---|
| 211 | |
---|
| 212 | /** |
---|
| 213 | * Prints the HTML forms corresponding to pedit variables. Each variable |
---|
| 214 | * must first be 'set'. |
---|
| 215 | * |
---|
| 216 | * @access public |
---|
| 217 | * |
---|
| 218 | * @param string $name The name of the variable. |
---|
| 219 | */ |
---|
| 220 | function printForm($name) |
---|
| 221 | { |
---|
| 222 | if ($this->_authorized && $this->op == 'Edit' && isset($this->_data[$name]['type'])) { |
---|
| 223 | // Print edit form. |
---|
| 224 | switch ($this->_data[$name]['type']) { |
---|
| 225 | case 'textbox' : |
---|
| 226 | $rows = is_numeric($this->_data[$name]['form_size']) ? $this->_data[$name]['form_size'] : 50; |
---|
| 227 | echo '<input class="monospaced" style="width: 100%;" type="text" name="data[' . $name . ']" value="' . oTxt($this->_data[$name]['content']) . '" size="' . $rows . '" /><br />'; |
---|
| 228 | break; |
---|
| 229 | case 'textarea' : |
---|
| 230 | $rows = is_numeric($this->_data[$name]['form_size']) ? $this->_data[$name]['form_size'] : 20; |
---|
| 231 | echo '<textarea class="monospaced" style="width: 100%;" rows="' . $rows . '" cols="60" name="data[' . $name . ']">' . oTxt($this->_data[$name]['content']) . '</textarea><br />'; |
---|
| 232 | break; |
---|
| 233 | case 'checkbox' : |
---|
| 234 | $checked = ('off' == $this->_data[$name]['content']) ? '' : 'checked="checked" '; |
---|
| 235 | // Note hidden form below. If the checkbox is not checked, the hidden variable will send "off" as the variable, |
---|
| 236 | // otherwise if the form is not posted for that checkbox the update will not occur. |
---|
| 237 | ?> |
---|
| 238 | <table border="0" cellspacing="0" cellpadding="2"><tr> |
---|
| 239 | <td valign="top"><input type="hidden" name="data[<?php echo $name; ?>]" value="off" /><input type="checkbox" name="data[<?php echo $name; ?>]" <?php echo $checked; ?>/></td> |
---|
| 240 | <td valign="top"><?php echo oTxt($this->_data[$name]['corresponding_text']); ?></td> |
---|
| 241 | </tr></table> |
---|
| 242 | <?php |
---|
| 243 | break; |
---|
| 244 | } |
---|
| 245 | } |
---|
| 246 | } |
---|
| 247 | |
---|
| 248 | /** |
---|
| 249 | * Loops through the PEdit data array and prints all the HTML forms corresponding |
---|
| 250 | * to all pedit variables, in the order in which they were 'set'. |
---|
| 251 | * |
---|
| 252 | * @access public |
---|
| 253 | */ |
---|
| 254 | function printAllForms() |
---|
| 255 | { |
---|
| 256 | if ($this->_authorized && $this->op == 'Edit' && is_array($this->_data) && !empty($this->_data)) { |
---|
| 257 | foreach ($this->_data as $name=>$d) { |
---|
| 258 | $this->printForm($name); |
---|
| 259 | } |
---|
| 260 | } |
---|
| 261 | } |
---|
| 262 | |
---|
| 263 | /** |
---|
| 264 | * Prints the beginning <form> HTML tag, as well as hidden input forms. |
---|
| 265 | * |
---|
| 266 | * @return bool False if unauthorized or current page is a version. |
---|
| 267 | */ |
---|
| 268 | function formBegin() |
---|
| 269 | { |
---|
| 270 | if (!$this->_authorized || preg_match('/\.php__/', $this->_filename)) { |
---|
| 271 | // Don't show form elements for versioned documents. |
---|
| 272 | return false; |
---|
| 273 | } |
---|
| 274 | ?> |
---|
[185] | 275 | <form action="<?php echo oTxt($_SERVER['PHP_SELF']); ?>" method="post"> |
---|
[1] | 276 | <input type="hidden" name="filename" value="<?php echo $this->_filename; ?>" /> |
---|
| 277 | <input type="hidden" name="file_hash" value="<?php echo md5('frog_guts' . $this->_filename); ?>" /> |
---|
| 278 | <?php |
---|
| 279 | printHiddenSession(); |
---|
| 280 | switch ($this->op) { |
---|
| 281 | case 'Edit' : |
---|
| 282 | ?> |
---|
| 283 | <div class="pedit_buttons"> |
---|
| 284 | <input class="formsubmitbutton" type="submit" name="op" value="<?php echo _("Save"); ?>" /> |
---|
| 285 | <input class="formsubmitbutton" type="submit" name="op" value="<?php echo _("Cancel"); ?>" /> |
---|
| 286 | </div> |
---|
| 287 | <?php |
---|
| 288 | break; |
---|
| 289 | } |
---|
| 290 | } |
---|
| 291 | |
---|
| 292 | /** |
---|
| 293 | * Prints the endig </form> HTML tag, as well as buttons used during |
---|
| 294 | * different operations. |
---|
| 295 | * |
---|
| 296 | * @return bool False if unauthorized or current page is a version. |
---|
| 297 | */ |
---|
| 298 | function formEnd() |
---|
| 299 | { |
---|
| 300 | if (!$this->_authorized || preg_match('/\.php__/', $this->_filename)) { |
---|
| 301 | // Don't show form elements for versioned documents. |
---|
| 302 | return false; |
---|
| 303 | } |
---|
| 304 | switch ($this->op) { |
---|
| 305 | case 'Edit' : |
---|
| 306 | ?> |
---|
| 307 | <div class="pedit_buttons"> |
---|
| 308 | <input class="formsubmitbutton" type="submit" name="op" value="<?php echo _("Save"); ?>" /> |
---|
| 309 | <input class="formsubmitbutton" type="submit" name="op" value="<?php echo _("Cancel"); ?>" /> |
---|
| 310 | </div> |
---|
| 311 | </form> |
---|
| 312 | <?php |
---|
| 313 | break; |
---|
| 314 | case 'Versions' : |
---|
| 315 | ?> |
---|
| 316 | <div class="pedit_buttons"> |
---|
| 317 | <input class="formsubmitbutton" type="submit" name="op" value="<?php echo _("Cancel"); ?>" /> |
---|
| 318 | </div> |
---|
| 319 | </form> |
---|
| 320 | <?php |
---|
| 321 | break; |
---|
| 322 | default : |
---|
| 323 | ?> |
---|
| 324 | <div class="pedit_buttons"> |
---|
| 325 | <input class="formsubmitbutton" type="submit" name="op" value="<?php echo _("Edit"); ?>" /> |
---|
| 326 | <input class="formsubmitbutton" type="submit" name="op" value="<?php echo _("Versions"); ?>" /> |
---|
| 327 | </div> |
---|
| 328 | </form> |
---|
| 329 | <?php |
---|
| 330 | } |
---|
| 331 | } |
---|
| 332 | |
---|
| 333 | /** |
---|
| 334 | * Saves the POSTed data by overwriting the pedit variables in the |
---|
| 335 | * current file. |
---|
| 336 | * |
---|
| 337 | * @access private |
---|
| 338 | * |
---|
| 339 | * @return bool False if unauthorized or on failure. True on success. |
---|
| 340 | */ |
---|
| 341 | function _writeData() |
---|
| 342 | { |
---|
| 343 | if (!$this->_authorized) { |
---|
| 344 | return false; |
---|
| 345 | } |
---|
| 346 | if (md5('frog_guts' . $this->_filename) != getFormData('file_hash')) { |
---|
| 347 | // Posted data is NOT for this file! |
---|
| 348 | trigger_error('PEdit error: file_hash does not match current file.', E_USER_WARNING); |
---|
| 349 | return false; |
---|
| 350 | } |
---|
| 351 | $whole_file = file_get_contents($this->_filename); |
---|
| 352 | $new_data = getFormData('data'); |
---|
| 353 | $search = array(); |
---|
| 354 | $replace = array(); |
---|
| 355 | if (is_array($new_data) && !empty($new_data)) { |
---|
| 356 | foreach ($new_data as $name=>$d) { |
---|
| 357 | if ('' != $d && !preg_match('/P_E_D_I_T_/', $d)) { |
---|
| 358 | // If the new posted data is not empty, and the heredoc identifer is not in it. |
---|
| 359 | $block_identifier = 'P_E_D_I_T_' . preg_quote($name); |
---|
| 360 | if (substr_count($whole_file, $block_identifier) != 2) { |
---|
| 361 | logMsg(sprintf('PEdit error: more than one %s heredoc identifier found.', $block_identifier), LOG_NOTICE, __FILE__, __LINE__); |
---|
| 362 | return false; |
---|
| 363 | } |
---|
| 364 | // Strip extra linefeeds. For some reason POST data has double EOL chars when writing to a unix file. |
---|
| 365 | $d = preg_replace("/[\n\r]{2,}/", "\n", $d); |
---|
| 366 | $search[] = "/$block_identifier.*?\n$block_identifier;/s"; |
---|
| 367 | $replace[] = "$block_identifier\n" . strip_tags($d, $this->allowed_tags) . "\n$block_identifier;"; |
---|
| 368 | } |
---|
| 369 | } |
---|
| 370 | |
---|
| 371 | // Search and replace all blocks. |
---|
| 372 | $whole_file = preg_replace($search, $replace, $whole_file); |
---|
| 373 | |
---|
| 374 | // Probably unnecessary, testing if resulting file is empty or smaller than input. |
---|
| 375 | if (strlen($whole_file) < strlen(strip_tags(serialize($new_data), $this->allowed_tags))) { |
---|
| 376 | logMsg(sprintf('PEdit error: saved file size (%s) is less than input data size (%s).', strlen($whole_file), strlen(strip_tags(serialize($new_data), $this->allowed_tags))), LOG_NOTICE, __FILE__, __LINE__); |
---|
| 377 | return false; |
---|
| 378 | } |
---|
| 379 | |
---|
| 380 | // Make certain a version is created. |
---|
| 381 | if (! $this->_createVersion()) { |
---|
| 382 | logMsg(sprintf('PEdit error: failed creating new version of file.', null), LOG_NOTICE, __FILE__, __LINE__); |
---|
| 383 | return false; |
---|
| 384 | } |
---|
| 385 | |
---|
| 386 | // Open file for writing and truncate to zero length. |
---|
| 387 | if (is_writable($this->_filename) && $fp = fopen($this->_filename, 'w')) { |
---|
| 388 | if (flock($fp, LOCK_EX)) { |
---|
| 389 | fwrite($fp, $whole_file, strlen($whole_file)); |
---|
| 390 | flock($fp, LOCK_UN); |
---|
| 391 | } else { |
---|
| 392 | logMsg(sprintf('PEdit error: could not lock file for writing: %s', $this->_filename), LOG_NOTICE, __FILE__, __LINE__); |
---|
| 393 | return false; |
---|
| 394 | } |
---|
| 395 | fclose($fp); |
---|
| 396 | // Success! |
---|
| 397 | return true; |
---|
| 398 | } else { |
---|
| 399 | logMsg(sprintf('PEdit error: could not open file for writing: %s', $this->_filename), LOG_NOTICE, __FILE__, __LINE__); |
---|
| 400 | return false; |
---|
| 401 | } |
---|
| 402 | } |
---|
| 403 | } |
---|
| 404 | |
---|
| 405 | /** |
---|
| 406 | * Makes a copy of the current file with the unix timestamp appended to the |
---|
| 407 | * filename. Deletes old versions based on threshold of age and qty. |
---|
| 408 | * |
---|
| 409 | * @access private |
---|
| 410 | * |
---|
| 411 | * @param optional boolean $do_cleanup Set to false to turn off the |
---|
| 412 | * cleanup routine. |
---|
| 413 | * |
---|
| 414 | * @return bool False if unauthorized or on failure. True on success. |
---|
| 415 | */ |
---|
| 416 | function _createVersion($do_cleanup=true) |
---|
| 417 | { |
---|
| 418 | if (!$this->_authorized) { |
---|
| 419 | return false; |
---|
| 420 | } |
---|
| 421 | if (md5('frog_guts' . $this->_filename) != getFormData('file_hash')) { |
---|
| 422 | // Posted data is NOT for this file! |
---|
| 423 | trigger_error('PEdit error: file_hash does not match current file.', E_USER_WARNING); |
---|
| 424 | return false; |
---|
| 425 | } |
---|
| 426 | $versions = $this->_getVersions(); |
---|
| 427 | |
---|
| 428 | // Clean up old versions. |
---|
| 429 | if (is_array($versions) && sizeof($versions) > $this->versions_min_qty && $do_cleanup) { |
---|
| 430 | // Pop oldest ones off bottom of array. |
---|
| 431 | $oldest = array_pop($versions); |
---|
| 432 | // Loop while minimum X qty && minimum X days worth but never more than 100 qty. |
---|
| 433 | while ((sizeof($versions) > $this->versions_min_qty |
---|
| 434 | && $oldest['unixtime'] < mktime(date('H'),date('i'),date('s'),date('m'),date('d')-$this->versions_min_days,date('Y'))) |
---|
| 435 | || sizeof($versions) > 100) { |
---|
| 436 | unlink(dirname($this->_filename) . '/' . $oldest['filename']); |
---|
| 437 | $oldest = array_pop($versions); |
---|
| 438 | } |
---|
| 439 | } |
---|
| 440 | |
---|
| 441 | // Do the actual copy. File naming scheme must be consistent! |
---|
| 442 | if (!copy($this->_filename, $this->_filename . '__' . time() . '.php')) { |
---|
| 443 | trigger_error('PEdit error: failed copying new version. Check file and directory permissions.', E_USER_WARNING); |
---|
| 444 | return false; |
---|
| 445 | } |
---|
| 446 | |
---|
| 447 | return true; |
---|
| 448 | } |
---|
| 449 | |
---|
| 450 | /** |
---|
| 451 | * Returns an array of all archived versions of the current file, |
---|
| 452 | * sorted with newest versions at the top of the array. |
---|
| 453 | * |
---|
| 454 | * @access private |
---|
| 455 | * |
---|
| 456 | * @return array Array of versions. |
---|
| 457 | */ |
---|
| 458 | function _getVersions() |
---|
| 459 | { |
---|
| 460 | $versions = array(); |
---|
| 461 | $dir_handle = opendir(dirname($this->_filename)); |
---|
| 462 | while ($dir_handle && ($version = readdir($dir_handle)) !== false) { |
---|
| 463 | if (!preg_match('/^\./', $version) && !is_dir($version) && preg_match('/^' . preg_quote(basename($this->_filename)) . '__.*/', $version)) { |
---|
| 464 | preg_match('/.+__(\d+)\.php/', $version, $time); |
---|
| 465 | $versions[] = array( |
---|
| 466 | 'filename' => $version, |
---|
| 467 | 'unixtime' => $time[1], |
---|
| 468 | 'filesize' => filesize(dirname($this->_filename) . '/' . $version) |
---|
| 469 | ); |
---|
| 470 | } |
---|
| 471 | } |
---|
| 472 | |
---|
| 473 | if (is_array($versions) && !empty($versions)) { |
---|
| 474 | array_multisort($versions, SORT_DESC); |
---|
| 475 | return $versions; |
---|
| 476 | } else { |
---|
| 477 | return array(); |
---|
| 478 | } |
---|
| 479 | } |
---|
| 480 | |
---|
| 481 | /** |
---|
| 482 | * Makes a version backup of the current file, then copies the specified |
---|
| 483 | * archived version over the current file. |
---|
| 484 | * |
---|
| 485 | * @access private |
---|
| 486 | * |
---|
| 487 | * @param string $with_file Filename of archived version to restore. |
---|
| 488 | * |
---|
| 489 | * @return bool False if unauthorized. True on success. |
---|
| 490 | */ |
---|
| 491 | function _restoreVersion($with_file) |
---|
| 492 | { |
---|
| 493 | if (!$this->_authorized) { |
---|
| 494 | return false; |
---|
| 495 | } |
---|
| 496 | |
---|
| 497 | if (is_writable($this->_filename)) { |
---|
| 498 | // Make certain a version is created. |
---|
| 499 | if (! $this->_createVersion(false)) { |
---|
| 500 | logMsg(sprintf('PEdit error: failed creating new version of file.', null), LOG_NOTICE, __FILE__, __LINE__); |
---|
| 501 | return false; |
---|
| 502 | } |
---|
| 503 | |
---|
| 504 | // Do the actual copy. |
---|
| 505 | if (!copy(dirname($this->_filename) . '/' . $with_file, $this->_filename)) { |
---|
| 506 | logMsg(sprintf('PEdit error: failed copying old version: %s', $with_file), LOG_NOTICE, __FILE__, __LINE__); |
---|
| 507 | return false; |
---|
| 508 | } |
---|
| 509 | |
---|
| 510 | // Success! |
---|
| 511 | return true; |
---|
| 512 | } else { |
---|
| 513 | logMsg(sprintf('PEdit error: could not open file for writing: %s', $this->_filename), LOG_NOTICE, __FILE__, __LINE__); |
---|
| 514 | return false; |
---|
| 515 | } |
---|
| 516 | } |
---|
| 517 | |
---|
| 518 | // End class. |
---|
| 519 | } |
---|
| 520 | ?> |
---|