phpBB
Statistics
| Revision:

root / trunk / phpBB / includes / functions_install.php

History | View | Annotate | Download (13.8 kB)

1
<?php
2
/**
3
*
4
* @package install
5
* @copyright (c) 2006 phpBB Group
6
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
7
*
8
*/
9
10
/**
11
* @ignore
12
*/
13
if (!defined('IN_PHPBB'))
14
{
15
        exit;
16
}
17
18
/**
19
* Determine if we are able to load a specified PHP module and do so if possible
20
*/
21
function can_load_dll($dll)
22
{
23
        // SQLite2 is a tricky thing, from 5.0.0 it requires PDO; if PDO is not loaded we must state that SQLite is unavailable
24
        // as the installer doesn't understand that the extension has a prerequisite.
25
        //
26
        // On top of this sometimes the SQLite extension is compiled for a different version of PDO
27
        // by some Linux distributions which causes phpBB to bomb out with a blank page.
28
        //
29
        // Net result we'll disable automatic inclusion of SQLite support
30
        //
31
        // See: r9618 and #56105
32
        if ($dll == 'sqlite')
33
        {
34
                return false;
35
        }
36
        return ((@ini_get('enable_dl') || strtolower(@ini_get('enable_dl')) == 'on') && (!@ini_get('safe_mode') || strtolower(@ini_get('safe_mode')) == 'off') && function_exists('dl') && @dl($dll . '.' . PHP_SHLIB_SUFFIX)) ? true : false;
37
}
38
39
/**
40
* Returns an array of available DBMS with some data, if a DBMS is specified it will only
41
* return data for that DBMS and will load its extension if necessary.
42
*/
43
function get_available_dbms($dbms = false, $return_unavailable = false, $only_20x_options = false)
44
{
45
        global $lang;
46
        $available_dbms = array(
47
                'firebird'        => array(
48
                        'LABEL'                        => 'FireBird',
49
                        'SCHEMA'                => 'firebird',
50
                        'MODULE'                => 'interbase',
51
                        'DELIM'                        => ';;',
52
                        'DRIVER'                => 'firebird',
53
                        'AVAILABLE'                => true,
54
                        '2.0.x'                        => false,
55
                ),
56
                'mysqli'        => array(
57
                        'LABEL'                        => 'MySQL with MySQLi Extension',
58
                        'SCHEMA'                => 'mysql_41',
59
                        'MODULE'                => 'mysqli',
60
                        'DELIM'                        => ';',
61
                        'DRIVER'                => 'mysqli',
62
                        'AVAILABLE'                => true,
63
                        '2.0.x'                        => true,
64
                ),
65
                'mysql'                => array(
66
                        'LABEL'                        => 'MySQL',
67
                        'SCHEMA'                => 'mysql',
68
                        'MODULE'                => 'mysql',
69
                        'DELIM'                        => ';',
70
                        'DRIVER'                => 'mysql',
71
                        'AVAILABLE'                => true,
72
                        '2.0.x'                        => true,
73
                ),
74
                'mssql'                => array(
75
                        'LABEL'                        => 'MS SQL Server 2000+',
76
                        'SCHEMA'                => 'mssql',
77
                        'MODULE'                => 'mssql',
78
                        'DELIM'                        => 'GO',
79
                        'DRIVER'                => 'mssql',
80
                        'AVAILABLE'                => true,
81
                        '2.0.x'                        => true,
82
                ),
83
                'mssql_odbc'=>        array(
84
                        'LABEL'                        => 'MS SQL Server [ ODBC ]',
85
                        'SCHEMA'                => 'mssql',
86
                        'MODULE'                => 'odbc',
87
                        'DELIM'                        => 'GO',
88
                        'DRIVER'                => 'mssql_odbc',
89
                        'AVAILABLE'                => true,
90
                        '2.0.x'                        => true,
91
                ),
92
                'mssqlnative'                => array(
93
                        'LABEL'                        => 'MS SQL Server 2005+ [ Native ]',
94
                        'SCHEMA'                => 'mssql',
95
                        'MODULE'                => 'sqlsrv',
96
                        'DELIM'                        => 'GO',
97
                        'DRIVER'                => 'mssqlnative',
98
                        'AVAILABLE'                => true,
99
                        '2.0.x'                        => false,
100
                ),
101
                'oracle'        =>        array(
102
                        'LABEL'                        => 'Oracle',
103
                        'SCHEMA'                => 'oracle',
104
                        'MODULE'                => 'oci8',
105
                        'DELIM'                        => '/',
106
                        'DRIVER'                => 'oracle',
107
                        'AVAILABLE'                => true,
108
                        '2.0.x'                        => false,
109
                ),
110
                'postgres' => array(
111
                        'LABEL'                        => 'PostgreSQL 7.x/8.x',
112
                        'SCHEMA'                => 'postgres',
113
                        'MODULE'                => 'pgsql',
114
                        'DELIM'                        => ';',
115
                        'DRIVER'                => 'postgres',
116
                        'AVAILABLE'                => true,
117
                        '2.0.x'                        => true,
118
                ),
119
                'sqlite'                => array(
120
                        'LABEL'                        => 'SQLite',
121
                        'SCHEMA'                => 'sqlite',
122
                        'MODULE'                => 'sqlite',
123
                        'DELIM'                        => ';',
124
                        'DRIVER'                => 'sqlite',
125
                        'AVAILABLE'                => true,
126
                        '2.0.x'                        => false,
127
                ),
128
        );
129
130
        if ($dbms)
131
        {
132
                if (isset($available_dbms[$dbms]))
133
                {
134
                        $available_dbms = array($dbms => $available_dbms[$dbms]);
135
                }
136
                else
137
                {
138
                        return array();
139
                }
140
        }
141
142
        // now perform some checks whether they are really available
143
        foreach ($available_dbms as $db_name => $db_ary)
144
        {
145
                if ($only_20x_options && !$db_ary['2.0.x'])
146
                {
147
                        if ($return_unavailable)
148
                        {
149
                                $available_dbms[$db_name]['AVAILABLE'] = false;
150
                        }
151
                        else
152
                        {
153
                                unset($available_dbms[$db_name]);
154
                        }
155
                        continue;
156
                }
157
158
                $dll = $db_ary['MODULE'];
159
160
                if (!@extension_loaded($dll))
161
                {
162
                        if (!can_load_dll($dll))
163
                        {
164
                                if ($return_unavailable)
165
                                {
166
                                        $available_dbms[$db_name]['AVAILABLE'] = false;
167
                                }
168
                                else
169
                                {
170
                                        unset($available_dbms[$db_name]);
171
                                }
172
                                continue;
173
                        }
174
                }
175
                $any_db_support = true;
176
        }
177
178
        if ($return_unavailable)
179
        {
180
                $available_dbms['ANY_DB_SUPPORT'] = $any_db_support;
181
        }
182
        return $available_dbms;
183
}
184
185
/**
186
* Generate the drop down of available database options
187
*/
188
function dbms_select($default = '', $only_20x_options = false)
189
{
190
        global $lang;
191
192
        $available_dbms = get_available_dbms(false, false, $only_20x_options);
193
        $dbms_options = '';
194
        foreach ($available_dbms as $dbms_name => $details)
195
        {
196
                $selected = ($dbms_name == $default) ? ' selected="selected"' : '';
197
                $dbms_options .= '<option value="' . $dbms_name . '"' . $selected .'>' . $lang['DLL_' . strtoupper($dbms_name)] . '</option>';
198
        }
199
        return $dbms_options;
200
}
201
202
/**
203
* Get tables of a database
204
*
205
* @deprecated
206
*/
207
function get_tables(&$db)
208
{
209
        if (!class_exists('phpbb_db_tools'))
210
        {
211
                global $phpbb_root_path, $phpEx;
212
                require($phpbb_root_path . 'includes/db/db_tools.' . $phpEx);
213
        }
214
215
        $db_tools = new phpbb_db_tools($db);
216
217
        return $db_tools->sql_list_tables();
218
}
219
220
/**
221
* Used to test whether we are able to connect to the database the user has specified
222
* and identify any problems (eg there are already tables with the names we want to use
223
* @param        array        $dbms should be of the format of an element of the array returned by {@link get_available_dbms get_available_dbms()}
224
*                                        necessary extensions should be loaded already
225
*/
226
function connect_check_db($error_connect, &$error, $dbms_details, $table_prefix, $dbhost, $dbuser, $dbpasswd, $dbname, $dbport, $prefix_may_exist = false, $load_dbal = true, $unicode_check = true)
227
{
228
        global $phpbb_root_path, $phpEx, $config, $lang;
229
230
        $dbms = $dbms_details['DRIVER'];
231
232
        if ($load_dbal)
233
        {
234
                // Include the DB layer
235
                include($phpbb_root_path . 'includes/db/' . $dbms . '.' . $phpEx);
236
        }
237
238
        // Instantiate it and set return on error true
239
        $sql_db = 'dbal_' . $dbms;
240
        $db = new $sql_db();
241
        $db->sql_return_on_error(true);
242
243
        // Check that we actually have a database name before going any further.....
244
        if ($dbms_details['DRIVER'] != 'sqlite' && $dbms_details['DRIVER'] != 'oracle' && $dbname === '')
245
        {
246
                $error[] = $lang['INST_ERR_DB_NO_NAME'];
247
                return false;
248
        }
249
250
        // Make sure we don't have a daft user who thinks having the SQLite database in the forum directory is a good idea
251
        if ($dbms_details['DRIVER'] == 'sqlite' && stripos(phpbb_realpath($dbhost), phpbb_realpath('../')) === 0)
252
        {
253
                $error[] = $lang['INST_ERR_DB_FORUM_PATH'];
254
                return false;
255
        }
256
257
        // Check the prefix length to ensure that index names are not too long and does not contain invalid characters
258
        switch ($dbms_details['DRIVER'])
259
        {
260
                case 'mysql':
261
                case 'mysqli':
262
                        if (strspn($table_prefix, '-./\\') !== 0)
263
                        {
264
                                $error[] = $lang['INST_ERR_PREFIX_INVALID'];
265
                                return false;
266
                        }
267
268
                // no break;
269
270
                case 'postgres':
271
                        $prefix_length = 36;
272
                break;
273
274
                case 'mssql':
275
                case 'mssql_odbc':
276
                case 'mssqlnative':
277
                        $prefix_length = 90;
278
                break;
279
280
                case 'sqlite':
281
                        $prefix_length = 200;
282
                break;
283
284
                case 'firebird':
285
                case 'oracle':
286
                        $prefix_length = 6;
287
                break;
288
        }
289
290
        if (strlen($table_prefix) > $prefix_length)
291
        {
292
                $error[] = sprintf($lang['INST_ERR_PREFIX_TOO_LONG'], $prefix_length);
293
                return false;
294
        }
295
296
        // Try and connect ...
297
        if (is_array($db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, true)))
298
        {
299
                $db_error = $db->sql_error();
300
                $error[] = $lang['INST_ERR_DB_CONNECT'] . '<br />' . (($db_error['message']) ? $db_error['message'] : $lang['INST_ERR_DB_NO_ERROR']);
301
        }
302
        else
303
        {
304
                // Likely matches for an existing phpBB installation
305
                if (!$prefix_may_exist)
306
                {
307
                        $temp_prefix = strtolower($table_prefix);
308
                        $table_ary = array($temp_prefix . 'attachments', $temp_prefix . 'config', $temp_prefix . 'sessions', $temp_prefix . 'topics', $temp_prefix . 'users');
309
310
                        $tables = get_tables($db);
311
                        $tables = array_map('strtolower', $tables);
312
                        $table_intersect = array_intersect($tables, $table_ary);
313
314
                        if (sizeof($table_intersect))
315
                        {
316
                                $error[] = $lang['INST_ERR_PREFIX'];
317
                        }
318
                }
319
320
                // Make sure that the user has selected a sensible DBAL for the DBMS actually installed
321
                switch ($dbms_details['DRIVER'])
322
                {
323
                        case 'mysqli':
324
                                if (version_compare(mysqli_get_server_info($db->db_connect_id), '4.1.3', '<'))
325
                                {
326
                                        $error[] = $lang['INST_ERR_DB_NO_MYSQLI'];
327
                                }
328
                        break;
329
330
                        case 'sqlite':
331
                                if (version_compare(sqlite_libversion(), '2.8.2', '<'))
332
                                {
333
                                        $error[] = $lang['INST_ERR_DB_NO_SQLITE'];
334
                                }
335
                        break;
336
337
                        case 'firebird':
338
                                // check the version of FB, use some hackery if we can't get access to the server info
339
                                if ($db->service_handle !== false && function_exists('ibase_server_info'))
340
                                {
341
                                        $val = @ibase_server_info($db->service_handle, IBASE_SVC_SERVER_VERSION);
342
                                        preg_match('#V([\d.]+)#', $val, $match);
343
                                        if ($match[1] < 2)
344
                                        {
345
                                                $error[] = $lang['INST_ERR_DB_NO_FIREBIRD'];
346
                                        }
347
                                        $db_info = @ibase_db_info($db->service_handle, $dbname, IBASE_STS_HDR_PAGES);
348
349
                                        preg_match('/^\\s*Page size\\s*(\\d+)/m', $db_info, $regs);
350
                                        $page_size = intval($regs[1]);
351
                                        if ($page_size < 8192)
352
                                        {
353
                                                $error[] = $lang['INST_ERR_DB_NO_FIREBIRD_PS'];
354
                                        }
355
                                }
356
                                else
357
                                {
358
                                        $sql = "SELECT *
359
                                                FROM RDB$FUNCTIONS
360
                                                WHERE RDB$SYSTEM_FLAG IS NULL
361
                                                        AND RDB$FUNCTION_NAME = 'CHAR_LENGTH'";
362
                                        $result = $db->sql_query($sql);
363
                                        $row = $db->sql_fetchrow($result);
364
                                        $db->sql_freeresult($result);
365
366
                                        // if its a UDF, its too old
367
                                        if ($row)
368
                                        {
369
                                                $error[] = $lang['INST_ERR_DB_NO_FIREBIRD'];
370
                                        }
371
                                        else
372
                                        {
373
                                                $sql = 'SELECT 1 FROM RDB$DATABASE
374
                                                        WHERE BIN_AND(10, 1) = 0';
375
                                                $result = $db->sql_query($sql);
376
                                                if (!$result) // This can only fail if BIN_AND is not defined
377
                                                {
378
                                                        $error[] = $lang['INST_ERR_DB_NO_FIREBIRD'];
379
                                                }
380
                                                $db->sql_freeresult($result);
381
                                        }
382
383
                                        // Setup the stuff for our random table
384
                                        $char_array = array_merge(range('A', 'Z'), range('0', '9'));
385
                                        $char_len = mt_rand(7, 9);
386
                                        $char_array_len = sizeof($char_array) - 1;
387
388
                                        $final = '';
389
390
                                        for ($i = 0; $i < $char_len; $i++)
391
                                        {
392
                                                $final .= $char_array[mt_rand(0, $char_array_len)];
393
                                        }
394
395
                                        // Create some random table
396
                                        $sql = 'CREATE TABLE ' . $final . " (
397
                                                FIELD1 VARCHAR(255) CHARACTER SET UTF8 DEFAULT '' NOT NULL COLLATE UNICODE,
398
                                                FIELD2 INTEGER DEFAULT 0 NOT NULL);";
399
                                        $db->sql_query($sql);
400
401
                                        // Create an index that should fail if the page size is less than 8192
402
                                        $sql = 'CREATE INDEX ' . $final . ' ON ' . $final . '(FIELD1, FIELD2);';
403
                                        $db->sql_query($sql);
404
405
                                        if (ibase_errmsg() !== false)
406
                                        {
407
                                                $error[] = $lang['INST_ERR_DB_NO_FIREBIRD_PS'];
408
                                        }
409
                                        else
410
                                        {
411
                                                // Kill the old table
412
                                                $db->sql_query('DROP TABLE ' . $final . ';');
413
                                        }
414
                                        unset($final);
415
                                }
416
                        break;
417
418
                        case 'oracle':
419
                                if ($unicode_check)
420
                                {
421
                                        $sql = "SELECT *
422
                                                FROM NLS_DATABASE_PARAMETERS
423
                                                WHERE PARAMETER = 'NLS_RDBMS_VERSION'
424
                                                        OR PARAMETER = 'NLS_CHARACTERSET'";
425
                                        $result = $db->sql_query($sql);
426
427
                                        while ($row = $db->sql_fetchrow($result))
428
                                        {
429
                                                $stats[$row['parameter']] = $row['value'];
430
                                        }
431
                                        $db->sql_freeresult($result);
432
433
                                        if (version_compare($stats['NLS_RDBMS_VERSION'], '9.2', '<') && $stats['NLS_CHARACTERSET'] !== 'UTF8')
434
                                        {
435
                                                $error[] = $lang['INST_ERR_DB_NO_ORACLE'];
436
                                        }
437
                                }
438
                        break;
439
440
                        case 'postgres':
441
                                if ($unicode_check)
442
                                {
443
                                        $sql = "SHOW server_encoding;";
444
                                        $result = $db->sql_query($sql);
445
                                        $row = $db->sql_fetchrow($result);
446
                                        $db->sql_freeresult($result);
447
448
                                        if ($row['server_encoding'] !== 'UNICODE' && $row['server_encoding'] !== 'UTF8')
449
                                        {
450
                                                $error[] = $lang['INST_ERR_DB_NO_POSTGRES'];
451
                                        }
452
                                }
453
                        break;
454
                }
455
456
        }
457
458
        if ($error_connect && (!isset($error) || !sizeof($error)))
459
        {
460
                return true;
461
        }
462
        return false;
463
}
464
465
/**
466
* Removes comments from schema files
467
*/
468
function remove_comments($sql)
469
{
470
        // Remove /* */ comments (http://ostermiller.org/findcomment.html)
471
        $sql = preg_replace('#/\*(.|[\r\n])*?\*/#', "\n", $sql);
472
473
        // Remove # style comments
474
        $sql = preg_replace('/\n{2,}/', "\n", preg_replace('/^#.*$/m', "\n", $sql));
475
476
        return $sql;
477
}
478
479
/**
480
* split_sql_file will split an uploaded sql file into single sql statements.
481
* Note: expects trim() to have already been run on $sql.
482
*/
483
function split_sql_file($sql, $delimiter)
484
{
485
        $sql = str_replace("\r" , '', $sql);
486
        $data = preg_split('/' . preg_quote($delimiter, '/') . '$/m', $sql);
487
488
        $data = array_map('trim', $data);
489
490
        // The empty case
491
        $end_data = end($data);
492
493
        if (empty($end_data))
494
        {
495
                unset($data[key($data)]);
496
        }
497
498
        return $data;
499
}
500
501
/**
502
* For replacing {L_*} strings with preg_replace_callback
503
*/
504
function adjust_language_keys_callback($matches)
505
{
506
        if (!empty($matches[1]))
507
        {
508
                global $lang, $db;
509
510
                return (!empty($lang[$matches[1]])) ? $db->sql_escape($lang[$matches[1]]) : $db->sql_escape($matches[1]);
511
        }
512
}
513
514
function phpbb_create_config_file_data($data, $dbms, $load_extensions, $debug = false)
515
{
516
        $load_extensions = implode(',', $load_extensions);
517
518
        $config_data = "<?php\n";
519
        $config_data .= "// phpBB 3.0.x auto-generated configuration file\n// Do not change anything in this file!\n";
520
521
        $config_data_array = array(
522
                'dbms'                        => $dbms,
523
                'dbhost'                => $data['dbhost'],
524
                'dbport'                => $data['dbport'],
525
                'dbname'                => $data['dbname'],
526
                'dbuser'                => $data['dbuser'],
527
                'dbpasswd'                => htmlspecialchars_decode($data['dbpasswd']),
528
                'table_prefix'        => $data['table_prefix'],
529
                'acm_type'                => 'file',
530
                'load_extensions'        => $load_extensions,
531
        );
532
533
        foreach ($config_data_array as $key => $value)
534
        {
535
                $config_data .= "\${$key} = '" . str_replace("'", "\\'", str_replace('\\', '\\\\', $value)) . "';\n";
536
        }
537
538
        $config_data .= "\n@define('PHPBB_INSTALLED', true);\n";
539
540
        if ($debug)
541
        {
542
                $config_data .= "@define('DEBUG', true);\n";
543
                $config_data .= "@define('DEBUG_EXTRA', true);\n";
544
        }
545
        else
546
        {
547
                $config_data .= "// @define('DEBUG', true);\n";
548
                $config_data .= "// @define('DEBUG_EXTRA', true);\n";
549
        }
550
551
        $config_data .= '?' . '>'; // Done this to prevent highlighting editors getting confused!
552
553
        return $config_data;
554
}