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