Aleksander Machniak
2013-06-14 461a30d771edd8bc6606f2c92dfde363514b93b1
commit | author | age
354978 1 <?php
T 2
3 /*
4  +-----------------------------------------------------------------------+
5  | rcube_install.php                                                     |
6  |                                                                       |
e019f2 7  | This file is part of the Roundcube Webmail package                    |
471d55 8  | Copyright (C) 2008-2012, The Roundcube Dev Team                       |
7fe381 9  |                                                                       |
T 10  | Licensed under the GNU General Public License version 3 or            |
11  | any later version with exceptions for skins & plugins.                |
12  | See the README file for a full license statement.                     |
354978 13  +-----------------------------------------------------------------------+
T 14 */
15
16
17 /**
e019f2 18  * Class to control the installation process of the Roundcube Webmail package
354978 19  *
T 20  * @category Install
e019f2 21  * @package  Roundcube
354978 22  * @author Thomas Bruederli
T 23  */
24 class rcube_install
25 {
26   var $step;
237119 27   var $is_post = false;
354978 28   var $failures = 0;
c5042d 29   var $config = array();
b3f9df 30   var $configured = false;
c5042d 31   var $last_error = null;
ad43e6 32   var $email_pattern = '([a-z0-9][a-z0-9\-\.\+\_]*@[a-z0-9]([a-z0-9\-][.]?)*[a-z0-9])';
871ca9 33   var $bool_config_props = array();
e10712 34
e6bb83 35   var $obsolete_config = array('db_backend', 'double_auth');
cbffc2 36   var $replaced_config = array(
651c7b 37     'skin_path'            => 'skin',
AM 38     'locale_string'        => 'language',
39     'multiple_identities'  => 'identities_level',
2a4135 40     'addrbook_show_images' => 'show_images',
651c7b 41     'imap_root'            => 'imap_ns_personal',
AM 42     'pagesize'             => 'mail_pagesize',
c321a9 43     'default_imap_folders' => 'default_folders',
651c7b 44     'top_posting'          => 'reply_mode',
cbffc2 45   );
08ffd9 46
398bff 47   // list of supported database drivers
AM 48   var $supported_dbs = array(
49     'MySQL'               => 'pdo_mysql',
50     'PostgreSQL'          => 'pdo_pgsql',
51     'SQLite'              => 'pdo_sqlite',
52     'SQLite (v2)'         => 'pdo_sqlite2',
53     'SQL Server (SQLSRV)' => 'pdo_sqlsrv',
54     'SQL Server (DBLIB)'  => 'pdo_dblib',
55   );
56
57
354978 58   /**
T 59    * Constructor
60    */
66d309 61   function __construct()
354978 62   {
T 63     $this->step = intval($_REQUEST['_step']);
237119 64     $this->is_post = $_SERVER['REQUEST_METHOD'] == 'POST';
354978 65   }
d68c90 66
c5042d 67   /**
T 68    * Singleton getter
69    */
66d309 70   static function get_instance()
c5042d 71   {
T 72     static $inst;
d68c90 73
c5042d 74     if (!$inst)
T 75       $inst = new rcube_install();
d68c90 76
c5042d 77     return $inst;
T 78   }
d68c90 79
354978 80   /**
c5042d 81    * Read the local config files and store properties
T 82    */
83   function load_config()
84   {
461a30 85     // defaults
AM 86     if ($config = $this->load_config_file(RCUBE_CONFIG_DIR . 'defaults.inc.php')) {
87         $this->config = (array) $config;
88         $this->defaults = $this->config;
89     }
90
91     $config = null;
92
93     // config
94     if ($config = $this->load_config_file(RCUBE_CONFIG_DIR . 'config.inc.php')) {
95         $this->config = array_merge($this->config, $config);
96     }
97     else {
98       if ($config = $this->load_config_file(RCUBE_CONFIG_DIR . 'main.inc.php')) {
99         $this->config = array_merge($this->config, $config);
100       }
101       if ($config = $this->load_config_file(RCUBE_CONFIG_DIR . 'db.inc.php')) {
102         $this->config = array_merge($this->config, $config);
103       }
104     }
105
106     $this->configured = !empty($config);
c5042d 107   }
T 108
109   /**
110    * Read the default config file and store properties
111    */
461a30 112   public function load_config_file($file)
c5042d 113   {
461a30 114     if (is_readable($file)) {
AM 115       include $file;
116
117       // deprecated name of config variable
118       if (is_array($rcmail_config)) {
119         return $rcmail_config;
120       }
121
122       return $config;
354978 123     }
T 124   }
d68c90 125
354978 126   /**
T 127    * Getter for a certain config property
128    *
129    * @param string Property name
ad43e6 130    * @param string Default value
354978 131    * @return string The property value
T 132    */
fa7539 133   function getprop($name, $default = '')
354978 134   {
b77d0d 135     $value = $this->config[$name];
d68c90 136
ccb412 137     if ($name == 'des_key' && !$this->configured && !isset($_REQUEST["_$name"]))
807d17 138       $value = rcube_install::random_key(24);
d68c90 139
fa7539 140     return $value !== null && $value !== '' ? $value : $default;
354978 141   }
403f0b 142
A 143
354978 144   /**
461a30 145    * Create configuration file that contains parameters
AM 146    * that differ from default values.
354978 147    *
T 148    * @return string The complete config file content
149    */
461a30 150   function create_config()
354978 151   {
461a30 152     $config = array();
0c3bde 153
c5042d 154     foreach ($this->config as $prop => $default) {
0829b7 155       $is_default = !isset($_POST["_$prop"]);
A 156       $value      = !$is_default || $this->bool_config_props[$prop] ? $_POST["_$prop"] : $default;
403f0b 157
354978 158       // convert some form data
0829b7 159       if ($prop == 'debug_level' && !$is_default) {
A 160         if (is_array($value)) {
161           $val = 0;
7d7f67 162           foreach ($value as $dbgval)
b77d0d 163             $val += intval($dbgval);
0829b7 164           $value = $val;
A 165         }
354978 166       }
0c3bde 167       else if ($which == 'db' && $prop == 'db_dsnw' && !empty($_POST['_dbtype'])) {
237119 168         if ($_POST['_dbtype'] == 'sqlite')
T 169           $value = sprintf('%s://%s?mode=0646', $_POST['_dbtype'], $_POST['_dbname']{0} == '/' ? '/' . $_POST['_dbname'] : $_POST['_dbname']);
0829b7 170         else if ($_POST['_dbtype'])
b61965 171           $value = sprintf('%s://%s:%s@%s/%s', $_POST['_dbtype'], 
7d7f67 172             rawurlencode($_POST['_dbuser']), rawurlencode($_POST['_dbpass']), $_POST['_dbhost'], $_POST['_dbname']);
c5042d 173       }
T 174       else if ($prop == 'smtp_auth_type' && $value == '0') {
175         $value = '';
176       }
177       else if ($prop == 'default_host' && is_array($value)) {
807d17 178         $value = rcube_install::_clean_array($value);
c5042d 179         if (count($value) <= 1)
T 180           $value = $value[0];
181       }
08ffd9 182       else if ($prop == 'mail_pagesize' || $prop == 'addressbook_pagesize') {
ccb412 183         $value = max(2, intval($value));
T 184       }
c5042d 185       else if ($prop == 'smtp_user' && !empty($_POST['_smtp_user_u'])) {
T 186         $value = '%u';
187       }
188       else if ($prop == 'smtp_pass' && !empty($_POST['_smtp_user_u'])) {
189         $value = '%p';
190       }
c321a9 191       else if ($prop == 'default_folders') {
d68c90 192         $value = array();
AM 193         foreach ($this->config['default_folders'] as $_folder) {
194           switch ($_folder) {
195           case 'Drafts': $_folder = $this->config['drafts_mbox']; break;
196           case 'Sent':   $_folder = $this->config['sent_mbox']; break;
197           case 'Junk':   $_folder = $this->config['junk_mbox']; break;
198           case 'Trash':  $_folder = $this->config['trash_mbox']; break;
569654 199           }
d68c90 200         if (!in_array($_folder, $value))
AM 201           $value[] = $_folder;
569654 202         }
A 203       }
c5042d 204       else if (is_bool($default)) {
27564f 205         $value = (bool)$value;
T 206       }
207       else if (is_numeric($value)) {
208         $value = intval($value);
c5042d 209       }
403f0b 210
c5042d 211       // skip this property
461a30 212       if (!array_key_exists($prop, $this->defaults) || ($value == $this->defaults[$prop])) {
c5042d 213         continue;
461a30 214       }
b77d0d 215
A 216       // save change
217       $this->config[$prop] = $value;
461a30 218       $config[$prop] = $value;
354978 219     }
0c3bde 220
461a30 221     // sort by option name
AM 222     ksort($config);
223
224     $out = "<?php\n\n";
225     foreach ($config as $prop => $value) {
226       // @TODO: copy option descriptions from defaults.inc.php file?
227       $out .= "\$config['$prop'] = " . rcube_install::_dump_var($value, $prop) . ";\n";
228     }
229     $out .= "\n?>";
230
231     return $out;
c5042d 232   }
e10712 233
T 234
235   /**
236    * Check the current configuration for missing properties
237    * and deprecated or obsolete settings
238    *
239    * @return array List with problems detected
240    */
241   function check_config()
242   {
243     $this->load_config();
461a30 244
AM 245     if (!$this->configured) {
e10712 246       return null;
461a30 247     }
d68c90 248
e10712 249     $out = $seen = array();
d68c90 250
cbffc2 251     // iterate over the current configuration
e10712 252     foreach ($this->config as $prop => $value) {
T 253       if ($replacement = $this->replaced_config[$prop]) {
254         $out['replaced'][] = array('prop' => $prop, 'replacement' => $replacement);
255         $seen[$replacement] = true;
256       }
257       else if (!$seen[$prop] && in_array($prop, $this->obsolete_config)) {
258         $out['obsolete'][] = array('prop' => $prop);
259         $seen[$prop] = true;
260       }
261     }
d68c90 262
15a049 263     // the old default mime_magic reference is obsolete
TB 264     if ($this->config['mime_magic'] == '/usr/share/misc/magic') {
265         $out['obsolete'][] = array('prop' => 'mime_magic', 'explain' => "Set value to null in order to use system default");
e10712 266     }
f8c06e 267
871ca9 268     // check config dependencies and contradictions
T 269     if ($this->config['enable_spellcheck'] && $this->config['spellcheck_engine'] == 'pspell') {
270       if (!extension_loaded('pspell')) {
271         $out['dependencies'][] = array('prop' => 'spellcheck_engine',
272           'explain' => 'This requires the <tt>pspell</tt> extension which could not be loaded.');
273       }
924b1a 274       else if (!empty($this->config['spellcheck_languages'])) {
01a8c5 275         foreach ($this->config['spellcheck_languages'] as $lang => $descr)
471d55 276           if (!@pspell_new($lang))
01a8c5 277             $out['dependencies'][] = array('prop' => 'spellcheck_languages',
T 278               'explain' => "You are missing pspell support for language $lang ($descr)");
871ca9 279       }
T 280     }
d68c90 281
871ca9 282     if ($this->config['log_driver'] == 'syslog') {
T 283       if (!function_exists('openlog')) {
284         $out['dependencies'][] = array('prop' => 'log_driver',
3a81af 285           'explain' => 'This requires the <tt>syslog</tt> extension which could not be loaded.');
871ca9 286       }
T 287       if (empty($this->config['syslog_id'])) {
288         $out['dependencies'][] = array('prop' => 'syslog_id',
289           'explain' => 'Using <tt>syslog</tt> for logging requires a syslog ID to be configured');
290       }
5f25a1 291     }
d68c90 292
5f25a1 293     // check ldap_public sources having global_search enabled
T 294     if (is_array($this->config['ldap_public']) && !is_array($this->config['autocomplete_addressbooks'])) {
295       foreach ($this->config['ldap_public'] as $ldap_public) {
296         if ($ldap_public['global_search']) {
297           $out['replaced'][] = array('prop' => 'ldap_public::global_search', 'replacement' => 'autocomplete_addressbooks');
298           break;
299         }
300       }
871ca9 301     }
d68c90 302
e10712 303     return $out;
T 304   }
d68c90 305
AM 306
e10712 307   /**
T 308    * Merge the current configuration with the defaults
309    * and copy replaced values to the new options.
310    */
311   function merge_config()
312   {
313     $current = $this->config;
314     $this->config = array();
0829b7 315
e6bb83 316     foreach ($this->replaced_config as $prop => $replacement) {
e10712 317       if (isset($current[$prop])) {
T 318         if ($prop == 'skin_path')
319           $this->config[$replacement] = preg_replace('#skins/(\w+)/?$#', '\\1', $current[$prop]);
cbffc2 320         else if ($prop == 'multiple_identities')
T 321           $this->config[$replacement] = $current[$prop] ? 2 : 0;
e10712 322         else
T 323           $this->config[$replacement] = $current[$prop];
e6bb83 324       }
T 325       unset($current[$prop]);
e10712 326     }
d68c90 327
e10712 328     foreach ($this->obsolete_config as $prop) {
T 329       unset($current[$prop]);
330     }
d68c90 331
5f25a1 332     // add all ldap_public sources having global_search enabled to autocomplete_addressbooks
T 333     if (is_array($current['ldap_public'])) {
334       foreach ($current['ldap_public'] as $key => $ldap_public) {
335         if ($ldap_public['global_search']) {
336           $this->config['autocomplete_addressbooks'][] = $key;
337           unset($current['ldap_public'][$key]['global_search']);
338         }
339       }
340     }
d68c90 341
461a30 342     $this->config = array_merge($this->config, $current);
0829b7 343
3725cf 344     foreach (array_keys((array)$current['ldap_public']) as $key) {
5f25a1 345       $this->config['ldap_public'][$key] = $current['ldap_public'][$key];
T 346     }
e10712 347   }
d68c90 348
2491c6 349   /**
T 350    * Compare the local database schema with the reference schema
e019f2 351    * required for this version of Roundcube
2491c6 352    *
3725cf 353    * @param rcube_db Database object
AM 354    *
2491c6 355    * @return boolean True if the schema is up-to-date, false if not or an error occured
T 356    */
3725cf 357   function db_schema_check($DB)
2491c6 358   {
T 359     if (!$this->configured)
360       return false;
d68c90 361
e6bb83 362     // read reference schema from mysql.initial.sql
T 363     $db_schema = $this->db_read_schema(INSTALL_PATH . 'SQL/mysql.initial.sql');
2491c6 364     $errors = array();
d68c90 365
2491c6 366     // check list of tables
T 367     $existing_tables = $DB->list_tables();
f6ee6f 368
2491c6 369     foreach ($db_schema as $table => $cols) {
399db1 370       $table = $this->config['db_prefix'] . $table;
e6bb83 371       if (!in_array($table, $existing_tables)) {
T 372         $errors[] = "Missing table '".$table."'";
373       }
374       else {  // compare cols
375         $db_cols = $DB->list_cols($table);
376         $diff = array_diff(array_keys($cols), $db_cols);
377         if (!empty($diff))
378           $errors[] = "Missing columns in table '$table': " . join(',', $diff);
379       }
2491c6 380     }
398bff 381
2491c6 382     return !empty($errors) ? $errors : false;
T 383   }
e6bb83 384
T 385   /**
386    * Utility function to read database schema from an .sql file
387    */
388   private function db_read_schema($schemafile)
389   {
390     $lines = file($schemafile);
391     $table_block = false;
392     $schema = array();
393     foreach ($lines as $line) {
394       if (preg_match('/^\s*create table `?([a-z0-9_]+)`?/i', $line, $m)) {
395         $table_block = $m[1];
396       }
397       else if ($table_block && preg_match('/^\s*`?([a-z0-9_-]+)`?\s+([a-z]+)/', $line, $m)) {
398         $col = $m[1];
399         if (!in_array(strtoupper($col), array('PRIMARY','KEY','INDEX','UNIQUE','CONSTRAINT','REFERENCES','FOREIGN'))) {
400           $schema[$table_block][$col] = $m[2];
401         }
402       }
403     }
398bff 404
e6bb83 405     return $schema;
871ca9 406   }
5fed07 407
AM 408
871ca9 409   /**
c5042d 410    * Getter for the last error message
T 411    *
412    * @return string Error message or null if none exists
413    */
414   function get_error()
415   {
416       return $this->last_error['message'];
354978 417   }
5fed07 418
AM 419
354978 420   /**
112c54 421    * Return a list with all imap hosts configured
T 422    *
423    * @return array Clean list with imap hosts
424    */
425   function get_hostlist()
426   {
427     $default_hosts = (array)$this->getprop('default_host');
428     $out = array();
5fed07 429
112c54 430     foreach ($default_hosts as $key => $name) {
T 431       if (!empty($name))
058eb6 432         $out[] = rcube_parse_host(is_numeric($key) ? $name : $key);
112c54 433     }
5fed07 434
112c54 435     return $out;
e6bb83 436   }
7177b5 437
e6bb83 438   /**
T 439    * Create a HTML dropdown to select a previous version of Roundcube
440    */
441   function versions_select($attrib = array())
442   {
443     $select = new html_select($attrib);
7177b5 444     $select->add(array(
A 445         '0.1-stable', '0.1.1',
446         '0.2-alpha', '0.2-beta', '0.2-stable',
447         '0.3-stable', '0.3.1',
448         '0.4-beta', '0.4.2',
c2c1bb 449         '0.5-beta', '0.5', '0.5.1', '0.5.2', '0.5.3', '0.5.4',
7177b5 450         '0.6-beta', '0.6',
c2c1bb 451         '0.7-beta', '0.7', '0.7.1', '0.7.2', '0.7.3', '0.7.4',
AM 452         '0.8-beta', '0.8-rc', '0.8.0', '0.8.1', '0.8.2', '0.8.3', '0.8.4', '0.8.5', '0.8.6',
1aff0e 453         '0.9-beta', '0.9-rc', '0.9-rc2',
AM 454         // Note: Do not add newer versions here
7177b5 455     ));
e6bb83 456     return $select;
112c54 457   }
7177b5 458
e49064 459   /**
T 460    * Return a list with available subfolders of the skin directory
461    */
462   function list_skins()
463   {
464     $skins = array();
465     $skindir = INSTALL_PATH . 'skins/';
466     foreach (glob($skindir . '*') as $path) {
467       if (is_dir($path) && is_readable($path)) {
468         $skins[] = substr($path, strlen($skindir));
469       }
470     }
471     return $skins;
472   }
5fed07 473
112c54 474   /**
354978 475    * Display OK status
T 476    *
477    * @param string Test name
478    * @param string Confirm message
479    */
480   function pass($name, $message = '')
481   {
482     echo Q($name) . ':&nbsp; <span class="success">OK</span>';
6557d3 483     $this->_showhint($message);
354978 484   }
5fed07 485
AM 486
354978 487   /**
T 488    * Display an error status and increase failure count
489    *
490    * @param string Test name
491    * @param string Error message
492    * @param string URL for details
493    */
494   function fail($name, $message = '', $url = '')
495   {
496     $this->failures++;
5fed07 497
354978 498     echo Q($name) . ':&nbsp; <span class="fail">NOT OK</span>';
6557d3 499     $this->_showhint($message, $url);
354978 500   }
11e670 501
A 502
503   /**
504    * Display an error status for optional settings/features
505    *
506    * @param string Test name
507    * @param string Error message
508    * @param string URL for details
509    */
510   function optfail($name, $message = '', $url = '')
511   {
512     echo Q($name) . ':&nbsp; <span class="na">NOT OK</span>';
513     $this->_showhint($message, $url);
514   }
5fed07 515
AM 516
354978 517   /**
T 518    * Display warning status
519    *
520    * @param string Test name
521    * @param string Warning message
522    * @param string URL for details
523    */
6557d3 524   function na($name, $message = '', $url = '')
354978 525   {
6557d3 526     echo Q($name) . ':&nbsp; <span class="na">NOT AVAILABLE</span>';
T 527     $this->_showhint($message, $url);
528   }
5fed07 529
AM 530
6557d3 531   function _showhint($message, $url = '')
T 532   {
533     $hint = Q($message);
5fed07 534
354978 535     if ($url)
6557d3 536       $hint .= ($hint ? '; ' : '') . 'See <a href="' . Q($url) . '" target="_blank">' . Q($url) . '</a>';
5fed07 537
6557d3 538     if ($hint)
T 539       echo '<span class="indent">(' . $hint . ')</span>';
354978 540   }
5fed07 541
AM 542
5f25a1 543   static function _clean_array($arr)
c5042d 544   {
T 545     $out = array();
5fed07 546
5f25a1 547     foreach (array_unique($arr) as $k => $val) {
T 548       if (!empty($val)) {
549         if (is_numeric($k))
550           $out[] = $val;
551         else
552           $out[$k] = $val;
553       }
554     }
5fed07 555
c5042d 556     return $out;
T 557   }
5fed07 558
AM 559
461a30 560   static function _dump_var($var, $name=null)
AM 561   {
0829b7 562     // special values
A 563     switch ($name) {
564     case 'syslog_facility':
565       $list = array(32 => 'LOG_AUTH', 80 => 'LOG_AUTHPRIV', 72 => ' LOG_CRON',
566                     24 => 'LOG_DAEMON', 0 => 'LOG_KERN', 128 => 'LOG_LOCAL0',
567                     136 => 'LOG_LOCAL1', 144 => 'LOG_LOCAL2', 152 => 'LOG_LOCAL3',
568                     160 => 'LOG_LOCAL4', 168 => 'LOG_LOCAL5', 176 => 'LOG_LOCAL6',
569                     184 => 'LOG_LOCAL7', 48 => 'LOG_LPR', 16 => 'LOG_MAIL',
570                     56 => 'LOG_NEWS', 40 => 'LOG_SYSLOG', 8 => 'LOG_USER', 64 => 'LOG_UUCP');
571       if ($val = $list[$var])
572         return $val;
573       break;
574
461a30 575     case 'mail_header_delimiter':
AM 576       $var = str_replace(array("\r", "\n"), array('\r', '\n'), $var);
577       return '"' . $var. '"';
578       break;
579 /*
580     // RCMAIL_VERSION is undefined here
581     case 'useragent':
582       if (preg_match('|^(.*)/('.preg_quote(RCMAIL_VERSION, '|').')$|i', $var, $m)) {
583         return '"' . addcslashes($var, '"') . '/" . RCMAIL_VERSION';
584       }
585       break;
586 */
587     }
0829b7 588
5f25a1 589     if (is_array($var)) {
T 590       if (empty($var)) {
591         return 'array()';
592       }
593       else {  // check if all keys are numeric
594         $isnum = true;
3725cf 595         foreach (array_keys($var) as $key) {
5f25a1 596           if (!is_numeric($key)) {
T 597             $isnum = false;
598             break;
599           }
600         }
5fed07 601
5f25a1 602         if ($isnum)
T 603           return 'array(' . join(', ', array_map(array('rcube_install', '_dump_var'), $var)) . ')';
604       }
605     }
5fed07 606
5f25a1 607     return var_export($var, true);
T 608   }
5fed07 609
AM 610
190e97 611   /**
T 612    * Initialize the database with the according schema
613    *
614    * @param object rcube_db Database connection
615    * @return boolen True on success, False on error
616    */
617   function init_db($DB)
618   {
ff54e9 619     $engine = $DB->db_provider;
5fed07 620
190e97 621     // read schema file from /SQL/*
e6bb83 622     $fname = INSTALL_PATH . "SQL/$engine.initial.sql";
T 623     if ($sql = @file_get_contents($fname)) {
624       $this->exec_sql($sql, $DB);
190e97 625     }
T 626     else {
627       $this->fail('DB Schema', "Cannot read the schema file: $fname");
628       return false;
629     }
5fed07 630
190e97 631     if ($err = $this->get_error()) {
T 632       $this->fail('DB Schema', "Error creating database schema: $err");
633       return false;
634     }
635
636     return true;
637   }
5fed07 638
AM 639
e6bb83 640   /**
4490d0 641    * Update database schema
e6bb83 642    *
T 643    * @param string Version to update from
4490d0 644    *
e6bb83 645    * @return boolen True on success, False on error
T 646    */
4490d0 647   function update_db($version)
e6bb83 648   {
f23ef1 649     system(INSTALL_PATH . "bin/updatedb.sh --package=roundcube"
AM 650       . " --version=" . escapeshellarg($version)
651       . " --dir=" . INSTALL_PATH . "SQL"
652       . " 2>&1", $result);
5fed07 653
4490d0 654     return !$result;
e6bb83 655   }
5fed07 656
AM 657
e6bb83 658   /**
T 659    * Execute the given SQL queries on the database connection
660    *
661    * @param string SQL queries to execute
662    * @param object rcube_db Database connection
663    * @return boolen True on success, False on error
664    */
665   function exec_sql($sql, $DB)
666   {
399db1 667     $sql = $this->fix_table_names($sql, $DB);
e6bb83 668     $buff = '';
T 669     foreach (explode("\n", $sql) as $line) {
670       if (preg_match('/^--/', $line) || trim($line) == '')
671         continue;
5fed07 672
e6bb83 673       $buff .= $line . "\n";
T 674       if (preg_match('/(;|^GO)$/', trim($line))) {
675         $DB->query($buff);
676         $buff = '';
677         if ($DB->is_error())
678           break;
679       }
680     }
5fed07 681
e6bb83 682     return !$DB->is_error();
T 683   }
5fed07 684
AM 685
c5042d 686   /**
399db1 687    * Parse SQL file and fix table names according to db_prefix
AM 688    * Note: This need to be a complete database initial file
689    */
690   private function fix_table_names($sql, $DB)
691   {
692     if (empty($this->config['db_prefix'])) {
693         return $sql;
694     }
695
696     // replace table names
697     if (preg_match_all('/CREATE TABLE (\[dbo\]\.|IF NOT EXISTS )?[`"\[\]]*([^`"\[\] \r\n]+)/i', $sql, $matches)) {
698       foreach ($matches[2] as $table) {
699         $real_table = $this->config['db_prefix'] . $table;
700         $sql = preg_replace("/([^a-zA-Z0-9_])$table([^a-zA-Z0-9_])/", "\\1$real_table\\2", $sql);
701       }
702     }
703     // replace sequence names
704     if ($DB->db_provider == 'postgres' && preg_match_all('/CREATE SEQUENCE (IF NOT EXISTS )?"?([^" \n\r]+)/i', $sql, $matches)) {
705       foreach ($matches[2] as $sequence) {
706         $real_sequence = $this->config['db_prefix'] . $sequence;
707         $sql = preg_replace("/([^a-zA-Z0-9_])$sequence([^a-zA-Z0-9_])/", "\\1$real_sequence\\2", $sql);
708       }
709     }
710
711     return $sql;
712   }
713
714
715   /**
e019f2 716    * Handler for Roundcube errors
c5042d 717    */
T 718   function raise_error($p)
719   {
720       $this->last_error = $p;
721   }
5fed07 722
AM 723
354978 724   /**
T 725    * Generarte a ramdom string to be used as encryption key
726    *
727    * @param int Key length
728    * @return string The generated random string
729    * @static
730    */
731   function random_key($length)
732   {
733     $alpha = 'ABCDEFGHIJKLMNOPQERSTUVXYZabcdefghijklmnopqrtsuvwxyz0123456789+*%&?!$-_=';
734     $out = '';
5fed07 735
354978 736     for ($i=0; $i < $length; $i++)
T 737       $out .= $alpha{rand(0, strlen($alpha)-1)};
5fed07 738
354978 739     return $out;
T 740   }
5fed07 741
c5042d 742 }
T 743