[ Index ]
 

Code source de eGroupWare 1.2.106-2

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/phpgwapi/inc/ -> class.vfs_versionsystem.inc.php (source)

   1  <?php
   2    /***************************************************************************\
   3    * eGroupWare - File Manager                                                 *
   4    * http://www.egroupware.org                                                 *
   5    * Written by:                                                               *
   6    *  - Vinicius Cubas Brand <viniciuscb@users.sourceforge.net>                *
   7    *  sponsored by Thyamad - http://www.thyamad.com                            *
   8    * ------------------------------------------------------------------------- *
   9    * Description: File version class handler for VFS (SQL implementation v2)   *
  10    * ------------------------------------------------------------------------- *
  11    *  This program is free software; you can redistribute it and/or modify it  *
  12    *  under the terms of the GNU General Public License as published by the    *
  13    *  Free Software Foundation; either version 2 of the License, or (at your   *
  14    *  option) any later version.                                               *
  15    \***************************************************************************/
  16  
  17      class vfs_versionsystem
  18      {
  19  
  20          /* The high level database handler object */
  21  //        var $db_highlevel;
  22  
  23          /* Stores the possible amount number of old file backups; In an
  24           * inserction, this number will be verified and if there are already 
  25           * $backups backed up for a file, will delete backup of the oldest
  26           * (although keeping the record of operations). 0 for no backup system
  27           * and -1 to infinite versions. */ 
  28          var $backups; 
  29  
  30          /* tmp dir (without end slash) to store temporary file backups (when
  31           * file is snapshotted) */
  32          var $tmp_dir;
  33  
  34          /* Virtual file system base class */
  35          var $vfs;
  36  
  37          /* Stores information about snapshotted files. Array with the file_id 
  38             as index. */
  39          var $snapshotted_files;
  40  
  41          /* Database handling */
  42          var $db;
  43  
  44          /* Now */
  45          var $now;
  46  
  47          var $account_id;
  48  
  49          var $last_saved_snapshot=-1;
  50  
  51          var $backup_foldername = '_backup';
  52  
  53          //Operations that create file backups
  54          var $backup_operations = array(
  55              VFS_OPERATION_EDITED
  56          );
  57  
  58          var $attributes = array(
  59              'version_id',     /* Integer. Unique to each modification. */
  60              'file_id',        /* Integer. Id of the file that modif. belongs.*/
  61              'operation',      /* Operation made in modification. */
  62              'modifiedby_id',  /* phpGW account_id of who last modified */
  63              'modified',       /* Datetime of modification, in SQL format */
  64              'version',        /* Version of file prior modification. */
  65              'comment',        /* Human-readable description of modification. */
  66              'backup_file_id', /* file_id of file that is a backup . */
  67              'backup_content', /* usable if files are stored in database. */
  68              'src',            /* source directory in a copy or move operation.*/
  69              'dest'       /* destination directory in a copy or move operation.*/
  70          );
  71  
  72          /*!
  73           * @function vfs_versionsystem
  74           * @abstract Object constructor
  75           * @author Vinicius Cubas Brand
  76           */
  77  		function vfs_versionsystem($create_vfs=true)
  78          {
  79              //use create_vfs=false and after this use $this->set_vfs to keep the
  80              // same object (i.e. use reference) in $this->vfs instead of 
  81              // creating a new object.
  82              if ($create_vfs)
  83              {
  84                  $this->vfs =& CreateObject('phpgwapi.vfs');
  85              }
  86  
  87              /* FIXME this takes a value defined in the filescenter
  88               * configuration. Better next time to take a value from global api
  89               * configuration. must fix here and in the filescenter */
  90              if (array_key_exists('filescenter',$GLOBALS['phpgw_info']['user']['preferences']))
  91              {
  92                  $this->backups = $GLOBALS['phpgw_info']['user']['preferences']['filescenter']['vfs_backups'];
  93              }
  94              else
  95              {
  96                  $this->backups = 5;
  97              }
  98  
  99              $this->snapshotted_files = array();
 100              $this->db = clone($GLOBALS['phpgw']->db);
 101              $this->now = date('Y-m-d H:i:s');
 102              $this->account_id = $GLOBALS['phpgw_info']['user']['account_id'];
 103              $this->tmp_dir = $GLOBALS['phpgw_info']['server']['temp_dir'];
 104              
 105          }
 106  
 107          /*!
 108           * @function create_initial_version()
 109           * @abstract Creates a initial journal entry for a file 
 110           * @description Must be used after a file has been created. Will create
 111           *              an initial journal entry in the database. If somehow
 112           *              the database already have any journal for that file,
 113           *              this method is wrongly called and will do nothing.
 114           *              Also if no file is found with that file_id, fails.
 115           *
 116           * @author Vinicius Cubas Brand
 117           */
 118  		function create_initial_version($file_id)
 119          {
 120              if ($GLOBALS['phpgw']->banish_journal)
 121              {
 122                  return;
 123              }
 124  
 125              $GLOBALS['phpgw']->banish_journal = true;
 126  
 127              //See if file exists
 128              $this->db->select('phpgw_vfs2_files','*',
 129                  array('file_id'=>$file_id),    __LINE__,__FILE__);
 130  
 131              if (!$this->db->next_record())
 132              {
 133                  $GLOBALS['phpgw']->banish_journal = false;
 134                  return false;
 135              }
 136  
 137              $file_record = $this->db->Record;
 138  
 139              //See if journal for the file already exists
 140              $this->db->select('phpgw_vfs2_versioning','*',
 141                  array('file_id'=>$file_id),__LINE__,__FILE__);
 142      
 143              if ($this->db->next_record())
 144              {
 145                  $GLOBALS['phpgw']->banish_journal = false;
 146                  return true; //TODO error message
 147              }
 148              
 149              $insert_data = array(
 150                  'file_id'       => $file_record['file_id'],
 151                  'operation'     => VFS_OPERATION_CREATED,
 152                  'modified'      => $this->now,
 153                  'modifiedby_id' => $this->account_id,
 154                  'version'       => '0.0.0.0'
 155              );
 156              
 157              $res = $this->db->insert('phpgw_vfs2_versioning',$insert_data,null,
 158                  __LINE__,__FILE__);
 159  
 160  /*            $this->db->update('phpgw_vfs2_files',array(
 161                      'modified' => $insert_data['modified'],
 162                      'modifiedby_id' => $insert_data['modifiedby_id']
 163                  ),
 164                  array('file_id' => $insert_data['file_id']).__LINE__,__FILE__
 165                  );*/
 166              
 167  
 168  
 169              if ($res)
 170              {
 171                  $GLOBALS['phpgw']->banish_journal = false;
 172                  return true;
 173              }
 174  
 175              $GLOBALS['phpgw']->banish_journal = false;
 176              return false;
 177          }
 178  
 179          /*!
 180           * @function save_snapshot()
 181           * @abstract Saves a snapshot from a file 
 182           * @description Must be called before any modification in a file. After
 183           * the modification was successful, one must do a vfs_version->commit()
 184           * Depending of the type of operation and how backups are set, will
 185           * handle backups. If a commit is not made until the end of the script,
 186           * no modifications in the journal will be saved.
 187           *
 188           * @param $file_id  int  The file_id 
 189           * @param $operation int  A VFS_OPERATION as defined in vfs_shared file
 190           * @param $other string  Its use will differ depending on the operation:
 191           *    Copy,Move: $other contains the fake_full_path_clean of destination
 192           *
 193           * @author Vinicius Cubas Brand
 194           * @result bool 
 195           */
 196  		function save_snapshot($file_id,$operation,$comment='',$other='')
 197          {
 198              //Prevent recursive reentrant when working in vfs->copy, f.inst
 199              if ($GLOBALS['phpgw']->banish_journal)
 200              {
 201                  return;
 202              }
 203  
 204              $GLOBALS['phpgw']->banish_journal = true;
 205  
 206              $this->db->select('phpgw_vfs2_files','*',
 207                  array('file_id'=>$file_id),    __LINE__,__FILE__);
 208  
 209              if (!$this->db->next_record())
 210              {
 211  
 212                  $GLOBALS['phpgw']->banish_journal = false;
 213                  return false;
 214              }
 215  
 216              $file_record = $this->db->Record;
 217  
 218              //If already snapshotted, will do a rollback in the old snapshot
 219              //before make a new one.
 220              if ($this->snapshotted_files[$file_record['file_id']])
 221              {
 222                  $this->rollback($file_record['file_id']);
 223              }
 224  
 225              //Create a backup if necessary
 226              if ($this->backups != 0 && in_array($operation,$this->backup_operations))
 227              {
 228                  $random_filename = $this->tmp_dir.SEP.$this->random_filename();
 229  
 230                  $this->vfs->cp(array(
 231                      'from' => $file_record['directory'].SEP.$file_record['name'],
 232                      'to'   => $random_filename,
 233                      'relatives' => array(RELATIVE_ROOT,RELATIVE_NONE|VFS_REAL)
 234                  ));
 235  
 236                  $this->vfs->set_attributes(array(
 237                      'string' => $random_filename,
 238                      'relatives' => array(RELATIVE_NONE|VFS_REAL),
 239                      'attributes' => array('is_backup' => 'Y')
 240                  ));
 241  
 242              }
 243          
 244              //backup_file_id and backup_data will be set in commit() only.
 245              $insert_data = array(
 246                  'file_id' => $file_record['file_id'],
 247                  'operation' => $operation,
 248                  'modifiedby_id' => $this->account_id,
 249                  'modified' => $this->now, //Datetime of entry
 250                  'version' => $file_record['version'],
 251                  'comment' => $comment,
 252              );
 253  
 254              if ($operation == VFS_OPERATION_COPIED || $operation == VFS_OPERATION_MOVED)
 255              {
 256                  $insert_data['src'] = $file_record['directory'].'/'.$file_record['name'];
 257                  $insert_data['dest'] = $other['dest'];
 258  
 259              }
 260  
 261              /* $file_data is the information of the file, stored in 
 262               * $this->snapshotted_files. 'insert_data' have the data to be
 263               * inserted in the versioning table, 'tmp_filename' is the name of
 264               * the temporary backup copy, if any, and 'record' is the 
 265               * information of the file before changes (that will be made between
 266               * the call to save_snapshot() and the call to commit(). 
 267               */
 268              $file_data = array(
 269                  'insert_data' => $insert_data,
 270                  'tmp_filename' => $random_filename,
 271                  'record' => $file_record
 272              );
 273  
 274              $this->snapshotted_files[$file_id] = $file_data;
 275              $this->last_saved_snapshot = $file_id;
 276  
 277              $GLOBALS['phpgw']->banish_journal = false;
 278              return true;
 279          }
 280  
 281          /*!
 282           * @function commit()
 283           * @abstract Commits the creation of a journal entry
 284           * @description Will have to be called after a save_snapshot is made.
 285           *    If a vfs_version->save_snapshot() call is not made before, this
 286           *    method does nothing. If no parameter is passed, will commit the
 287           *    file from the last saved snapshot.
 288           *
 289           * @param $file_id  int  The file_id 
 290           *
 291           * @author Vinicius Cubas Brand
 292           * @result bool 
 293           */
 294  		function commit($file_id=-1)
 295          {
 296              //Prevent recursive reentrant when working in vfs->copy, f.inst
 297              if ($GLOBALS['phpgw']->banish_journal)
 298              {
 299                  return;
 300              }
 301  
 302              $GLOBALS['phpgw']->banish_journal = true;
 303  
 304              if ($file_id == -1)
 305              {
 306                  if ($this->last_saved_snapshot == -1)
 307                  {
 308  
 309                      $GLOBALS['phpgw']->banish_journal = false;
 310                      return false;
 311                  }
 312  
 313                  $file_id = $this->last_saved_snapshot;
 314              }
 315  
 316              if (!$this->snapshotted_files[$file_id])
 317              {
 318  
 319                  $GLOBALS['phpgw']->banish_journal = false;
 320                  return false;
 321              }
 322  
 323              $file_data = $this->snapshotted_files[$file_id];
 324  
 325              //if there is any backup to be made, will make these backups and
 326              //remove too old backup versions, as defined in configuration.
 327              if ($this->backups != 0 && in_array($file_data['insert_data']['operation'],$this->backup_operations))
 328              {
 329  
 330                  //counts the number of stored backups
 331                  $where = "file_id=$file_id AND (backup_file_id != NULL OR backup_file_id != 0)";
 332  
 333                  $this->db->select('phpgw_vfs2_versioning','count(*)',$where,
 334                      __LINE__,__FILE__);
 335  
 336                  $this->db->next_record();
 337  
 338                  if ($this->db->Record[0] >= $this->backups && $this->backups != -1)
 339                  {
 340                      //Remove old backups
 341  
 342                      //Deletes oldest backup(s)
 343                      $backups_to_be_deleted = $this->db->Record[0] - $this->backups + 1;
 344  
 345                      $sql = "SELECT vers.version_id      as version_id,
 346                                     vers.backup_file_id  as backup_file_id,
 347                                     files.directory      as directory, 
 348                                     files.name           as name 
 349                              FROM   phpgw_vfs2_versioning  as vers,
 350                                     phpgw_vfs2_files       as files
 351                              WHERE  vers.file_id=$file_id 
 352                                AND  vers.backup_file_id = files.file_id 
 353                              ORDER BY vers.modified";
 354  
 355                      $this->db->query($sql,__LINE__,__FILE__);
 356  
 357                      for ($i = 0; $i < $backups_to_be_deleted; $i++)
 358                      {
 359                          //FIXME don't know why this only works 4 the 1st cycle
 360                          $this->db->next_record();
 361  
 362                          $version_file_id = $this->db->Record['backup_file_id'];
 363                          $version_id = $this->db->Record['version_id'];
 364  
 365  
 366                          $version_directory = $this->db->Record['directory'];
 367                          $version_name = $this->db->Record['name'];
 368  
 369                          //Removes old backup
 370                          $this->vfs->rm(array(
 371                              'string' => $version_directory.SEP.$version_name,
 372                              'relatives' => array(RELATIVE_ROOT)
 373                          ));
 374  
 375                          $versions_to_update[] = $version_id;
 376  
 377                      }
 378  
 379                      if ($versions_to_update)
 380                      {
 381                          //updates old journal            
 382                          $update_data = array(
 383                              'backup_file_id' => '',
 384                              'backup_content' => ''
 385                          );
 386  
 387                          foreach ($versions_to_update as $key => $val)
 388                          {
 389          
 390                              $update_where = array(
 391                                  'version_id' => $val
 392                              );
 393  
 394                              $this->db->update('phpgw_vfs2_versioning',
 395                                  $update_data,$update_where,__LINE__,__FILE__);
 396                          }
 397  
 398                      }
 399                      unset($version_id);
 400                  }
 401  
 402                  //create backup folder, if not exists
 403                  //Important: the backup dir will be inside the virtual root
 404                  $backup_foldername = $file_data['record']['directory'].SEP.$this->backup_foldername;
 405              
 406                  $dir = array(
 407                      'string' => $backup_foldername,
 408                      'relatives' => array(RELATIVE_ROOT)
 409                  );
 410  
 411                  if (!$this->vfs->file_exists($dir))
 412                  {
 413                      $this->vfs->mkdir($dir); //TODO error messages
 414  
 415                      $attributes=array_merge($dir,array(
 416                          'attributes' => array(
 417                              'is_backup' => 'Y'
 418                          )
 419                      ));
 420                  
 421                      $this->vfs->set_attributes($attributes);
 422                  }
 423  
 424                  //create a backup filename
 425                  $backup_filename = $this->backup_filename(
 426                      $file_data['record']['name'],
 427                      $file_data['insert_data']['version']
 428                  );
 429  
 430                  //move file from temporary location to its definitive location
 431                  $res = $this->vfs->mv(array(
 432                      'from' => $file_data['tmp_filename'],
 433                      'to' => $backup_foldername.SEP.$backup_filename,
 434                      'relatives' => array(RELATIVE_NONE|VFS_REAL,RELATIVE_ROOT)
 435                  ));
 436  
 437                  //sets its attribute as backup
 438                  $this->vfs->set_attributes(array(
 439                      'string' => $backup_foldername.SEP.$backup_filename,
 440                      'relatives' => array(RELATIVE_ROOT),
 441                      'attributes' => array('is_backup' => 'Y')
 442                  ));
 443  
 444                  //TODO backup content in database support
 445  
 446                  //Fetch the backup file_id to put this information in the 
 447                  //version table
 448                  if ($res)
 449                  {
 450                      $res_ls = $this->vfs->ls(array(
 451                          'string' => $backup_foldername.SEP.$backup_filename,
 452                          'relatives' => RELATIVE_ROOT,
 453                          'nofiles' => True,
 454                          'backups' => True
 455                      ));
 456  
 457                      if ($res_ls)
 458                      {
 459                          $file_data['insert_data']['backup_file_id'] = $res_ls[0]['file_id'];
 460                      }
 461                  }
 462              }
 463  
 464              $res = $this->db->insert('phpgw_vfs2_versioning',
 465                  $file_data['insert_data'],null,__LINE__,__FILE__);
 466  
 467  
 468  
 469              if ($res)
 470              {
 471                  //If operation is one of the type that increments file version
 472                  if (in_array($file_data['insert_data']['operation'],$this->backup_operations))
 473                  {
 474      
 475                      $this->db->update('phpgw_vfs2_files',
 476                          array(
 477                              'version' => $this->inc($file_data['insert_data']['version']),
 478                              'modified' => $file_data['insert_data']['modified'],
 479                              'modifiedby_id' => $file_data['insert_data']['modifiedby_id']
 480                              ),
 481                          array('file_id' => $file_data['insert_data']['file_id']),
 482                          __LINE__, __FILE__
 483                      );
 484                  }
 485  
 486                  unset($this->snapshotted_files[$file_id]);
 487                  $this->last_saved_snapshot = -1;
 488  
 489                  $GLOBALS['phpgw']->banish_journal = false;
 490                  return true;
 491              }
 492  
 493              $GLOBALS['phpgw']->banish_journal = false;
 494              return false;
 495          }
 496  
 497  
 498          /*!
 499           * @function rollback()
 500           * @abstract Rollbacks the save of the snapshot
 501           * @description Will have to be called after a save_snapshot is made.
 502           *    If a vfs_version->save_snapshot() call is not made before, this
 503           *    method does nothing. If no parameter is passed, will rollback the
 504           *    file from the last saved snapshot. This method only deletes the
 505           *    temporary backup file and the saved file information
 506           *
 507           * @param $file_id  int  The file_id 
 508           *
 509           * @author Vinicius Cubas Brand
 510           * @result bool 
 511           */
 512  		function rollback($file_id=-1)
 513          {
 514              //Prevent recursive reentrant when working in vfs->copy, f.inst
 515              if ($GLOBALS['phpgw']->banish_journal)
 516              {
 517                  return;
 518              }
 519  
 520              $GLOBALS['phpgw']->banish_journal = true;
 521  
 522              if ($file_id == -1)
 523              {
 524                  if ($this->last_saved_snapshot == -1)
 525                  {
 526  
 527                      $GLOBALS['phpgw']->banish_journal = false;
 528                      return false;
 529                  }
 530  
 531                  $file_id = $this->last_saved_snapshot;
 532              }
 533  
 534              if (!$this->snapshotted_files[$file_id])
 535              {
 536  
 537                  $GLOBALS['phpgw']->banish_journal = false;
 538                  return false;
 539              }
 540  
 541              $file_data = $this->snapshotted_files[$file_id];
 542  
 543              $this->vfs->rm(array(
 544                  'string' => $file_data['tmp_filename'],
 545                  'relatives' => array(RELATIVE_NONE | VFS_REAL)
 546              ));
 547  
 548              unset($this->snapshotted_files[$file_id]);
 549              $this->last_saved_snapshot = -1;
 550  
 551              $GLOBALS['phpgw']->banish_journal = false;
 552              return true;
 553          }
 554  
 555          /*!
 556           * @function get_journal()
 557           * @abstract Returns an array with the journal for a file
 558           */
 559  		function get_journal($file_id)
 560          {
 561              //TODO support for database-only storage.
 562              $fields = array_diff($this->attributes,array('backup_content'));
 563              
 564              $where = 'file_id='.$file_id.' ORDER BY modified DESC, version DESC, operation DESC';
 565  
 566              
 567              $this->db->select('phpgw_vfs2_versioning',$fields,$where,
 568                  __LINE__,__FILE__);
 569  
 570              while ($this->db->next_record())
 571              {
 572                  $result[] = $this->db->Record;
 573              }
 574                  
 575              return $result;    
 576          }
 577  
 578  
 579          /*!
 580           * @function inc()
 581           * @abstract Given a file version, increments it using the vfs
 582           *   versioning pattern and returns the incremented file version.
 583           *   Analyzes operation and increments the file version taking
 584           *   consideration of this operation.
 585           *
 586           * @param $version string The file version
 587           * @param $operation int Some VFS_OPERATION as defined in vfs_shared
 588           *
 589           * @result string
 590           */
 591  		function inc($version)
 592          {
 593              /*
 594               * Let's increment the version for the file itself.  We keep the
 595               * current version when making the journal entry, because that was
 596               * the version that was operated on.  The maximum numbers for each
 597               * part in the version string: none.99.9.9
 598              */
 599              $version_parts = split ("\.", $version);
 600              $newnumofparts = $numofparts = count ($version_parts);
 601  
 602              if ($version_parts[3] >= 9)
 603              {
 604                  $version_parts[3] = 0;
 605                  $version_parts[2]++;
 606                  $version_parts_3_update = 1;
 607              }
 608              elseif (isset ($version_parts[3]))
 609              {
 610                  $version_parts[3]++;
 611              }
 612  
 613              if ($version_parts[2] >= 9 && $version_parts[3] == 0 && $version_parts_3_update)
 614              {
 615                  $version_parts[2] = 0;
 616                  $version_parts[1]++;
 617              }
 618  
 619              if ($version_parts[1] > 99)
 620              {
 621                  $version_parts[1] = 0;
 622                  $version_parts[0]++;
 623              }
 624  
 625              for ($i = 0; $i < $newnumofparts; $i++)
 626              {
 627                  if (!isset ($version_parts[$i]))
 628                  {
 629                      break;
 630                  }
 631  
 632                  if ($i)
 633                  {
 634                      $newversion .= '.';
 635                  }
 636  
 637                  $newversion .= $version_parts[$i];
 638              }
 639  
 640              return $newversion;
 641          }
 642  
 643  		function set_vfs(&$vfs)
 644          {
 645              $this->vfs =& $vfs;
 646          }
 647  
 648          #helper, private functions
 649  
 650          /*!
 651           * @function random_filename()
 652           * @abstract Generates a Random Filename
 653           *
 654           * @result string
 655           */
 656  		function random_filename()
 657          {
 658              $filename = '';
 659              $filename_length = 8;
 660              while (strlen($filename) < $filename_length) {
 661                  $filename .= chr(rand (97,122));
 662              } 
 663  
 664              return $filename.'.tmp';
 665          }
 666  
 667          /*!
 668           * @function backup_filename()
 669           * @abstract Return the backup filename for a certain filename + version
 670           *
 671           * @result string
 672           */
 673  		function backup_filename($filename,$version)
 674          {
 675              $version = str_replace('.','_',$version);
 676              $fbrk = explode('.',$filename);
 677              $fbrk[0] .= '-'.$version;
 678              return implode('.',$fbrk);
 679          }
 680  
 681      }
 682  
 683  
 684  ?>


Généré le : Sun Feb 25 17:20:01 2007 par Balluche grâce à PHPXref 0.7