[ 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.db_backup.inc.php (source)

   1  <?php
   2      /**************************************************************************\
   3      * eGroupWare - Setup - db-backups                                          *
   4      * http://www.egroupware.org                                                *
   5      * --------------------------------------------                             *
   6      * Written and copyright by Ralf Becker <RalfBecker@outdoor-training.de>    *
   7      * --------------------------------------------                             *
   8      *  This program is free software; you can redistribute it and/or modify it *
   9      *  under the terms of the GNU General Public License as published by the   *
  10      *  Free Software Foundation; either version 2 of the License, or (at your  *
  11      *  option) any later version.                                              *
  12      \**************************************************************************/
  13      
  14      /* $Id: class.db_backup.inc.php 20295 2006-02-15 12:31:25Z  $ */
  15  
  16      define('BACKSLASH_TOKEN','##!!**bAcKsLaSh**!!##');    // used in cvs_split
  17  
  18      /**
  19       * DB independent backup and restore of eGW's DB
  20       *
  21       * @package phpgwapi
  22       * @subpackage db
  23       * @author RalfBecker-AT-outdoor-training.de
  24       * @license GPL
  25       */
  26  
  27      class db_backup
  28      {
  29          var $schema_proc;    /** schema_proc class */
  30          var $schemas = array();        /** array tablename => schema */
  31          var $exclude_tables = array(    /** exclude from backup */
  32              'egw_sessions','egw_app_sessions','phpgw_sessions','phpgw_app_sessions',    // eGW's session-tables
  33              'phpgw_anglemail',    // email's cache
  34              'egw_felamimail_cache','egw_felamimail_folderstatus','phpgw_felamimail_cache','phpgw_felamimail_folderstatus',    // felamimail's cache
  35          );
  36          var $system_tables = false;    /** regular expression to identify system-tables => ignored for schema+backup */
  37          var $egw_tables = false;    /** regurar expression to identify eGW tables => if set only they are used */
  38  
  39          /**
  40           * Constructor
  41           */
  42  		function db_backup()
  43          {
  44              if (is_object($GLOBALS['egw_setup']->oProc))    // schema_proc already instanciated, use it
  45              {
  46                  $this->schema_proc = $GLOBALS['egw_setup']->oProc;
  47              }
  48              else
  49              {
  50                  $this->schema_proc = CreateObject('phpgwapi.schema_proc');
  51              }
  52  
  53              $this->db = $this->schema_proc->m_odb;
  54              $this->adodb = &$GLOBALS['egw']->ADOdb;
  55              if (is_object($GLOBALS['egw_setup']))        // called from setup
  56              {
  57                  if ($GLOBALS['egw_setup']->config_table && $GLOBALS['egw_setup']->table_exist(array($GLOBALS['egw_setup']->config_table)))
  58                  {
  59                      $this->db->query("SELECT config_value FROM {$GLOBALS['egw_setup']->config_table} WHERE config_app='phpgwapi' AND config_name='backup_dir'",__LINE__,__FILE__);
  60                      $this->db->next_record();
  61                      if (!($this->backup_dir = $this->db->f(0)))
  62                      {
  63                          $this->db->query("SELECT config_value FROM {$GLOBALS['egw_setup']->config_table} WHERE config_app='phpgwapi' AND config_name='files_dir'",__LINE__,__FILE__);
  64                          $this->db->next_record();
  65                          $this->backup_dir = $this->db->f(0).'/db_backup';
  66                      }                    
  67                      $this->db->query("SELECT config_value FROM {$GLOBALS['egw_setup']->config_table} WHERE config_app='phpgwapi' AND config_name='system_charset'",__LINE__,__FILE__);
  68                      $this->db->next_record();
  69                      $this->charset = $this->db->f(0);
  70                      if (!$this->charset)
  71                      {
  72                          $this->db->query("SELECT content FROM {$GLOBALS['egw_setup']->lang_table} WHERE message_id='charset' AND app_name='common' AND lang!='en'",__LINE__,__FILE__);
  73                          $this->db->next_record();
  74                          $this->charset = $this->db->f(0);
  75                      }
  76                      $this->db->select($GLOBALS['egw_setup']->applications_table,'app_version',array('app_name'=>'phpgwapi'),__LINE__,__FILE__);
  77                      $this->api_version = $this->db->next_record() ? $this->db->f(0) : false;
  78                  }
  79                  if (!$this->charset) $this->charset = 'iso-8859-1';
  80              }
  81              else    // called from eGW
  82              {
  83                  $this->schema_proc = CreateObject('phpgwapi.schema_proc');
  84                  if (!($this->backup_dir = $GLOBALS['egw_info']['server']['backup_dir']))
  85                  {
  86                      $this->backup_dir = $GLOBALS['egw_info']['server']['files_dir'].'/db_backup';
  87                  }
  88                  $this->charset = $GLOBALS['egw']->translation->charset();
  89                  
  90                  $this->api_version = $GLOBALS['egw_info']['apps']['phpgwapi']['version'];
  91              }
  92              if (!is_dir($this->backup_dir) && is_writable(dirname($this->backup_dir)))
  93              {
  94                  mkdir($this->backup_dir);
  95              }
  96              switch($this->db->Type)
  97              {
  98                  case 'sapdb': 
  99                  case 'maxdb':
 100                      //$this->system_tables = '/^(sql_cursor.*|session_roles|activeconfiguration|cachestatistics|commandcachestatistics|commandstatistics|datastatistics|datavolumes|hotstandbycomponent|hotstandbygroup|instance|logvolumes|machineconfiguration|machineutilization|memoryallocatorstatistics|memoryholders|omslocks|optimizerinformation|sessions|snapshots|spinlockstatistics|version)$/i';
 101                      $this->egw_tables = '/^(egw_|phpgw_)/i';
 102                      break;
 103              }
 104          }
 105          
 106          /**
 107           * Opens the backup-file using the highest availible compression
 108           *
 109           * @param $name=false string/boolean filename to use, or false for the default one
 110           * @param $reading=false opening for reading ('rb') or writing ('wb')
 111           * @return string/resource error-msg of file-handle
 112           */
 113  		function fopen_backup($name=false,$reading=false)
 114          {
 115              if (!$name) 
 116              {
 117                  if (!$this->backup_dir || !is_writable($this->backup_dir))
 118                  {
 119                      return lang("backupdir '%1' is not writeable by the webserver",$this->backup_dir);
 120                  }
 121                  $name = $this->backup_dir.'/db_backup-'.date('YmdHi');
 122              }
 123              else    // remove the extension, to use the correct wrapper based on the extension
 124              {
 125                  $name = preg_replace('/\.(bz2|gz)$/i','',$name);
 126              }
 127              $mode = $reading ? 'rb' : 'wb';
 128  
 129              if (!($f = @fopen($file = "compress.bzip2://$name.bz2",$mode)) &&
 130                  !($f = @fopen($file = "compress.zlib://$name.gz",$mode)) &&
 131                  !($f = @fopen($file = "zlib:$name.gz",$mode)) &&    // php < 4.3
 132                  !($f = @fopen($file = $name,$mode)))
 133              {
 134                  $lang_mode = $reading ? lang('reading') : lang('writing');
 135                  return lang("Cant open '%1' for %2",$name,$lang_mode);
 136              }
 137              return $f;
 138          }
 139  
 140          /**
 141           * Backup all data in the form of a (compressed) csv file
 142           *
 143           * @param resource $f file opened with fopen for reading
 144           * @param boolean $convert_to_system_charset=false convert the restored data to the selected system-charset
 145           */ 
 146  		function restore($f,$convert_to_system_charset=false)
 147          {
 148              @set_time_limit(0);
 149              ini_set('auto_detect_line_endings',true);
 150              
 151              $this->db->transaction_begin();
 152  
 153              // drop all existing tables
 154              foreach($this->adodb->MetaTables('TABLES') as $table)
 155              {
 156                  if ($this->system_tables && preg_match($this->system_tables,$table) ||
 157                      $this->egw_tables && !preg_match($this->egw_tables,$table))
 158                  {
 159                       continue;
 160                  }
 161                  $this->schema_proc->DropTable($table);
 162              }    
 163  
 164              $table = False;
 165              $n = 0;
 166              while(!feof($f))
 167              {
 168                  $line = trim(fgets($f)); ++$n;
 169  
 170                  if (empty($line)) continue;
 171                  
 172                  if (substr($line,0,9) == 'version: ')
 173                  {
 174                      $api_version = trim(substr($line,9));
 175                      continue;
 176                  }
 177                  if (substr($line,0,9) == 'charset: ')
 178                  {
 179                      $charset = trim(substr($line,9));
 180                      // needed if mbstring.func_overload > 0, else eg. substr does not work with non ascii chars
 181                      @ini_set('mbstring.internal_encoding',$charset);
 182                      
 183                      // set the DB's client encoding (for mysql only if api_version >= 1.0.1.019)
 184                      if ((!$convert_to_system_charset || $this->db->capabilities['client_encoding']) &&
 185                          (substr($this->db->Type,0,5) != 'mysql' || !is_object($GLOBALS['egw_setup']) || 
 186                          $api_version && !$GLOBALS['egw_setup']->alessthanb($api_version,'1.0.1.019')))
 187                      {
 188                          $this->db->Link_ID->SetCharSet($charset);
 189                          if (!$convert_to_system_charset)
 190                          {
 191                              $this->schema_proc->system_charset = $charset;    // so schema_proc uses it for the creation of the tables
 192                          }
 193                      }
 194                      continue;
 195                  }
 196                  if (substr($line,0,8) == 'schema: ')
 197                  {
 198                      // create the tables in the backup set
 199                      $this->schemas = unserialize(trim(substr($line,8)));
 200                      foreach($this->schemas as $table_name => $schema)
 201                      {
 202                          echo "<pre>$table_name => ".$this->write_array($schema,1)."</pre>\n";
 203                          $this->schema_proc->CreateTable($table_name,$schema);
 204                      }
 205                      // make the schemas availible for the db-class
 206                      $GLOBALS['egw_info']['apps']['all-apps']['table_defs'] = &$this->schemas;
 207                      continue;
 208                  }
 209                  if (substr($line,0,7) == 'table: ')
 210                  {
 211                      $table = substr($line,7);
 212                      
 213                      $cols = $this->csv_split($line=fgets($f)); ++$n;
 214  
 215                      if (feof($f)) break;
 216                      continue;
 217                  }
 218                  if ($convert_to_system_charset && !$this->db->capabilities['client_encoding'])
 219                  {
 220                      if ($GLOBALS['egw_setup'])
 221                      {
 222                          if (!is_object($GLOBALS['egw_setup']->translation->sql))
 223                          {
 224                              $GLOBALS['egw_setup']->translation->setup_translation_sql();
 225                          }
 226                          $translation =& $GLOBALS['egw_setup']->translation->sql;
 227                      }
 228                      else
 229                      {
 230                          $translation =& $GLOBALS['egw']->translation;
 231                      }
 232                  }
 233                  if ($table)    // do we already reached the data part
 234                  {
 235                      $data = $this->csv_split($line,$cols);
 236  
 237                      if (count($data) == count($cols))
 238                      {
 239                          if ($convert_to_system_charset && !$this->db->capabilities['client_encoding'])
 240                          {
 241                              $translation->convert($data,$charset);
 242                          }
 243                          $this->db->insert($table,$data,False,__LINE__,__FILE__,'all-apps',true);
 244                      }
 245                      else 
 246                      {
 247                          echo '<p>'.lang("Line %1: '%2'<br><b>csv data does not match column-count of table %3 ==> ignored</b>",$n,$line,$table)."</p>\n";
 248                          echo 'data=<pre>'.print_r($data,true)."</pre>\n";
 249                      }
 250                  }
 251              }
 252              // updated the sequences, if the DB uses them
 253              foreach($this->schemas as $table => $schema)
 254              {
 255                  foreach($schema['fd'] as $column => $definition)
 256                  {
 257                      if ($definition['type'] == 'auto')
 258                      {
 259                          $this->schema_proc->UpdateSequence($table,$column);
 260                          break;    // max. one per table
 261                      }
 262                  }
 263              }
 264              
 265              if ($convert_to_system_charset)    // store the changed charset
 266              {
 267                  $this->db->insert($GLOBALS['egw_setup']->config_table,array(
 268                      'config_value' => $GLOBALS['egw_setup']->system_charset,
 269                  ),array(
 270                      'config_app' => 'phpgwapi',
 271                      'config_name' => 'system_charset',
 272                  ),__LINE__,__FILE__);
 273              }
 274              $this->db->transaction_commit();
 275          }
 276                  
 277          /**
 278           * Split one line of a csv file into an array and does all unescaping
 279           * @internal
 280           */
 281  		function csv_split($line,$keys=False)
 282          {
 283              $fields = explode(',',trim($line));
 284              
 285              $str_pending = False;
 286              $n = 0;
 287              foreach($fields as $i => $field)
 288              {
 289                  if ($str_pending !== False)
 290                  {
 291                      $field = $str_pending.','.$field;
 292                      $str_pending = False;
 293                  }
 294                  $key = $keys ? $keys[$n] : $n;
 295  
 296                  if ($field[0] == '"')
 297                  {
 298                      if (substr($field,-1) !== '"' || $field === '"' || !preg_match('/[^\\\\]+(\\\\\\\\)*"$/',$field))
 299                      {
 300                          $str_pending = $field;
 301                          continue;
 302                      }
 303                      $arr[$key] = str_replace(BACKSLASH_TOKEN,'\\',str_replace(array('\\\\','\\n','\\r','\\"'),array(BACKSLASH_TOKEN,"\n","\r",'"'),substr($field,1,-1)));
 304                  }
 305                  else
 306                  {
 307                      $arr[$key] = $field == 'NULL' ? NULL : $field;
 308                  }
 309                  ++$n;
 310              }
 311              return $arr;
 312          }
 313  
 314          /**
 315           * @internal
 316           */
 317  		function escape_data(&$data,$col,$defs)
 318          {
 319              if (is_null($data))
 320              {
 321                  $data = 'NULL';
 322              }
 323              else
 324              {
 325                  switch($defs[$col]['type'])
 326                  {
 327                      case 'int': 
 328                      case 'auto':
 329                      case 'decimal':
 330                      case 'date':
 331                      case 'timestamp':
 332                          break;
 333                      default:
 334                          $data = '"'.str_replace(array('\\',"\n","\r",'"'),array('\\\\','\\n','\\r','\\"'),$data).'"';
 335                          break;
 336                  }
 337              }
 338          }
 339          
 340          /**
 341           * Backup all data in the form of a (compressed) csv file
 342           *
 343           * @param f resource file opened with fopen for writing
 344           */ 
 345  		function backup($f)
 346          {
 347              @set_time_limit(0);
 348  
 349              fwrite($f,"eGroupWare backup from ".date('Y-m-d H:i:s')."\n\n");
 350  
 351              fwrite($f,"version: $this->api_version\n\n");
 352              
 353              fwrite($f,"charset: $this->charset\n\n");
 354  
 355              $this->schema_backup($f);    // add the schema in a human readable form too
 356              
 357              /* not needed, already done by schema_backup
 358              foreach($this->adodb->MetaTables('TABLES') as $table)
 359              {
 360                  if ($this->db->Type == 'sapdb' || $this->db->Type == 'maxdb')
 361                  {
 362                      $table = strtolower($table);
 363                  }
 364                  if (!($this->schemas[$table] = $this->schema_proc->GetTableDefinition($table)))
 365                  {
 366                      unset($this->schemas[$table]);
 367                  } 
 368              }
 369              */
 370              fwrite($f,"\nschema: ".serialize($this->schemas)."\n");
 371  
 372              foreach($this->schemas as $table => $schema)
 373              {
 374                  if (in_array($table,$this->exclude_tables)) continue;    // dont backup
 375  
 376                  $first_row = true;
 377                  $this->db->select($table,'*',false,__LINE__,__FILE__);
 378                  while(($row = $this->db->row(true)))
 379                  {
 380                      if ($first_row)
 381                      {
 382                          fwrite($f,"\ntable: $table\n".implode(',',array_keys($row))."\n");
 383                          $first_row = false;
 384                      }
 385                      array_walk($row,array('db_backup','escape_data'),$schema['fd']);
 386                      fwrite($f,implode(',',$row)."\n");
 387                  }
 388              }
 389              return true;        
 390          }
 391  
 392          /**
 393           * Backup all schemas in the form of a setup/tables_current.inc.php file
 394           *
 395           * @param f resource/boolean 
 396           */ 
 397  		function schema_backup($f=False)
 398          {
 399              foreach($this->adodb->MetaTables('TABLES') as $table)
 400              {
 401                  if ($this->system_tables && preg_match($this->system_tables,$table) ||
 402                      $this->egw_tables && !preg_match($this->egw_tables,$table))
 403                  {
 404                      continue;
 405                  }
 406                  if ($this->db->Type == 'sapdb' || $this->db->Type == 'maxdb')
 407                  {
 408                      $table = strtolower($table);
 409                  }
 410                  if (!($this->schemas[$table] = $this->schema_proc->GetTableDefinition($table)))
 411                  {
 412                      unset($this->schemas[$table]);
 413                  }
 414                  if (($this->db->Type == 'sapdb' || $this->db->Type == 'maxdb') && $table == 'phpgw_anglemail')
 415                  {
 416                      // sapdb does not differ between text and blob
 417                      $this->schemas[$table]['fd']['content']['type'] = 'blob';
 418                  }
 419              }
 420              $def = "\t\$phpgw_baseline = ";
 421              $def .= $this->write_array($this->schemas,1);
 422              $def .= ";\n";
 423  
 424              if ($f)
 425              {
 426                  fwrite($f,$def);
 427              }
 428              else
 429              {
 430                  if (!is_object($this->browser))
 431                  {
 432                      $this->browser = CreateObject('phpgwapi.browser');
 433                  }
 434                  $this->browser->content_header('schema-backup-'.date('YmdHi').'.inc.php','text/plain',strlen($def));
 435                  echo "<?php\n\t/* eGroupWare schema-backup from ".date('Y-m-d H:i:s')." */\n\n".$def;
 436              }
 437          }
 438          
 439          /**
 440           * @internal copied from etemplate/inc/class.db_tools.inc.php
 441           */
 442  		function write_array($arr,$depth,$parent='')
 443          {
 444              if (in_array($parent,array('pk','fk','ix','uc')))
 445              {
 446                  $depth = 0;
 447              }
 448              if ($depth)
 449              {
 450                  $tabs = "\n";
 451                  for ($n = 0; $n < $depth; ++$n)
 452                  {
 453                      $tabs .= "\t";
 454                  }
 455                  ++$depth;
 456              }
 457              $def = "array($tabs".($tabs ? "\t" : '');
 458  
 459              $n = 0;
 460              foreach($arr as $key => $val)
 461              {
 462                  if (!is_int($key))
 463                  {
 464                      $def .= "'$key' => ";
 465                  }
 466                  if (is_array($val))
 467                  {
 468                      $def .= $this->write_array($val,$parent == 'fd' ? 0 : $depth,$key);
 469                  }
 470                  else
 471                  {
 472                      if (!$only_vals && $key === 'nullable')
 473                      {
 474                          $def .= $val ? 'True' : 'False';
 475                      }
 476                      else
 477                      {
 478                          $def .= "'$val'";
 479                      }
 480                  }
 481                  if ($n < count($arr)-1)
 482                  {
 483                      $def .= ",$tabs".($tabs ? "\t" : '');
 484                  }
 485                  ++$n;
 486              }
 487              $def .= "$tabs)";
 488  
 489              return $def;
 490          }
 491      }
 492  /*    
 493  $line = '"de","ranking","use \\"yes\\", or \\"no, prefession\\"","benützen Sie \\"yes\\" oder \\"no, Beruf\\""';
 494  
 495  echo "<p>line='$line'</p>\n";
 496  echo "<pre>".print_r(db_backup::csv_split($line),true)."</pre>\n";
 497  */


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