· 10 years ago · Mar 21, 2016, 06:29 AM
1<?php
2/*
3 * @file /drupal/sites/default/build_db.php (location not important)
4 * for Drupal 4.6 / 4.7
5 * Author: Don Lekei
6 * Version: 4.0 April 24, 2005
7 * Creates all tables for the current domain.
8 * inspired by code by Daniel Convissor
9 *
10 * If Drupal is not installed, it will make your users for you
11 *
12 * Builds all of the main database tables and scans all modules for
13 * database files and adds them if they haven't already
14 *
15 * Any modules which have already been added will be ignored
16 * Note: This feature may need to be modified if you use an array
17 * of db_prefix and only prefix some tables
18 *
19 * The database connection information (username, password, etc) and
20 * table name prefixes are obtained from the appropriate
21 * $_SERVER['DOCUMENT_ROOT']/sites/???/settings.php files.
22 *
23 * To execute this script via a web browser:
24 * http://<domain>/database/build_db.php[?pw=password[&dba=dbauser]]
25 *
26 * If you call this function programatically via http then you should
27 * use POST
28 *
29 * If you call the script from a url with no parameters, you will be
30 * prompted for DBU password and optional user.
31 *
32 * For security, you must specify the password for the drupal db user
33 * as the pw parameter. It must match the value in the settings.php file.
34 *
35 * If you specify a dba parameter, this will be taken as the db user to use
36 * and the program will use that user and password to access the database
37 * (this allows you to specify the dba user, allowing the program to create
38 * the appropriate database and user if needed).
39 *
40 * IT IS ADVISED TO ONLY USE THIS DBA OVERRIDE FUNCTION
41 * FROM LOCALHOST OR USING AN HTTPS ALIAS TO YOUR SERVER
42 * OTHERWISE THE DBA USER AND PASSWORD WILL BE TRANSMITTED
43 * IN THE CLEAR
44 *
45 * This script will ONLY initiate the table creation on load if it is
46 * called directly. This gives you the option to include
47 * the file and use its functions elsewhere (provided the name of
48 * your script is _NOT_ named the same as this file).
49 *
50 * To perfrom the table creation under your own program control, use the
51 * build_dbs() function.
52 */
53
54// $DEBUG_CREATE forces displaying SQL instead of executing
55// UNCOMMENT THIS LINE FOR TESTING
56
57// $DEBUG_CREATE=true;
58
59if (basename($_SERVER['PHP_SELF']) == basename(__FILE__)) { // we are being called directly
60?>
61<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
62<html>
63<head>
64<title><?= $_SERVER['HTTP_HOST'] ?> Database Setup</title>
65<style type="text/css"> body {
66 font: message-box;
67 }
68 h1 {
69 font-size: 200%;
70 text-decoration: underline;
71 }
72 h2 {
73 font-size: 150%;
74 }
75 h3 {
76 font-size: 125%;
77 }
78 h4, h5 {
79 font-size: 100%;
80 }
81 a {
82 text-decoration: none;
83 color: WindowText;
84 }
85 a.normal {
86 text-decoration: underline;
87 color: blue;
88 }
89 a:hover {
90 text-decoration: underline;
91 color: Red;
92 }
93 .boxouter {
94 background-color: ActiveCaption;
95 border: thin outset ActiveBorder;
96 font: message-box;
97 }
98 .boxinner {
99 background-color: Window;
100 border: thin inset ActiveBorder;
101 font: message-box;
102 padding: 5px 5px 5px 5px;
103 }
104 .caption {
105 background-color: ActiveCaption;
106 font: caption;
107 text-align: left;
108 color: CaptionText;
109 }
110</style>
111
112</head><body>
113<?php
114// set default critical site settings
115
116$site_name = make_site_title();
117$site_mail = "system@".preg_replace('/^(www|dev)\.(.*)/i','$2',trim(strtolower($_SERVER['HTTP_HOST']),'/'));
118$date_default_timezone = "-28800";
119$use_clean_urls = 1;
120
121 if (isset($_POST) && isset($_POST['pw']) && $_POST['pw']) {
122 $DEBUG_CREATE=$_POST['DEBUG_CREATE'];
123 $NODUP_CREATE=$_POST['NODUP_CREATE'];
124 $DO_OPTIONS=$_POST['DO_OPTIONS'];
125 $CRON=$_POST['CRON'];
126 if (isset($_POST['use_clean_urls'])) $use_clean_urls = $_POST['use_clean_urls'];
127 if (isset($_POST['site_name'])) $site_name = $_POST['site_name'];
128 if (isset($_POST['site_mail'])) $site_mail = $_POST['site_mail'];
129 if (isset($_POST['timezone'])) $date_default_timezone = ''.($_POST['timezone']*3600); //time zone in seconds
130
131 visual_build_dbs($_POST['pw'],$_POST['dba'],$_POST['create']);
132
133 } elseif (isset($_GET) && isset($_GET['pw']) && $_GET['pw']) {
134 $DEBUG_CREATE=$_GET['DEBUG_CREATE'];
135 $NODUP_CREATE=$_GET['NODUP_CREATE'];
136 $DO_OPTIONS=$_GET['DO_OPTIONS'];
137 $CRON=$_GET['CRON'];
138 if (isset($_GET['use_clean_urls'])) $use_clean_urls = $_GET['use_clean_urls'];
139 if (isset($_GET['site_name'])) $site_name = $_GET['site_name'];
140 if (isset($_GET['site_mail'])) $site_mail = $_GET['site_mail'];
141 if (isset($_GET['timezone'])) $date_default_timezone = ''.($_GET['timezone']*3600); //time zone in seconds
142
143 visual_build_dbs($_GET['pw'],$_GET['dba'],$_GET['create']);
144
145 } else {
146 ?>
147<table cellspacing=0 align=center class=boxouter>
148<form action='' method=post>
149<tr><td class=caption>Drupal Database Build / Repair | <?=$_SERVER['HTTP_HOST'] ?></td></tr><tr><td><table class=boxinner>
150<tr><td colspan=2 align=center>This wizard will install a new Drupal installation for <?= $_SERVER['HTTP_HOST']?>.<br>
151Point the mouse to any option below for help tips. <?php
152
153 if (!(isset($_SERVER['HTTP_USER_AGENT']) && preg_match('/msie\s(5\.[5-9]|[6]\.[0-9]*).*(win)/i',$_SERVER['HTTP_USER_AGENT'])
154)) {?><br>Firefox has a bug preventing it from displaying the full tooltip. Click <a style="text-decoration:underline" href='http://home.etu.unige.ch/~robin0/LongTitles_en.html'>here</a> for a patch.<?php } ?></td>
155</tr>
156<tr>
157 <td align=right><a href="#" title="The Password for the Drupal database user or for the (optional) database user below."<?php if(isset($_POST) && isset($_POST['pw']))
158
159 echo'style="color:red; font-weight:bolder;"'; ?>>DBU Password:</a></td>
160 <td align=left><input type=password name="pw" id="pw" size=20 ></td>
161</tr>
162<tr>
163 <td align=right><a href="#" title="Optional database user with create table rights.">DBA User (Optional):</a></td>
164 <td align=left><input type=text name="dba" id="dba" size=20></td>
165</tr>
166<tr>
167 <td align=right><a href="#" title="If this is checked then installs will be prvented from resetting already installed modules to defaults">Prevent Overwrites:</a></td>
168 <td align=left><input type=checkbox name="NODUP_CREATE" value="1" checked>YES</td>
169</tr>
170<tr>
171 <td align=right><a href="#" title="If set to Show SQL Only then all database queries will be printed and not executed. MUST BE SET TO RUN SQL TO ACTUALLY PERFORM THE INSTALLATION!">Test mode:</a></td>
172 <td align=left><input type=radio ID="D0" name="DEBUG_CREATE" value="0" >RUN SQL <input type=radio ID="D1" name="DEBUG_CREATE" value="1" checked>Show SQL Only</td>
173</tr>
174<tr>
175 <td align=right><a href="#" title="This will attempt to create the Drupal database if it does not exist. You must set a Database user with sufficient privilages to CREATE DATABASE and GRANT (eg. root or DBA).">Create Database:</a></td>
176 <td align=left><input type=radio name="create" value="0" checked>No <input type=radio name="create" value="1">Yes (requres DBA or root login above)</td>
177</tr>
178<tr><td colspan=2 align=center><hr/></td></tr>
179<tr>
180 <td align=right><a href="#" title="Sets Drupal to use clean urls by default. You can fix this by starting the sytem in safe mode and resetting the option in administration settings.">Use Clean URLs:</a></td>
181 <td align=left><input type=radio name="use_clean_urls" value="0">No <input type=radio name="use_clean_urls" value="1" checked>Yes</td>
182</tr>
183<tr>
184 <td align=right><a href="#" title="Sets the title of the site to one based on the domain instead of the default -- Drupal">Site Title:</a></td>
185 <td align=left><input type=text name="site_name" value="<?= $site_name ?>" ></td>
186</tr>
187<tr>
188 <td align=right><a href="#" title="Sets the return address for server generated emails. This may need to be an address or alias at the current domain to allow some servers to send mail.">Site Email:</a></td>
189 <td align=left><input type=text name="site_mail" value="<?= $site_mail ?>" ></td>
190</tr>
191<tr>
192 <td align=right><a href="#" title="The default timezone as an offset from GMT. Defaults to the timezone you are at now.">Timezone from GMT:</a></td>
193 <td align=left><script language="JavaScript">
194 var curDateTime = new Date();
195 document.write ('<input type=text size=5 name="timezone" value="'+(-(curDateTime.getTimezoneOffset()/60))+'" >')
196 </script> Hours</td>
197</tr>
198<tr>
199 <td align=right><a href="#" title="If set it will process these settings and any entries in options.mysql">Process Options:</a></td>
200 <td align=left><input type=radio id="OP0" name="DO_OPTIONS" value="0"><a href="#" title="This option will leave the Drupal/module installation defaults">Leave Defaults</a><br/><input type=radio id="OP1" name="DO_OPTIONS" value="1" checked><a href="#" title="Override the Drupal defaults with the above only (will not process options.mysql).">Set the above only</a><br/><input type=radio id="OP2" name="DO_OPTIONS" value="2" ><a href="#" title="Set the above options plus read in options.php to override the Drupal and module defaults">Use Options File</a></td>
201</tr>
202<tr>
203 <td align=right><a href="#" title="Adds this site to the list of sites to process in the cron loop.">Add to cron chain:</a></td>
204 <td align=left><input type=checkbox name="CRON" value="1" checked>YES</td>
205</tr>
206<tr><td colspan=2 align=center><input type=button value="Set Debug Defaults" onclick="OP2.checked=1;D1.checked=1;NODUP_CREATE.checked=0;"><input type=button value="Set Install Defaults" onclick="OP2.checked=1;D0.checked=1;NODUP_CREATE.checked=0;"><input type=button value="Set Update Defaults" onclick="OP0.checked=1;D0.checked=1;NODUP_CREATE.checked=1;"></td></tr>
207<tr><td colspan=2 align=center><input type=submit value="GO"></td></tr>
208</table></td></tr></form></table>
209</body></html>
210 <?PHP
211 }
212 ?>
213
214<?php
215}
216/*
217 * call build_dbs() with visual wrapper
218 * make it really pretty for user
219 */
220function visual_build_dbs($password='',$user='',$create=0) {
221 global $DEBUG_CREATE;
222 global $NODUP_CREATE;
223 global $DO_OPTIONS;
224 global $CRON;
225
226?>
227 <div style="text-align:center;">
228 <div class=boxouter style="width: 490px; margin-left:auto; margin-right:auto; "><div class=caption>Drupal Database Build / Repair (<?=($DEBUG_CREATE)?"SIMULATING ONLY":"processing" ?>)</div>
229 <div class=boxinner >
230 <div style="margin-bottom: 5px;">Please wait while while <?= $_SERVER['HTTP_HOST']?> is created...<br>It may take a minute or more to process all of the files.</div>
231<div><?PHP
232 if($DEBUG_CREATE) echo '<p style="color:red;">You have selected the Debug Mode (Show SQL Only) so the site will <b>not actually be created</b>.</p>';
233 if($DO_OPTIONS==0) echo '<p style="color:darkred;">You have elected <b>NOT</b> to process the options sql file.</p>';
234 ?></div>
235
236 <div style="text-align:left; margin-left:15px; width: 460px; height: 250px; overflow: scroll; border: thin inset;">
237
238 <?PHP $n=build_dbs($password,$user,$create); ?>
239 </div>
240 <h2 style="color: darkgreen;"><?= $n?> database files successfully <?=($DEBUG_CREATE)?"simulated":"processed" ?>.</h2>
241 <div><form method=get action="http://<?= trim($_SERVER['HTTP_HOST'],"/")?>"><input type=hidden name=q value="user/register"><input type=submit value="Add your ADMIN USER" ></form></div>
242<?PHP
243 if($DEBUG_CREATE) echo '<div><p>You have selected the Debug Mode so the site was <b>not actually created</b>. <a class=normal href="http://'. trim($_SERVER['HTTP_HOST'],'/').'/'.trim($_SERVER['PHP_SELF'],'/').'">Click here to run the wizard again.</a></p></div>';
244 ?>
245
246<div>If you have already created your admin user, you can <a class=normal href="http://<?= $_SERVER['HTTP_HOST'] ?>">click here to visit <?= $_SERVER['HTTP_HOST'] ?></a>.</div>
247
248 </div></div></body></html>
249 <?PHP
250}
251
252/**
253 * Creates all tables for this site *
254 *
255 * Calls the various functions needed to gather and implement the tables:
256 * + Gets the $db_url and $db_prefix from settings.php file.
257 * + Gets the SQL script for the DBMS specified.
258 * + Assembles the queries for each site, prefixing table names as needed.
259 * + Bunches all of the sites' queries per db_url and removes duplicates.
260 * + Connects to each db_url and executes the queries for it.
261 *
262 * WARNING: If the variable_get() function has not been defined yet,
263 * this function will define a fake version of it. This is necessary
264 * to avoid having to include bootstrap.inc
265 *
266 * @param $password
267 * If you supply a password it must match the database user password
268 * the password is used as a security measure if called from the web
269 * internal calls can call with no password
270 *
271 * @param $user
272 * If you supply a user, then the user name and password provided
273 * will override the ones in the settings file. This allows you
274 * to specify dba credentials to allow creation of a new database
275 *
276 * @return void
277 */
278function build_dbs($password='',$user='',$create=0) {
279 global $DO_OPTIONS; //flag to process the options file
280 global $CRON; //flag to add to the cron chain
281
282 define_api();
283 echo "<h2>Creating Database for ".$_SERVER['HTTP_HOST'].'...</h2>';
284 @ob_end_flush(); // let user see what's going on in real time
285
286 $settings = get_site_settings();
287
288 if (empty($settings)) {
289 trigger_error('Found no valid settings.php for site '.$_SERVER['HTTP_HOST'].'.',
290 E_USER_ERROR);
291 }
292
293 $db_url = $settings['url'];
294 $url = parse_url($db_url);
295 $dbms = $url['scheme'];
296
297 if($password) {
298 if($user) {
299 // rebuild url with supplied user and password
300 $db_url = $url['scheme']."://$user:$password@".$url['host'].$url['path'];
301 } elseif( $password != $url['pass'] ) die('oops.');
302 }
303
304 // Load the database API for the current database type
305 require_once str_replace ( '//', '/', $_SERVER['DOCUMENT_ROOT'].'/includes/database.').$dbms.'.inc';
306
307 /*
308 * Need to catch errors with error handler due to die() in db_connect().
309 *
310 * The return value must be stored in a varialbe named $active_db
311 * because that's the connection variable used in _db_query().
312 */
313 set_error_handler('no_error');
314
315 global $active_db;
316 //connect and try to create database if possible
317 $active_db = my_db_connect($db_url,$create, $url['user'], $url['pass']);
318 $success = 0;
319 restore_error_handler();
320 echo ("<h3>Database $dbms: ".trim($url['path'],'/').'</h2>');
321 if($dbms=='mysql') {
322 $mysql_version = mysql_get_server_info($active_db);
323 echo('<h3>Database info: '.$mysql_version.'</h3>');
324 }
325
326 echo "<h3>Processing database.$dbms</h3>";
327 @flush(); // let user see what's going on in real time
328
329 $queries = get_queries_from_file(str_replace ( '//', '/', $_SERVER['DOCUMENT_ROOT'].'/database/database.').$dbms);
330// fix for Drupal 4.7 with
331 if (($queries === false) && ($dbms == 'mysql')){
332 $dbext=((strcmp($mysql_version,'4.1')<0)?'4.0.mysql':'4.1.mysql');
333 $queries = get_queries_from_file(str_replace ( '//', '/', $_SERVER['DOCUMENT_ROOT'].'/database/database.').$dbext);
334 }
335 if ($queries === false) {
336 trigger_error("Not able to find main settings for $dbms from /database.$dbms file.",
337 E_USER_WARNING);
338 return(0);
339 }
340 if( execute_arrays_queries(get_queries_for_settings($settings, $queries))) $success++;
341
342 $modules=find_modules($dbms);
343
344 if($modules) foreach ( $modules as $k=>$module ) {
345 echo '<h3>Processing '.str_replace ( $_SERVER['DOCUMENT_ROOT'], '', $module)." ($k)</h3>";
346 @flush(); // let user see what's going on in real time
347
348 $queries = get_queries_from_file($module);
349 @flush(); // let user see what's going on in real time
350
351 if( execute_arrays_queries(get_queries_for_settings($settings, $queries))) $success++;
352
353 }
354
355 // process option settings / database defaults overrides
356 if ($DO_OPTIONS) $success += process_options( $settings, $dbms );
357 if ($CRON) add_to_urls(); // add to url list
358 return $success;
359}
360
361/**
362 * Obtains configuration settings specified in settings.php file.
363 *
364 * NOTE: Will not return data from a settings file that has
365 * its $db_url set to the default value shipped by Drupal.
366 *
367 * An example of an array returned by this function:
368 *
369 *
370 * @return
371 * an array of:
372 * 'url' : the $db_url.
373 * 'named' : an array with table names for keys and table name prefixes
374 * for values.
375 * 'default' : a string that should prefix all other tables.
376 * Returns FALSE if the sites directory can not be found.
377 */
378function get_site_settings() {
379 $default_url = 'mysql://username:password@localhost/database';
380 $settings = array();
381 $site = $_SERVER['HTTP_HOST'];
382
383 // Get the $db_url and $db_prefix variables.
384 include conf_init() . '/settings.php';
385 // Detect the use of the Drupal settings.php file
386 if ( (!is_string($db_url)) || $db_url == $default_url) {
387 echo "<h3>The settings.php file has not been configured for $site.</h3>";
388 return false;
389 }
390 $settings['url'] = $db_url;
391 if (is_string($db_prefix)) {
392 $settings['default'] = $db_prefix;
393 $settings['named'] = array();
394 }
395 else {
396 $settings['default'] = '';
397 $settings['named'] = $db_prefix;
398 }
399
400 return $settings;
401}
402
403/**
404 * Grabs the contents of the query script and puts each query into
405 * an array element.
406 *
407 * @param $dbms
408 * The name of the DBMS you are want the queries for ('mysql', 'pgsql').
409 *
410 * @return
411 * An array with each query in a separate element. Returns FALSE if
412 * the database query script does not exist.
413 */
414function get_queries_from_file($file) {
415
416set_time_limit(60); // this could take a while
417
418
419 if (!file_exists($file)) {
420 return false;
421 }
422 $func = '';
423 $contents = '';
424 $comments = array('/^--.*/','/#.*$/');
425 $fh = fopen($file, 'r');
426 while (!feof($fh)) {
427 // get line, strip out superflous backticks and extra whitespace
428 $line = str_replace('`','',fgets($fh, 5000));
429 $line = preg_replace($comments,'',$line);
430 $line = trim(preg_replace('/\s+/',' ',$line))."\n";
431
432 if (preg_match("/^ *[(a-z)']/i", $line)) {
433 /*
434 * Mush functions into one line because they can contain ';' at the
435 * ends of lines and at the end of the query, which trips up the split
436 * ';[\r\n]+' that is used to put queries into separate array elements.
437 */
438 if (preg_match('/^\s*CREATE FUNCTION/i', $line)) {
439 // Beginning of CREATE FUNCTION statement.
440 $func = trim($line);
441 } elseif ($func) {
442 // CREATE FUNCTION statement is still in the works.
443 $line = ' ' . trim($line);
444 if (preg_match("/ ' LANGUAGE '\w+';/i", $line)) {
445 // End of CREATE FUNCTION statement.
446 $contents .= $func . $line . "\n";
447 $func = '';
448 }
449 else {
450 // Middle of CREATE FUNCTION statement.
451 $func .= $line;
452 }
453 } else {
454 // Regular query content.
455 $contents .= $line;
456 }
457 }
458 }
459 $queries = preg_split('/;[\r\n]+/', $contents);
460 $last_key = count($queries) - 1;
461 if (trim($queries[$last_key]) == '') {
462 unset($queries[$last_key]);
463 }
464
465 return $queries;
466}
467
468/**
469 * Assembles all of the queries for a db_url.
470 *
471 * The process includes getting the table names prefixed (via
472 * prefix_queries_in_array()) and then eliminating duplicate queries.
473 *
474 * @param $prefixes
475 * The associative array of sites containing the
476 * table name prefixes.
477 * @param $queries
478 * The enumerated array containing one query per element.
479 *
480 * @return
481 * The array of queries for the db_url.
482 */
483function get_queries_for_settings($prefixes, $queries) {
484 $out = array();
485 $out = prefix_queries_in_array($queries, $prefixes['default'], $prefixes['named']);
486
487 return array_unique($out);
488}
489
490/**
491 * Goes through each element of the queries array, prefixing the table
492 * names as needed.
493 *
494 * @param $queries
495 * The enumerated array containing one query per element.
496 * @param $default
497 * The string for prefixing all other tables.
498 * @param $named
499 * The associative array of specific tables to prefix.
500 * Each key is a table name and the value is the prefix for that table.
501 *
502 * @return
503 * The array of queries with the table names prefixed as needed.
504 */
505function prefix_queries_in_array($queries, $default, $named) {
506global $NODUP_CREATE; // flag that drop & if not exist should be trimmed.
507set_time_limit(30); // this could take a while
508
509 $commands = 'CREATE TABLE(?: IF NOT EXISTS|)|'
510 . 'DROP TABLE(?: IF EXISTS|)|'
511 . 'CREATE SEQUENCE(?: IF NOT EXISTS|)|'
512 . 'DROP SEQUENCE(?: IF EXISTS|)|'
513 . 'DROP INDEX(?: IF EXISTS|)|'
514 . 'ALTER TABLE(?: IF EXISTS|)|'
515 . 'ALTER SEQUENCE(?: IF EXISTS|)|'
516 . 'INSERT(?: IGNORE|)(?: INTO|)|UPDATE|REPLACE(?: INTO|)|DELETE FROM';
517
518 $out = array();
519
520 if($named) foreach ($named as $table => $prefix) {
521 if($queries) foreach ($queries as $key => $query) {
522 $query = ltrim($query);
523 if (preg_match("/^($commands) +($table)([\s(]+.*|)$/is",
524 $query,
525 $match))
526 {
527 if ($NODUP_CREATE) { //prevent error checking
528 $match[1]=preg_replace('/ IF NOT EXISTS/i','',$match[1]);
529 if (!preg_match('/^DROP /i',$match[1]))
530 $out[$key] = $match[1] . ' ' . $prefix . $match[2] . $match[3];
531 } else {
532 $out[$key] = $match[1] . ' ' . $prefix . $match[2] . $match[3];
533 }
534 unset($queries[$key]);
535
536 }
537 elseif (preg_match("/^CREATE +INDEX +([a-z0-9_]+) +ON +($table)([\s(]+.*|)$/is",
538 $query,
539 $match))
540 {
541 $out[$key] = 'CREATE INDEX ' . $prefix . $match[1]
542 . ' ON ' . $prefix . $match[2] . $match[3];
543 unset($queries[$key]);
544 }
545 }
546 }
547 if (trim($default) == '') {
548 return array_merge($out, $queries);
549 }
550 if($queries) foreach ($queries as $key => $query) {
551 $query = ltrim($query);
552 if (preg_match("/^($commands) +([a-z0-9_]+)([\s(]+.*|)$/is",
553 $query,
554 $match))
555 {
556 if ($NODUP_CREATE) { //prevent error checking
557 $match[1]=preg_replace('/ IF NOT EXISTS/i','',$match[1]);
558 if (!preg_match('/^DROP /i',$match[1]))
559 $out[$key] = $match[1] . ' ' . $default . $match[2] . $match[3];
560 } else {
561 $out[$key] = $match[1] . ' ' . $default . $match[2] . $match[3];
562 }
563 }
564 elseif (preg_match('/^CREATE +INDEX +([a-z0-9_]+) +ON +([a-z0-9_]+)([\s(]+.*|)$/is',
565 $query,
566 $match))
567 {
568 $out[$key] = 'CREATE INDEX ' . $default . $match[1]
569 . ' ON ' . $default . $match[2] . $match[3];
570 }
571 else {
572 $out[$key] = $query;
573 echo "<h3 style='color:purple;'>WARNING: UNHANDLED SQL STATEMENT<BR>".htmlentities($query)."</h3>";
574 @flush(); // let user see what's going on in real time
575
576 }
577 // echo "<h4 style='color:green;'>".htmlentities($out[$key])."</h3>";
578 }
579 ksort($out);
580
581 return $out;
582}
583
584/**
585 * Runs all queries in an array.
586 *
587 * If the database table exists, we abort processing that set of queries
588 * so that later queries don't restore initial values
589 *
590 * @param $queries
591 * The array containing one query per element.
592 *
593 * @return void
594 */
595function execute_arrays_queries($queries) {
596
597 ksort($queries);
598 foreach ($queries as $query) {
599
600 if(!do_a_query($query)) return false; // abort on any error
601 }
602 return true; // table sussessfully added
603}
604
605/*
606 * do_a_query
607 * defines it's own error handler to catch and handle errors
608 * and prints sql instead of executing it if global $DEBUG_CREATE is set
609 * returns result handle or FALSE in DEBUG mode returns TRUE
610 */
611function do_a_query($query) {
612 global $DEBUG_CREATE; // flag to print instead of executing SQL
613 // set to the user defined error handler so we can catch "table exists" errors
614 set_time_limit(15); // this could take a while
615
616 if($DEBUG_CREATE){ //debug - list queries
617 echo(htmlentities($query)."<br/>\n");
618 @flush(); // let user see what's going on in real time
619
620 } else { //just show first line of the query
621 echo (htmlentities(strtok($query,"\n\r"))."<br/>\n");
622 @flush(); // let user see what's going on in real time
623 }
624
625 if (!$DEBUG_CREATE) { // actually do the queries
626 set_error_handler('no_error');
627 $result=_db_query($query);
628 restore_error_handler();
629 if( $result===FALSE ) {
630 return FALSE; // table aready exist - abort this file
631 }
632 return $result; // query successful
633 }
634 return TRUE; // query successful
635}
636
637// to catch table exst errors for above
638function no_error($errno, $errstr, $errfile, $errline)
639{
640if(($errno & error_reporting())==0) return; // not reportable error
641
642// DON'T GIVE AWAY INFO ON ACCESS DENIED
643if(eregi('Access denied.*',$errstr,$msg)) die("<h3 style='color:red'>".$msg[0].'</h3>');
644
645
646 switch ($errno) {
647 case E_USER_ERROR:
648 case E_USER_WARNING:
649 if (eregi("Table '[^']*' already exists",html_entity_decode($errstr,ENT_QUOTES),$msg)) {
650 echo '<div style="font-weight:bolder;color:#ab7936;">'.$msg[0].'. File Skipped.</div>';
651 @flush(); // let user see what's going on in real time
652 return;
653 }
654 if (eregi('Duplicate entry.*:',$errstr,$msg)) {
655 echo '<div style="font-weight:bolder;color:red;">'.$msg[0].' File Skipped.</div>';
656 @flush(); // let user see what's going on in real time
657 return;
658 }
659 if (eregi("mysql.*",$errstr,$msg)) {
660 echo '<div style="font-weight:bolder;color:orange;">'.$msg[0].'. File Skipped.</div>';
661 @flush(); // let user see what's going on in real time
662 return;
663 }
664
665 if ($errno == E_USER_ERROR) die ("$errstr<br/> in <b>$errfile</b><br/>line <b>$errline</b>.<br/>\n");
666
667 echo "<b>WARNING:</b> $errstr<br />\n";
668 break;
669 case E_USER_NOTICE:
670 echo "<b>NOTICE:</b> $errstr<br />\n";
671 break;
672 default:
673 die ("$errstr<br/> in <b>$errfile</b><br/>line <b>$errline</b>.<br/>\n");
674 break;
675 }
676
677}
678/**
679 * Defines a fake version of variable_get() and conf_init() if it hasn't been defined yet.
680 *
681 * Necessary becasue we don't want to include bootstrap.inc.
682 *
683 * @return void
684 */
685function define_api() {
686 if (!function_exists('variable_get')) {
687 function variable_get($name, $default) {
688 return $default;
689 }
690 }
691
692
693/*
694 * Locate the appropriate configuration file.
695 * This code is taken from bootstrap.inc (modified to make it position independant)
696 */
697 if (!function_exists('conf_init')) {
698
699 function conf_init() {
700 static $conf = '';
701
702 if ($conf) {
703 return $conf;
704 }
705
706 $confdir = str_replace ( '//', '/', $_SERVER['DOCUMENT_ROOT'].'/sites');
707 $uri = explode('/', $_SERVER['PHP_SELF']);
708 $server = explode('.', rtrim($_SERVER['HTTP_HOST'], '.'));
709 for ($i = count($uri) - 1; $i > 0; $i--) {
710 for ($j = count($server); $j > 0; $j--) {
711 $dir = implode('.', array_slice($server, -$j)) . implode('.', array_slice($uri, 0, $i));
712 if (file_exists("$confdir/$dir/settings.php")) {
713 $conf = "$confdir/$dir";
714 return $conf;
715 }
716 }
717 }
718 $conf = "$confdir/default";
719 return $conf;
720 }
721 }
722}
723/*
724 * Scan all module directories an return an array of database files
725 * for the current dbms.
726 *
727 * For Drupal 4.7, if there is an installer file the database files are skipped
728 *
729 * @param $dbms The database type (mysql/pgsql)
730 *
731 * @return
732 * array of full paths to all .$dbms files
733 */
734function find_modules($dbms,$mods_dir='') {
735
736set_time_limit(10); // this could take a while
737
738// if we are not recursing, set the modules directory
739 if ($mods_dir=='')
740 $mods_dir = str_replace ( '//', '/', $_SERVER['DOCUMENT_ROOT'].'/modules');
741
742 $modules = array();
743
744 // mysql patch for paypal framework module which needs a different
745 // file for MySQL 4.0 and 4.1 (perhaps others)
746
747 if ($dbms='mysql') {
748 $dbmsv = '-'. preg_replace('/(^[0-9]\.[0-9]+)(\..*)/','$1',mysql_get_server_info());
749 } else $dbmsv='';
750
751 // check for installers and skip if there is one
752 $installer=glob("$mods_dir/*.install");
753 if($installer) {
754 echo('<div style="font-weight:bolder;color:#808000;">"'.$installer[0].'" found.<BR/>Module skipped.</div>');
755 } else {
756
757 // Check for .$dbms files for this directory.
758 $SQL_files = glob("$mods_dir/*.$dbms");
759 // Get all of the .$dbms files for this directory.
760
761 if($SQL_files ) foreach ($SQL_files as $filename){
762 // if there is a version-specific database file, use it instead!
763 // mainly for paypal_module
764 if($dbmsv && file_exists($filename.$dbmsv)) {
765 $filename = $filename.$dbmsv;
766 }
767 $modules[]=$filename;
768 }
769 usort($modules,'dbfile_rank');
770 }
771 $dh = opendir($mods_dir);
772 if (!$dh) {
773 return false;
774 }
775 // recurse for modules with sub_modules (like ecommerce)
776 while (false !== ($dir = readdir($dh))) {
777 if (is_dir($mods_dir . '/' . $dir)) {
778 switch ($dir) {
779 case '.':
780 case '..':
781 continue;
782 default:
783 // check subdirectories recursively
784 $modules = array_merge($modules,find_modules($dbms,"$mods_dir/$dir"));
785
786 }
787
788 }
789 }
790 closedir($dh);
791 return $modules;
792}
793
794//
795// Sort the database files so main files are processed first
796// Currently just compares the number of dots to look for secondary
797// files (eg. zipcodes.us.mysql)
798//
799// This works ok for now and is quick.. for full feature it might
800// be better (but a lot slower) to check for create vs insert files
801//
802function dbfile_rank($a,$b) {
803 $ranka= count(explode('.',$a));
804 $rankb= count(explode('.',$b));
805 return ($ranka==$rankb)? 0: (($ranka<$rankb)?-1:1);
806 // returns > 0 if a has less periods than b
807}
808
809
810// replacement db_connect which allows create if database is mysql
811
812
813function my_db_connect($url,$create=0,$user='',$pass='') {
814
815 global $active_db; //Drupal needs static db connection
816
817 $url = parse_url($url);
818// if we are not mysql just use the normal connect
819 if($url['scheme'] != 'mysql') return db_connect($url);
820
821 // Allow for non-standard MySQL port.
822 if (isset($url['port'])) {
823 $url['host'] = $url['host'] .':'. $url['port'];
824 }
825
826 $connection = @mysql_connect($url['host'], $url['user'], $url['pass'], TRUE) or die(mysql_error());
827$dbname=trim($url['path'],'/');
828 if (mysql_select_db($dbname)) return $connection;
829
830 echo "<h2>Not able to connect to the database $dbname.</h2>";
831
832if(!$create) die ('<p>You must log into your control panel and create the database: <b>'.$dbname.'</b> and grant access to user: <b>'.$url['user'].'</b></p><h3>Try running the wizard again with the "Create Database" box checked.<br/><a class=normal href="http://'. trim($_SERVER['HTTP_HOST'],'/').'/'.trim($_SERVER['PHP_SELF'],'/').'">Click here to run the wizard again.</a></h3>') ;
833
834 echo "<h4>Attempting to create database...</h4>";
835 if($user=='') $user=$url['user'];
836 if($pass=='') $pass=$url['pass'];
837 $tdb=$active_db;
838 $active_db = $connection;
839 if( (do_a_query("CREATE DATABASE IF NOT EXISTS `$dbname` ")==FALSE)
840 || (do_a_query('GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX,
841 ALTER, CREATE TEMPORARY TABLES, LOCK TABLES
842 ON '.$dbname.'.*
843 TO \''.$user.'\' IDENTIFIED BY \''.$pass.'\';') ==FALSE) ) {
844 die ("<h2 style='color:777;'>Due to access restrictions, the table and user access cannot be created for you.</h2><p>You must log into your control panel and create the database: <h3>$dbname</h3> and grant access to user: ".$url['user']."</p>");
845}
846
847 $active_db = $tdb; //restore the global value
848 if (mysql_select_db($dbname)) return $connection;
849 die("<h2>Failed to connect to the new database. Perhaps you do not have sufficient rights.</h2>");
850
851}
852//
853// Build default site title by capitalizing all words seperated
854// by dots and dashes. If you CamelCase the original input, such
855// capitalization will be preserved
856//
857function make_site_title() {
858
859$n = preg_replace(
860 array('/^dev./i','/^www./i','/^new./i'), '', trim(strtolower($_SERVER['HTTP_HOST']),'/')
861);
862
863// make . sections capitalized
864$n = strtr(ucwords(strtr($n,'.',' ')),' ','.');
865// make - sections capitalized
866$n = strtr(ucwords(strtr($n,'-',' ')),' ','-');
867$n = ucwords(strtr($n,'/',' '));
868return $n;
869}
870
871/*
872Convert an array of update queries to update - on duplicate statemets
873expects the update statements to be in the format produced by a mySQL UPDATE Dump
874as generated by phpMyAdmin
875
876The WHERE clause contains the KEY so we remove it.
877
878All non-matching lines are left intact.
879
880NOTE: SQL Statements are expected to be CAPS as produced by the dump, so we use that
881 feature to simplify the regexp!
882
883UPDATE tbl_name SET col_name1=expr1 [, col_name2=expr2 ...] WHERE where_definition
884 ( 1 ) ( 2 ) ( )
885REPLACE INTO tbl_name SET expr1 [, col_name2=expr2 ...] col_name=expr, ... ]
886 ( 1 ) ( 2 )
887
888*/
889
890function do_update_inserts( $queries ) {
891
892return preg_replace(
893 '/UPDATE ([^ ]*) SET (.*) WHERE (.*)/',
894 'REPLACE INTO $1 SET $2',
895 $queries);
896
897}
898
899/*
900
901 reads a file options.mysql in the site configuration folder
902 returns 0 on fail, or count of successful options blocks
903 Global $DO_OPTIONS flag determins how much:
904 0=no, 1=name etc only, 2=process options.mysql
905
906*/
907
908function process_options( $settings, $title, $dbms='mysql' ) {
909 global $DEBUG_CREATE;
910 global $DO_OPTIONS;
911 global $site_name; $l_sn = strlen($site_name);
912 global $site_mail; $l_sm = strlen($site_mail);
913 global $use_clean_urls;
914 global $date_default_timezone; $l_tz = strlen($date_default_timezone);
915
916// system settings will get processed with options.mysql
917$queries=array(
918"UPDATE variable SET name = 'site_name', value = 's:{$l_sn}:\"{$site_name}\";' WHERE name = 'site_name'",
919"UPDATE variable SET name = 'site_mail', value = 's:{$l_sm}:\"{$site_mail}\";' WHERE name = 'site_mail'",
920"UPDATE variable SET name = 'date_default_timezone', value = 's:{$l_tz}:\"{$date_default_timezone}\";' WHERE name = 'date_default_timezone'",
921"UPDATE variable SET name = 'clean_url', value = 's:1:\"{$use_clean_urls}\";' WHERE name = 'clean_url'"
922);
923// 0=no 1=name etc only, 2=process options.mysql
924 if($DO_OPTIONS > 1) {
925 $opsfile = conf_init().'/options.'.$dbms;
926 if (!file_exists($opsfile)) {
927 $opsfile = str_replace( '//', '/', $_SERVER['DOCUMENT_ROOT'].'/sites').'/options.'.$dbms;
928 if (!file_exists($opsfile)) $opsfile='';
929 }
930 if ($opsfile) {
931 echo "<h2>Processing $opsfile</h2>";
932 @flush(); // let user see what's going on in real time
933
934
935 $queries =array_merge($queries, get_queries_from_file($opsfile));
936 @flush(); // let user see what's going on in real time
937
938
939 }
940 }
941 $succes = (execute_arrays_queries(do_update_inserts(get_queries_for_settings($settings, $queries))))?1:0;
942 @flush(); // let user see what's going on in real time
943 return $success;
944}
945
946/*
947 Function to add the current url to the database of urls to process by allcron.php
948
949 This function requires version 3.0 or greater of the universal settings.php file.
950 The database for the common data must have been created!
951
952 This will work with a standard file if a $db_prefix is used to seperate databases
953
954*/
955function add_to_urls () {
956 $ret = TRUE; //any fail makes return 0
957 // Get the database and site definitions.
958 include conf_init() . '/settings.php';
959 if ( !isset($db_prefix_common) ) $db_prefix_common=''; // use database for common if defined
960 if ( (!isset($db_common)) ||$db_common=='' ) $db_common=$db_url; // use database for common if defined
961 if ( $db_common=='' ) {
962 $db_common=$db_url; // if database for common not defined, use main
963 if (isset($db_dbprefix) && ($db_dbprefix !='') ) { // my ver of settings.php -- work it out
964 $url = parse_url($db_common);
965 // rebuild url using base db prefix
966 $db_common = "{$url['scheme']}://{$url['user']}:{$url['pass']}@{$url['host']}/$db_dbprefix";
967 }
968 }
969
970 global $active_db;
971 $old_db=$active_db;
972 $active_db = my_db_connect($db_common,0); // connect to the database for common info
973
974 $query = "CREATE TABLE IF NOT EXISTS {$db_prefix_common}installed_sites (
975 url varchar(100) NOT NULL default '',
976 PRIMARY KEY (url)
977 ) TYPE=MyISAM";
978
979 $ret &= do_a_query($query); // create the table
980 //remove dev prefix from url
981 // $base_url=preg_replace('#^(http://)(dev\.)#i','$1',$base_url);
982
983 $query = "INSERT IGNORE INTO {$db_prefix_common}installed_sites SET url = '".db_escape_string($base_url)."'";
984
985 $ret &= do_a_query($query); // create the table
986
987 return $ret;
988}
989
990/**
991 * API function used by database routines
992 * Encode special characters in a plain-text string for display as HTML.
993 */
994function check_plain($text) {
995 return htmlspecialchars($text, ENT_QUOTES);
996}
997