MediaWiki master
MysqlCreateUserTask.php
Go to the documentation of this file.
1<?php
2
4
11
18 public function getName() {
19 return 'user';
20 }
21
22 public function getDependencies() {
23 return 'database';
24 }
25
26 public function isSkipped(): bool {
27 $dbUser = $this->getConfigVar( MainConfigNames::DBuser );
28 return $dbUser == $this->getOption( 'InstallUser' )
29 || $this->getOption( 'InstallUser' ) === null;
30 }
31
32 public function execute(): Status {
33 $dbUser = $this->getConfigVar( MainConfigNames::DBuser );
34 $status = $this->getConnection( ITaskContext::CONN_CREATE_DATABASE );
35 if ( !$status->isOK() ) {
36 return $status;
37 }
38
39 $conn = $status->getDB();
40 $server = $this->getConfigVar( MainConfigNames::DBserver );
41 $password = $this->getConfigVar( MainConfigNames::DBpassword );
42 $grantableNames = [];
43
44 if ( $this->getOption( 'CreateDBAccount' ) ) {
45 // Before we blindly try to create a user that already has access,
46 try { // first attempt to connect to the database
47 ( new DatabaseFactory() )->create( 'mysql', [
48 'host' => $server,
49 'user' => $dbUser,
50 'password' => $password,
51 'ssl' => $this->getConfigVar( MainConfigNames::DBssl ),
52 'dbname' => null,
53 'flags' => 0,
54 'tablePrefix' => $this->getConfigVar( MainConfigNames::DBprefix )
55 ] );
56 $grantableNames[] = $this->buildFullUserName( $conn, $dbUser, $server );
57 $tryToCreate = false;
58 } catch ( DBConnectionError $e ) {
59 $tryToCreate = true;
60 }
61 } else {
62 $grantableNames[] = $this->buildFullUserName( $conn, $dbUser, $server );
63 $tryToCreate = false;
64 }
65
66 if ( $tryToCreate ) {
67 $createHostList = [
68 $server,
69 'localhost',
70 'localhost.localdomain',
71 '%'
72 ];
73
74 $createHostList = array_unique( $createHostList );
75 $escPass = $conn->addQuotes( $password );
76
77 foreach ( $createHostList as $host ) {
78 $fullName = $this->buildFullUserName( $conn, $dbUser, $host );
79 if ( !$this->userDefinitelyExists( $conn, $host, $dbUser ) ) {
80 try {
81 $conn->begin( __METHOD__ );
82 $conn->query( "CREATE USER $fullName IDENTIFIED BY $escPass", __METHOD__ );
83 $conn->commit( __METHOD__ );
84 $grantableNames[] = $fullName;
85 } catch ( DBQueryError $dqe ) {
86 if ( $conn->lastErrno() == 1396 /* ER_CANNOT_USER */ ) {
87 // User (probably) already exists
88 $conn->rollback( __METHOD__ );
89 $status->warning( 'config-install-user-alreadyexists', $dbUser );
90 $grantableNames[] = $fullName;
91 break;
92 } else {
93 // If we couldn't create for some bizarre reason and the
94 // user probably doesn't exist, skip the grant
95 $conn->rollback( __METHOD__ );
96 $status->warning( 'config-install-user-create-failed', $dbUser, $dqe->getMessage() );
97 }
98 }
99 } else {
100 $status->warning( 'config-install-user-alreadyexists', $dbUser );
101 $grantableNames[] = $fullName;
102 break;
103 }
104 }
105 }
106
107 // Try to grant to all the users we know exist or we were able to create
108 $dbAllTables = $conn->addIdentifierQuotes( $this->getConfigVar( MainConfigNames::DBname ) ) . '.*';
109 foreach ( $grantableNames as $name ) {
110 try {
111 $conn->begin( __METHOD__ );
112 $conn->query( "GRANT ALL PRIVILEGES ON $dbAllTables TO $name", __METHOD__ );
113 $conn->commit( __METHOD__ );
114 } catch ( DBQueryError $dqe ) {
115 $conn->rollback( __METHOD__ );
116 $status->fatal( 'config-install-user-grant-failed', $dbUser, $dqe->getMessage() );
117 }
118 }
119
120 return $status;
121 }
122
130 private function buildFullUserName( $conn, $name, $host ) {
131 return $conn->addQuotes( $name ) . '@' . $conn->addQuotes( $host );
132 }
133
142 private function userDefinitelyExists( $conn, $host, $user ) {
143 try {
144 $res = $conn->newSelectQueryBuilder()
145 ->select( [ 'Host', 'User' ] )
146 ->from( 'mysql.user' )
147 ->where( [ 'Host' => $host, 'User' => $user ] )
148 ->caller( __METHOD__ )->fetchRow();
149
150 return (bool)$res;
151 } catch ( DBQueryError $dqe ) {
152 return false;
153 }
154 }
155
156}
isSkipped()
Override this to return true to skip the task.
getDependencies()
Get a list of names or aliases of tasks that must be done prior to this task.
getName()
Get the symbolic name of the task.
Base class for installer tasks.
Definition Task.php:24
getOption(string $name)
Get an installer option value.
Definition Task.php:192
getConfigVar(string $name)
Get a configuration variable for the wiki being created.
Definition Task.php:182
A class containing constants representing the names of configuration variables.
const DBname
Name constant for the DBname setting, for use with Config::get()
const DBprefix
Name constant for the DBprefix setting, for use with Config::get()
const DBssl
Name constant for the DBssl setting, for use with Config::get()
const DBserver
Name constant for the DBserver setting, for use with Config::get()
const DBpassword
Name constant for the DBpassword setting, for use with Config::get()
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition Status.php:54
Constructs Database objects.
const CONN_CREATE_DATABASE
A connection for creating DBs, suitable for pre-installation.
Advanced database interface for IDatabase handles that include maintenance methods.