MediaWiki  master
MysqlInstaller.php
Go to the documentation of this file.
1 <?php
27 
35 
36  protected $globalNames = [
37  'wgDBserver',
38  'wgDBname',
39  'wgDBuser',
40  'wgDBpassword',
41  'wgDBprefix',
42  'wgDBTableOptions',
43  ];
44 
45  protected $internalDefaults = [
46  '_MysqlEngine' => 'InnoDB',
47  '_MysqlCharset' => 'binary',
48  '_InstallUser' => 'root',
49  ];
50 
51  public $supportedEngines = [ 'InnoDB' ];
52 
53  public static $minimumVersion = '5.5.8';
54  protected static $notMinimumVersionMessage = 'config-mysql-old';
55 
56  public $webUserPrivs = [
57  'DELETE',
58  'INSERT',
59  'SELECT',
60  'UPDATE',
61  'CREATE TEMPORARY TABLES',
62  ];
63 
67  public function getName() {
68  return 'mysql';
69  }
70 
74  public function isCompiled() {
75  return self::checkExtension( 'mysqli' );
76  }
77 
81  public function getConnectForm() {
82  return $this->getTextBox(
83  'wgDBserver',
84  'config-db-host',
85  [],
86  $this->parent->getHelpBox( 'config-db-host-help' )
87  ) .
88  Html::openElement( 'fieldset' ) .
89  Html::element( 'legend', [], wfMessage( 'config-db-wiki-settings' )->text() ) .
90  $this->getTextBox( 'wgDBname', 'config-db-name', [ 'dir' => 'ltr' ],
91  $this->parent->getHelpBox( 'config-db-name-help' ) ) .
92  $this->getTextBox( 'wgDBprefix', 'config-db-prefix', [ 'dir' => 'ltr' ],
93  $this->parent->getHelpBox( 'config-db-prefix-help' ) ) .
94  Html::closeElement( 'fieldset' ) .
95  $this->getInstallUserBox();
96  }
97 
98  public function submitConnectForm() {
99  // Get variables from the request.
100  $newValues = $this->setVarsFromRequest( [ 'wgDBserver', 'wgDBname', 'wgDBprefix' ] );
101 
102  // Validate them.
103  $status = Status::newGood();
104  if ( !strlen( $newValues['wgDBserver'] ) ) {
105  $status->fatal( 'config-missing-db-host' );
106  }
107  if ( !strlen( $newValues['wgDBname'] ) ) {
108  $status->fatal( 'config-missing-db-name' );
109  } elseif ( !preg_match( '/^[a-z0-9+_-]+$/i', $newValues['wgDBname'] ) ) {
110  $status->fatal( 'config-invalid-db-name', $newValues['wgDBname'] );
111  }
112  if ( !preg_match( '/^[a-z0-9_-]*$/i', $newValues['wgDBprefix'] ) ) {
113  $status->fatal( 'config-invalid-db-prefix', $newValues['wgDBprefix'] );
114  }
115  if ( !$status->isOK() ) {
116  return $status;
117  }
118 
119  // Submit user box
120  $status = $this->submitInstallUserBox();
121  if ( !$status->isOK() ) {
122  return $status;
123  }
124 
125  // Try to connect
126  $status = $this->getConnection();
127  if ( !$status->isOK() ) {
128  return $status;
129  }
133  $conn = $status->value;
134  '@phan-var Database $conn';
135 
136  // Check version
137  return static::meetsMinimumRequirement( $conn->getServerVersion() );
138  }
139 
143  public function openConnection() {
144  $status = Status::newGood();
145  try {
147  $db = Database::factory( 'mysql', [
148  'host' => $this->getVar( 'wgDBserver' ),
149  'user' => $this->getVar( '_InstallUser' ),
150  'password' => $this->getVar( '_InstallPassword' ),
151  'dbname' => false,
152  'flags' => 0,
153  'tablePrefix' => $this->getVar( 'wgDBprefix' ) ] );
154  $status->value = $db;
155  } catch ( DBConnectionError $e ) {
156  $status->fatal( 'config-connection-error', $e->getMessage() );
157  }
158 
159  return $status;
160  }
161 
162  public function preUpgrade() {
163  global $wgDBuser, $wgDBpassword;
164 
165  $status = $this->getConnection();
166  if ( !$status->isOK() ) {
167  $this->parent->showStatusMessage( $status );
168 
169  return;
170  }
174  $conn = $status->value;
175  $conn->selectDB( $this->getVar( 'wgDBname' ) );
176 
177  # Determine existing default character set
178  if ( $conn->tableExists( "revision", __METHOD__ ) ) {
179  $revision = $this->escapeLikeInternal( $this->getVar( 'wgDBprefix' ) . 'revision', '\\' );
180  $res = $conn->query( "SHOW TABLE STATUS LIKE '$revision'", __METHOD__ );
181  $row = $conn->fetchObject( $res );
182  if ( !$row ) {
183  $this->parent->showMessage( 'config-show-table-status' );
184  $existingSchema = false;
185  $existingEngine = false;
186  } else {
187  if ( preg_match( '/^latin1/', $row->Collation ) ) {
188  $existingSchema = 'latin1';
189  } elseif ( preg_match( '/^utf8/', $row->Collation ) ) {
190  $existingSchema = 'utf8';
191  } elseif ( preg_match( '/^binary/', $row->Collation ) ) {
192  $existingSchema = 'binary';
193  } else {
194  $existingSchema = false;
195  $this->parent->showMessage( 'config-unknown-collation' );
196  }
197  $existingEngine = $row->Engine ?? $row->Type;
198  }
199  } else {
200  $existingSchema = false;
201  $existingEngine = false;
202  }
203 
204  if ( $existingSchema && $existingSchema != $this->getVar( '_MysqlCharset' ) ) {
205  $this->setVar( '_MysqlCharset', $existingSchema );
206  }
207  if ( $existingEngine && $existingEngine != $this->getVar( '_MysqlEngine' ) ) {
208  $this->setVar( '_MysqlEngine', $existingEngine );
209  }
210 
211  # Normal user and password are selected after this step, so for now
212  # just copy these two
213  $wgDBuser = $this->getVar( '_InstallUser' );
214  $wgDBpassword = $this->getVar( '_InstallPassword' );
215  }
216 
222  protected function escapeLikeInternal( $s, $escapeChar = '`' ) {
223  return str_replace( [ $escapeChar, '%', '_' ],
224  [ "{$escapeChar}{$escapeChar}", "{$escapeChar}%", "{$escapeChar}_" ],
225  $s );
226  }
227 
233  public function getEngines() {
234  $status = $this->getConnection();
235 
239  $conn = $status->value;
240 
241  $engines = [];
242  $res = $conn->query( 'SHOW ENGINES', __METHOD__ );
243  foreach ( $res as $row ) {
244  if ( $row->Support == 'YES' || $row->Support == 'DEFAULT' ) {
245  $engines[] = $row->Engine;
246  }
247  }
248  $engines = array_intersect( $this->supportedEngines, $engines );
249 
250  return $engines;
251  }
252 
258  public function getCharsets() {
259  return [ 'binary', 'utf8' ];
260  }
261 
267  public function canCreateAccounts() {
268  $status = $this->getConnection();
269  if ( !$status->isOK() ) {
270  return false;
271  }
273  $conn = $status->value;
274 
275  // Get current account name
276  $currentName = $conn->selectField( '', 'CURRENT_USER()', '', __METHOD__ );
277  $parts = explode( '@', $currentName );
278  if ( count( $parts ) != 2 ) {
279  return false;
280  }
281  $quotedUser = $conn->addQuotes( $parts[0] ) .
282  '@' . $conn->addQuotes( $parts[1] );
283 
284  // The user needs to have INSERT on mysql.* to be able to CREATE USER
285  // The grantee will be double-quoted in this query, as required
286  $res = $conn->select( 'INFORMATION_SCHEMA.USER_PRIVILEGES', '*',
287  [ 'GRANTEE' => $quotedUser ], __METHOD__ );
288  $insertMysql = false;
289  $grantOptions = array_flip( $this->webUserPrivs );
290  foreach ( $res as $row ) {
291  if ( $row->PRIVILEGE_TYPE == 'INSERT' ) {
292  $insertMysql = true;
293  }
294  if ( $row->IS_GRANTABLE ) {
295  unset( $grantOptions[$row->PRIVILEGE_TYPE] );
296  }
297  }
298 
299  // Check for DB-specific privs for mysql.*
300  if ( !$insertMysql ) {
301  $row = $conn->selectRow( 'INFORMATION_SCHEMA.SCHEMA_PRIVILEGES', '*',
302  [
303  'GRANTEE' => $quotedUser,
304  'TABLE_SCHEMA' => 'mysql',
305  'PRIVILEGE_TYPE' => 'INSERT',
306  ], __METHOD__ );
307  if ( $row ) {
308  $insertMysql = true;
309  }
310  }
311 
312  if ( !$insertMysql ) {
313  return false;
314  }
315 
316  // Check for DB-level grant options
317  $res = $conn->select( 'INFORMATION_SCHEMA.SCHEMA_PRIVILEGES', '*',
318  [
319  'GRANTEE' => $quotedUser,
320  'IS_GRANTABLE' => 1,
321  ], __METHOD__ );
322  foreach ( $res as $row ) {
323  $regex = $this->likeToRegex( $row->TABLE_SCHEMA );
324  if ( preg_match( $regex, $this->getVar( 'wgDBname' ) ) ) {
325  unset( $grantOptions[$row->PRIVILEGE_TYPE] );
326  }
327  }
328  if ( count( $grantOptions ) ) {
329  // Can't grant everything
330  return false;
331  }
332 
333  return true;
334  }
335 
342  protected function likeToRegex( $wildcard ) {
343  $r = preg_quote( $wildcard, '/' );
344  $r = strtr( $r, [
345  '%' => '.*',
346  '_' => '.'
347  ] );
348  return "/$r/s";
349  }
350 
354  public function getSettingsForm() {
355  if ( $this->canCreateAccounts() ) {
356  $noCreateMsg = false;
357  } else {
358  $noCreateMsg = 'config-db-web-no-create-privs';
359  }
360  $s = $this->getWebUserBox( $noCreateMsg );
361 
362  // Do engine selector
363  $engines = $this->getEngines();
364  // If the current default engine is not supported, use an engine that is
365  if ( !in_array( $this->getVar( '_MysqlEngine' ), $engines ) ) {
366  $this->setVar( '_MysqlEngine', reset( $engines ) );
367  }
368 
369  // If the current default charset is not supported, use a charset that is
370  $charsets = $this->getCharsets();
371  if ( !in_array( $this->getVar( '_MysqlCharset' ), $charsets ) ) {
372  $this->setVar( '_MysqlCharset', reset( $charsets ) );
373  }
374 
375  return $s;
376  }
377 
381  public function submitSettingsForm() {
382  $this->setVarsFromRequest( [ '_MysqlEngine', '_MysqlCharset' ] );
383  $status = $this->submitWebUserBox();
384  if ( !$status->isOK() ) {
385  return $status;
386  }
387 
388  // Validate the create checkbox
389  $canCreate = $this->canCreateAccounts();
390  if ( !$canCreate ) {
391  $this->setVar( '_CreateDBAccount', false );
392  $create = false;
393  } else {
394  $create = $this->getVar( '_CreateDBAccount' );
395  }
396 
397  if ( !$create ) {
398  // Test the web account
399  try {
400  Database::factory( 'mysql', [
401  'host' => $this->getVar( 'wgDBserver' ),
402  'user' => $this->getVar( 'wgDBuser' ),
403  'password' => $this->getVar( 'wgDBpassword' ),
404  'dbname' => false,
405  'flags' => 0,
406  'tablePrefix' => $this->getVar( 'wgDBprefix' )
407  ] );
408  } catch ( DBConnectionError $e ) {
409  return Status::newFatal( 'config-connection-error', $e->getMessage() );
410  }
411  }
412 
413  // Validate engines and charsets
414  // This is done pre-submit already so it's just for security
415  $engines = $this->getEngines();
416  if ( !in_array( $this->getVar( '_MysqlEngine' ), $engines ) ) {
417  $this->setVar( '_MysqlEngine', reset( $engines ) );
418  }
419  $charsets = $this->getCharsets();
420  if ( !in_array( $this->getVar( '_MysqlCharset' ), $charsets ) ) {
421  $this->setVar( '_MysqlCharset', reset( $charsets ) );
422  }
423 
424  return Status::newGood();
425  }
426 
427  public function preInstall() {
428  # Add our user callback to installSteps, right before the tables are created.
429  $callback = [
430  'name' => 'user',
431  'callback' => [ $this, 'setupUser' ],
432  ];
433  $this->parent->addInstallStep( $callback, 'tables' );
434  }
435 
439  public function setupDatabase() {
440  $status = $this->getConnection();
441  if ( !$status->isOK() ) {
442  return $status;
443  }
445  $conn = $status->value;
446  $dbName = $this->getVar( 'wgDBname' );
447  if ( !$this->databaseExists( $dbName ) ) {
448  $conn->query(
449  "CREATE DATABASE " . $conn->addIdentifierQuotes( $dbName ) . "CHARACTER SET utf8",
450  __METHOD__
451  );
452  }
453  $conn->selectDB( $dbName );
454  $this->setupSchemaVars();
455 
456  return $status;
457  }
458 
464  private function databaseExists( $dbName ) {
465  $encDatabase = $this->db->addQuotes( $dbName );
466 
467  return $this->db->query(
468  "SELECT 1 FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = $encDatabase",
469  __METHOD__
470  )->numRows() > 0;
471  }
472 
476  public function setupUser() {
477  $dbUser = $this->getVar( 'wgDBuser' );
478  if ( $dbUser == $this->getVar( '_InstallUser' ) ) {
479  return Status::newGood();
480  }
481  $status = $this->getConnection();
482  if ( !$status->isOK() ) {
483  return $status;
484  }
485 
486  $this->setupSchemaVars();
487  $dbName = $this->getVar( 'wgDBname' );
488  $this->db->selectDB( $dbName );
489  $server = $this->getVar( 'wgDBserver' );
490  $password = $this->getVar( 'wgDBpassword' );
491  $grantableNames = [];
492 
493  if ( $this->getVar( '_CreateDBAccount' ) ) {
494  // Before we blindly try to create a user that already has access,
495  try { // first attempt to connect to the database
496  Database::factory( 'mysql', [
497  'host' => $server,
498  'user' => $dbUser,
499  'password' => $password,
500  'dbname' => false,
501  'flags' => 0,
502  'tablePrefix' => $this->getVar( 'wgDBprefix' )
503  ] );
504  $grantableNames[] = $this->buildFullUserName( $dbUser, $server );
505  $tryToCreate = false;
506  } catch ( DBConnectionError $e ) {
507  $tryToCreate = true;
508  }
509  } else {
510  $grantableNames[] = $this->buildFullUserName( $dbUser, $server );
511  $tryToCreate = false;
512  }
513 
514  if ( $tryToCreate ) {
515  $createHostList = [
516  $server,
517  'localhost',
518  'localhost.localdomain',
519  '%'
520  ];
521 
522  $createHostList = array_unique( $createHostList );
523  $escPass = $this->db->addQuotes( $password );
524 
525  foreach ( $createHostList as $host ) {
526  $fullName = $this->buildFullUserName( $dbUser, $host );
527  if ( !$this->userDefinitelyExists( $host, $dbUser ) ) {
528  try {
529  $this->db->begin( __METHOD__ );
530  $this->db->query( "CREATE USER $fullName IDENTIFIED BY $escPass", __METHOD__ );
531  $this->db->commit( __METHOD__ );
532  $grantableNames[] = $fullName;
533  } catch ( DBQueryError $dqe ) {
534  if ( $this->db->lastErrno() == 1396 /* ER_CANNOT_USER */ ) {
535  // User (probably) already exists
536  $this->db->rollback( __METHOD__ );
537  $status->warning( 'config-install-user-alreadyexists', $dbUser );
538  $grantableNames[] = $fullName;
539  break;
540  } else {
541  // If we couldn't create for some bizzare reason and the
542  // user probably doesn't exist, skip the grant
543  $this->db->rollback( __METHOD__ );
544  $status->warning( 'config-install-user-create-failed', $dbUser, $dqe->getMessage() );
545  }
546  }
547  } else {
548  $status->warning( 'config-install-user-alreadyexists', $dbUser );
549  $grantableNames[] = $fullName;
550  break;
551  }
552  }
553  }
554 
555  // Try to grant to all the users we know exist or we were able to create
556  $dbAllTables = $this->db->addIdentifierQuotes( $dbName ) . '.*';
557  foreach ( $grantableNames as $name ) {
558  try {
559  $this->db->begin( __METHOD__ );
560  $this->db->query( "GRANT ALL PRIVILEGES ON $dbAllTables TO $name", __METHOD__ );
561  $this->db->commit( __METHOD__ );
562  } catch ( DBQueryError $dqe ) {
563  $this->db->rollback( __METHOD__ );
564  $status->fatal( 'config-install-user-grant-failed', $dbUser, $dqe->getMessage() );
565  }
566  }
567 
568  return $status;
569  }
570 
577  private function buildFullUserName( $name, $host ) {
578  return $this->db->addQuotes( $name ) . '@' . $this->db->addQuotes( $host );
579  }
580 
588  private function userDefinitelyExists( $host, $user ) {
589  try {
590  $res = $this->db->selectRow( 'mysql.user', [ 'Host', 'User' ],
591  [ 'Host' => $host, 'User' => $user ], __METHOD__ );
592 
593  return (bool)$res;
594  } catch ( DBQueryError $dqe ) {
595  return false;
596  }
597  }
598 
605  protected function getTableOptions() {
606  $options = [];
607  if ( $this->getVar( '_MysqlEngine' ) !== null ) {
608  $options[] = "ENGINE=" . $this->getVar( '_MysqlEngine' );
609  }
610  if ( $this->getVar( '_MysqlCharset' ) !== null ) {
611  $options[] = 'DEFAULT CHARSET=' . $this->getVar( '_MysqlCharset' );
612  }
613 
614  return implode( ', ', $options );
615  }
616 
622  public function getSchemaVars() {
623  return [
624  'wgDBTableOptions' => $this->getTableOptions(),
625  'wgDBname' => $this->getVar( 'wgDBname' ),
626  'wgDBuser' => $this->getVar( 'wgDBuser' ),
627  'wgDBpassword' => $this->getVar( 'wgDBpassword' ),
628  ];
629  }
630 
631  public function getLocalSettings() {
632  $prefix = LocalSettingsGenerator::escapePhpString( $this->getVar( 'wgDBprefix' ) );
634 
635  return "# MySQL specific settings
636 \$wgDBprefix = \"{$prefix}\";
637 
638 # MySQL table options to use during installation or update
639 \$wgDBTableOptions = \"{$tblOpts}\";";
640  }
641 }
MysqlInstaller\getTableOptions
getTableOptions()
Return any table options to be applied to all tables that don't override them.
Definition: MysqlInstaller.php:605
MysqlInstaller\submitSettingsForm
submitSettingsForm()
Definition: MysqlInstaller.php:381
Wikimedia\Rdbms\Database
Relational database abstraction object.
Definition: Database.php:49
MysqlInstaller\likeToRegex
likeToRegex( $wildcard)
Convert a wildcard (as used in LIKE) to a regex Slashes are escaped, slash terminators included.
Definition: MysqlInstaller.php:342
MysqlInstaller\getEngines
getEngines()
Get a list of storage engines that are available and supported.
Definition: MysqlInstaller.php:233
StatusValue\newFatal
static newFatal( $message,... $parameters)
Factory function for fatal errors.
Definition: StatusValue.php:69
DatabaseInstaller\checkExtension
static checkExtension( $name)
Convenience function.
Definition: DatabaseInstaller.php:443
MysqlInstaller\getSettingsForm
getSettingsForm()
Definition: MysqlInstaller.php:354
MysqlInstaller\$supportedEngines
$supportedEngines
Definition: MysqlInstaller.php:51
MysqlInstaller\setupUser
setupUser()
Definition: MysqlInstaller.php:476
MysqlInstaller\userDefinitelyExists
userDefinitelyExists( $host, $user)
Try to see if the user account exists.
Definition: MysqlInstaller.php:588
DatabaseInstaller\getConnection
getConnection()
Connect to the database using the administrative user/password currently defined in the session.
Definition: DatabaseInstaller.php:182
MysqlInstaller\preInstall
preInstall()
Allow DB installers a chance to make last-minute changes before installation occurs.
Definition: MysqlInstaller.php:427
MysqlInstaller\getLocalSettings
getLocalSettings()
Get the DBMS-specific options for LocalSettings.php generation.
Definition: MysqlInstaller.php:631
DatabaseInstaller\getTextBox
getTextBox( $var, $label, $attribs=[], $helpData="")
Get a labelled text box to configure a local variable.
Definition: DatabaseInstaller.php:514
wfMessage
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
Definition: GlobalFunctions.php:1263
$s
$s
Definition: mergeMessageFileList.php:185
MysqlInstaller\openConnection
openConnection()
Definition: MysqlInstaller.php:143
MysqlInstaller\$minimumVersion
static $minimumVersion
Definition: MysqlInstaller.php:53
$res
$res
Definition: testCompression.php:54
$wgDBpassword
$wgDBpassword
Database user's password.
Definition: DefaultSettings.php:1933
MysqlInstaller\getName
getName()
Definition: MysqlInstaller.php:67
MysqlInstaller\buildFullUserName
buildFullUserName( $name, $host)
Return a formal 'User'@'Host' username for use in queries.
Definition: MysqlInstaller.php:577
MysqlInstaller\isCompiled
isCompiled()
Definition: MysqlInstaller.php:74
DatabaseInstaller\submitWebUserBox
submitWebUserBox()
Submit the form from getWebUserBox().
Definition: DatabaseInstaller.php:707
DatabaseInstaller\setupSchemaVars
setupSchemaVars()
Set appropriate schema variables in the current database connection.
Definition: DatabaseInstaller.php:342
MysqlInstaller\$notMinimumVersionMessage
static $notMinimumVersionMessage
Definition: MysqlInstaller.php:54
MysqlInstaller\submitConnectForm
submitConnectForm()
Set variables based on the request array, assuming it was submitted via the form returned by getConne...
Definition: MysqlInstaller.php:98
DatabaseInstaller\getWebUserBox
getWebUserBox( $noCreateMsg=false)
Get a standard web-user fieldset.
Definition: DatabaseInstaller.php:680
Wikimedia\Rdbms\DBQueryError
Definition: DBQueryError.php:27
MysqlInstaller\$internalDefaults
$internalDefaults
Definition: MysqlInstaller.php:45
MysqlInstaller\preUpgrade
preUpgrade()
Allow DB installers a chance to make checks before upgrade.
Definition: MysqlInstaller.php:162
DatabaseInstaller\getVar
getVar( $var, $default=null)
Get a variable, taking local defaults into account.
Definition: DatabaseInstaller.php:484
StatusValue\newGood
static newGood( $value=null)
Factory function for good results.
Definition: StatusValue.php:81
MysqlInstaller\getSchemaVars
getSchemaVars()
Get variables to substitute into tables.sql and the SQL patch files.
Definition: MysqlInstaller.php:622
DatabaseInstaller\submitInstallUserBox
submitInstallUserBox()
Submit a standard install user fieldset.
Definition: DatabaseInstaller.php:667
DatabaseInstaller
Base class for DBMS-specific installation helper classes.
Definition: DatabaseInstaller.php:37
MysqlInstaller\getCharsets
getCharsets()
Get a list of character sets that are available and supported.
Definition: MysqlInstaller.php:258
MysqlInstaller
Class for setting up the MediaWiki database using MySQL.
Definition: MysqlInstaller.php:34
MysqlInstaller\setupDatabase
setupDatabase()
Definition: MysqlInstaller.php:439
MysqlInstaller\$globalNames
$globalNames
Definition: MysqlInstaller.php:36
DatabaseInstaller\setVar
setVar( $name, $value)
Convenience alias for $this->parent->setVar()
Definition: DatabaseInstaller.php:501
DatabaseInstaller\getInstallUserBox
getInstallUserBox()
Get a standard install-user fieldset.
Definition: DatabaseInstaller.php:645
DatabaseInstaller\setVarsFromRequest
setVarsFromRequest( $varNames)
Convenience function to set variables based on form data.
Definition: DatabaseInstaller.php:607
Wikimedia\Rdbms\DBConnectionError
Definition: DBConnectionError.php:26
LocalSettingsGenerator\escapePhpString
static escapePhpString( $string)
Returns the escaped version of a string of php code.
Definition: LocalSettingsGenerator.php:113
MysqlInstaller\databaseExists
databaseExists( $dbName)
Try to see if a given database exists.
Definition: MysqlInstaller.php:464
MysqlInstaller\getConnectForm
getConnectForm()
Definition: MysqlInstaller.php:81
$wgDBuser
$wgDBuser
Database username.
Definition: DefaultSettings.php:1928
DatabaseInstaller\$db
Database $db
The database connection.
Definition: DatabaseInstaller.php:61
MysqlInstaller\$webUserPrivs
$webUserPrivs
Definition: MysqlInstaller.php:56
MysqlInstaller\canCreateAccounts
canCreateAccounts()
Return true if the install user can create accounts.
Definition: MysqlInstaller.php:267
MysqlInstaller\escapeLikeInternal
escapeLikeInternal( $s, $escapeChar='`')
Definition: MysqlInstaller.php:222