Updated to Drupal 8.6.4, which is PHP 7.3 friendly. Also updated HTMLaw library....
[yaffs-website] / web / core / lib / Drupal / Core / Database / Install / Tasks.php
1 <?php
2
3 namespace Drupal\Core\Database\Install;
4
5 use Drupal\Core\Database\Database;
6
7 /**
8  * Database installer structure.
9  *
10  * Defines basic Drupal requirements for databases.
11  */
12 abstract class Tasks {
13
14   /**
15    * The name of the PDO driver this database type requires.
16    *
17    * @var string
18    */
19   protected $pdoDriver;
20
21   /**
22    * Structure that describes each task to run.
23    *
24    * @var array
25    *
26    * Each value of the tasks array is an associative array defining the function
27    * to call (optional) and any arguments to be passed to the function.
28    */
29   protected $tasks = [
30     [
31       'function'    => 'checkEngineVersion',
32       'arguments'   => [],
33     ],
34     [
35       'arguments'   => [
36         'CREATE TABLE {drupal_install_test} (id int NULL)',
37         'Drupal can use CREATE TABLE database commands.',
38         'Failed to <strong>CREATE</strong> a test table on your database server with the command %query. The server reports the following message: %error.<p>Are you sure the configured username has the necessary permissions to create tables in the database?</p>',
39         TRUE,
40       ],
41     ],
42     [
43       'arguments'   => [
44         'INSERT INTO {drupal_install_test} (id) VALUES (1)',
45         'Drupal can use INSERT database commands.',
46         'Failed to <strong>INSERT</strong> a value into a test table on your database server. We tried inserting a value with the command %query and the server reported the following error: %error.',
47       ],
48     ],
49     [
50       'arguments'   => [
51         'UPDATE {drupal_install_test} SET id = 2',
52         'Drupal can use UPDATE database commands.',
53         'Failed to <strong>UPDATE</strong> a value in a test table on your database server. We tried updating a value with the command %query and the server reported the following error: %error.',
54       ],
55     ],
56     [
57       'arguments'   => [
58         'DELETE FROM {drupal_install_test}',
59         'Drupal can use DELETE database commands.',
60         'Failed to <strong>DELETE</strong> a value from a test table on your database server. We tried deleting a value with the command %query and the server reported the following error: %error.',
61       ],
62     ],
63     [
64       'arguments'   => [
65         'DROP TABLE {drupal_install_test}',
66         'Drupal can use DROP TABLE database commands.',
67         'Failed to <strong>DROP</strong> a test table from your database server. We tried dropping a table with the command %query and the server reported the following error %error.',
68       ],
69     ],
70   ];
71
72   /**
73    * Results from tasks.
74    *
75    * @var array
76    */
77   protected $results = [
78     'fail' => [],
79     'pass' => [],
80   ];
81
82   /**
83    * Ensure the PDO driver is supported by the version of PHP in use.
84    */
85   protected function hasPdoDriver() {
86     return in_array($this->pdoDriver, \PDO::getAvailableDrivers());
87   }
88
89   /**
90    * Assert test as failed.
91    */
92   protected function fail($message) {
93     $this->results['fail'][] = $message;
94   }
95
96   /**
97    * Assert test as a pass.
98    */
99   protected function pass($message) {
100     $this->results['pass'][] = $message;
101   }
102
103   /**
104    * Check whether Drupal is installable on the database.
105    */
106   public function installable() {
107     return $this->hasPdoDriver() && empty($this->error);
108   }
109
110   /**
111    * Return the human-readable name of the driver.
112    */
113   abstract public function name();
114
115   /**
116    * Return the minimum required version of the engine.
117    *
118    * @return
119    *   A version string. If not NULL, it will be checked against the version
120    *   reported by the Database engine using version_compare().
121    */
122   public function minimumVersion() {
123     return NULL;
124   }
125
126   /**
127    * Run database tasks and tests to see if Drupal can run on the database.
128    *
129    * @return array
130    *   A list of error messages.
131    */
132   public function runTasks() {
133     // We need to establish a connection before we can run tests.
134     if ($this->connect()) {
135       foreach ($this->tasks as $task) {
136         if (!isset($task['function'])) {
137           $task['function'] = 'runTestQuery';
138         }
139         if (method_exists($this, $task['function'])) {
140           // Returning false is fatal. No other tasks can run.
141           if (FALSE === call_user_func_array([$this, $task['function']], $task['arguments'])) {
142             break;
143           }
144         }
145         else {
146           $this->fail(t("Failed to run all tasks against the database server. The task %task wasn't found.", ['%task' => $task['function']]));
147         }
148       }
149     }
150     return $this->results['fail'];
151   }
152
153   /**
154    * Check if we can connect to the database.
155    */
156   protected function connect() {
157     try {
158       // This doesn't actually test the connection.
159       Database::setActiveConnection();
160       // Now actually do a check.
161       Database::getConnection();
162       $this->pass('Drupal can CONNECT to the database ok.');
163     }
164     catch (\Exception $e) {
165       $this->fail(t('Failed to connect to your database server. The server reports the following message: %error.<ul><li>Is the database server running?</li><li>Does the database exist, and have you entered the correct database name?</li><li>Have you entered the correct username and password?</li><li>Have you entered the correct database hostname?</li></ul>', ['%error' => $e->getMessage()]));
166       return FALSE;
167     }
168     return TRUE;
169   }
170
171   /**
172    * Run SQL tests to ensure the database can execute commands with the current user.
173    */
174   protected function runTestQuery($query, $pass, $fail, $fatal = FALSE) {
175     try {
176       Database::getConnection()->query($query);
177       $this->pass(t($pass));
178     }
179     catch (\Exception $e) {
180       $this->fail(t($fail, ['%query' => $query, '%error' => $e->getMessage(), '%name' => $this->name()]));
181       return !$fatal;
182     }
183   }
184
185   /**
186    * Check the engine version.
187    */
188   protected function checkEngineVersion() {
189     // Ensure that the database server has the right version.
190     if ($this->minimumVersion() && version_compare(Database::getConnection()->version(), $this->minimumVersion(), '<')) {
191       $this->fail(t("The database server version %version is less than the minimum required version %minimum_version.", ['%version' => Database::getConnection()->version(), '%minimum_version' => $this->minimumVersion()]));
192     }
193   }
194
195   /**
196    * Return driver specific configuration options.
197    *
198    * @param $database
199    *   An array of driver specific configuration options.
200    *
201    * @return
202    *   The options form array.
203    */
204   public function getFormOptions(array $database) {
205     $form['database'] = [
206       '#type' => 'textfield',
207       '#title' => t('Database name'),
208       '#default_value' => empty($database['database']) ? '' : $database['database'],
209       '#size' => 45,
210       '#required' => TRUE,
211       '#states' => [
212         'required' => [
213           ':input[name=driver]' => ['value' => $this->pdoDriver],
214         ],
215       ],
216     ];
217
218     $form['username'] = [
219       '#type' => 'textfield',
220       '#title' => t('Database username'),
221       '#default_value' => empty($database['username']) ? '' : $database['username'],
222       '#size' => 45,
223       '#required' => TRUE,
224       '#states' => [
225         'required' => [
226           ':input[name=driver]' => ['value' => $this->pdoDriver],
227         ],
228       ],
229     ];
230
231     $form['password'] = [
232       '#type' => 'password',
233       '#title' => t('Database password'),
234       '#default_value' => empty($database['password']) ? '' : $database['password'],
235       '#required' => FALSE,
236       '#size' => 45,
237     ];
238
239     $form['advanced_options'] = [
240       '#type' => 'details',
241       '#title' => t('Advanced options'),
242       '#weight' => 10,
243     ];
244
245     $profile = drupal_get_profile();
246     $db_prefix = ($profile == 'standard') ? 'drupal_' : $profile . '_';
247     $form['advanced_options']['prefix'] = [
248       '#type' => 'textfield',
249       '#title' => t('Table name prefix'),
250       '#default_value' => empty($database['prefix']) ? '' : $database['prefix'],
251       '#size' => 45,
252       '#description' => t('If more than one application will be sharing this database, a unique table name prefix – such as %prefix – will prevent collisions.', ['%prefix' => $db_prefix]),
253       '#weight' => 10,
254     ];
255
256     $form['advanced_options']['host'] = [
257       '#type' => 'textfield',
258       '#title' => t('Host'),
259       '#default_value' => empty($database['host']) ? 'localhost' : $database['host'],
260       '#size' => 45,
261       // Hostnames can be 255 characters long.
262       '#maxlength' => 255,
263       '#required' => TRUE,
264     ];
265
266     $form['advanced_options']['port'] = [
267       '#type' => 'number',
268       '#title' => t('Port number'),
269       '#default_value' => empty($database['port']) ? '' : $database['port'],
270       '#min' => 0,
271       '#max' => 65535,
272     ];
273
274     return $form;
275   }
276
277   /**
278    * Validates driver specific configuration settings.
279    *
280    * Checks to ensure correct basic database settings and that a proper
281    * connection to the database can be established.
282    *
283    * @param $database
284    *   An array of driver specific configuration options.
285    *
286    * @return
287    *   An array of driver configuration errors, keyed by form element name.
288    */
289   public function validateDatabaseSettings($database) {
290     $errors = [];
291
292     // Verify the table prefix.
293     if (!empty($database['prefix']) && is_string($database['prefix']) && !preg_match('/^[A-Za-z0-9_.]+$/', $database['prefix'])) {
294       $errors[$database['driver'] . '][prefix'] = t('The database table prefix you have entered, %prefix, is invalid. The table prefix can only contain alphanumeric characters, periods, or underscores.', ['%prefix' => $database['prefix']]);
295     }
296
297     return $errors;
298   }
299
300 }