Merge pull request #19683 from colemanw/searchDisplayFixes
[civicrm-core.git] / api / v3 / System.php
CommitLineData
6a488035 1<?php
6a488035
TO
2/*
3 +--------------------------------------------------------------------+
a30c801b 4 | Copyright CiviCRM LLC. All rights reserved. |
6a488035 5 | |
a30c801b
TO
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
6a488035
TO
9 +--------------------------------------------------------------------+
10 */
11
12/**
b081365f 13 * This api exposes CiviCRM system functionality.
6a488035 14 *
b081365f 15 * Includes caching, logging, and checking system functionality.
6a488035 16 *
b081365f 17 * @package CiviCRM_APIv3
6a488035
TO
18 */
19
20/**
9d32e6f7 21 * Flush all system caches.
6a488035 22 *
cf470720
TO
23 * @param array $params
24 * Input parameters.
c28e1768
CW
25 * - triggers: bool, whether to drop/create SQL triggers; default: FALSE
26 * - session: bool, whether to reset the CiviCRM session data; default: FALSE
6a488035 27 *
c23f45d3 28 * @return array
6a488035
TO
29 */
30function civicrm_api3_system_flush($params) {
31 CRM_Core_Invoke::rebuildMenuAndCaches(
32 CRM_Utils_Array::value('triggers', $params, FALSE),
33 CRM_Utils_Array::value('session', $params, FALSE)
34 );
35 return civicrm_api3_create_success();
36}
37
11e09c59 38/**
9d32e6f7 39 * Adjust Metadata for Flush action.
6a488035 40 *
0aa0303c
EM
41 * The metadata is used for setting defaults, documentation & validation.
42 *
cf470720 43 * @param array $params
b081365f 44 * Array of parameters determined by getfields.
6a488035 45 */
9b873358 46function _civicrm_api3_system_flush_spec(&$params) {
cf8f0fff 47 $params['triggers'] = [
b2ed8e73
CW
48 'title' => 'Triggers',
49 'description' => 'rebuild triggers (boolean)',
50 'type' => CRM_Utils_Type::T_BOOLEAN,
cf8f0fff
CW
51 ];
52 $params['session'] = [
b2ed8e73
CW
53 'title' => 'Sessions',
54 'description' => 'refresh sessions (boolean)',
55 'type' => CRM_Utils_Type::T_BOOLEAN,
cf8f0fff 56 ];
9ef501da 57}
6a488035 58
9ef501da 59/**
9d32e6f7
EM
60 * System.Check API specification (optional).
61 *
9ef501da
TO
62 * This is used for documentation and validation.
63 *
cf470720
TO
64 * @param array $spec
65 * Description of fields supported by this API call.
9d32e6f7 66 *
9ef501da
TO
67 * @see http://wiki.civicrm.org/confluence/display/CRM/API+Architecture+Standards
68 */
69function _civicrm_api3_system_check_spec(&$spec) {
cf8f0fff 70 $spec['id'] = [
e5e4a5b2
CW
71 'title' => 'ID',
72 'description' => 'Not a real identifier - do not use',
73 'type' => CRM_Utils_Type::T_INT,
cf8f0fff
CW
74 ];
75 $spec['name'] = [
e5e4a5b2
CW
76 'title' => 'Name',
77 'description' => 'Unique identifier',
78 'type' => CRM_Utils_Type::T_STRING,
cf8f0fff
CW
79 ];
80 $spec['title'] = [
e5e4a5b2
CW
81 'title' => 'Title',
82 'description' => 'Short title text',
83 'type' => CRM_Utils_Type::T_STRING,
cf8f0fff
CW
84 ];
85 $spec['message'] = [
e5e4a5b2
CW
86 'title' => 'Message',
87 'description' => 'Long description html',
88 'type' => CRM_Utils_Type::T_STRING,
cf8f0fff
CW
89 ];
90 $spec['help'] = [
e5e4a5b2
CW
91 'title' => 'Help',
92 'description' => 'Optional extra help (html string)',
93 'type' => CRM_Utils_Type::T_STRING,
cf8f0fff
CW
94 ];
95 $spec['severity'] = [
e5e4a5b2 96 'title' => 'Severity',
d1fa280a
CW
97 'description' => 'Psr\Log\LogLevel string',
98 'type' => CRM_Utils_Type::T_STRING,
0e1b333f 99 'options' => array_combine(CRM_Utils_Check::getSeverityList(), CRM_Utils_Check::getSeverityList()),
cf8f0fff
CW
100 ];
101 $spec['severity_id'] = [
d1fa280a 102 'title' => 'Severity ID',
e5e4a5b2
CW
103 'description' => 'Integer representation of Psr\Log\LogLevel',
104 'type' => CRM_Utils_Type::T_INT,
0e1b333f 105 'options' => CRM_Utils_Check::getSeverityList(),
cf8f0fff
CW
106 ];
107 $spec['is_visible'] = [
fc8d84da 108 'title' => 'is visible',
e5e4a5b2 109 'description' => '0 if message has been hidden by the user',
a1c17079 110 'type' => CRM_Utils_Type::T_BOOLEAN,
cf8f0fff
CW
111 ];
112 $spec['hidden_until'] = [
e5e4a5b2
CW
113 'title' => 'Hidden_until',
114 'description' => 'When will hidden message be visible again?',
115 'type' => CRM_Utils_Type::T_DATE,
cf8f0fff 116 ];
232624b1 117}
9ef501da
TO
118
119/**
b081365f 120 * System Check API.
9ef501da
TO
121 *
122 * @param array $params
9d32e6f7 123 *
a6c01b45 124 * @return array
72b3a70c 125 * API result descriptor; return items are alert codes/messages
9ef501da
TO
126 * @see civicrm_api3_create_success
127 * @see civicrm_api3_create_error
128 * @throws API_Exception
129 */
130function civicrm_api3_system_check($params) {
e918c16d 131 // array(array('name'=> $, 'severity'=>$, ...))
7c6fb573 132 $id = 1;
cf8f0fff 133 $returnValues = $fields = [];
e5e4a5b2 134 _civicrm_api3_system_check_spec($fields);
e918c16d
NM
135
136 // array(CRM_Utils_Check_Message)
e5e4a5b2 137 $messages = CRM_Utils_Check::checkAll();
e918c16d 138
7c6fb573 139 foreach ($messages as $msg) {
cf8f0fff 140 $returnValues[] = $msg->toArray() + ['id' => $id++];
46a903fb
NM
141 }
142
e5e4a5b2 143 return _civicrm_api3_basic_array_get('systemCheck', $params, $returnValues, "id", array_keys($fields));
e2bef985 144}
145
146/**
9d32e6f7
EM
147 * Log entry to system log table.
148 *
c490a46a 149 * @param array $params
e2bef985 150 *
151 * @return array
152 */
153function civicrm_api3_system_log($params) {
154 $log = new CRM_Utils_SystemLogger();
9d32e6f7 155 // This part means fields with separate db storage are accepted as params which kind of seems more intuitive to me
e2bef985 156 // because I felt like not doing this required a bunch of explanation in the spec function - but perhaps other won't see it as helpful?
22e263ad 157 if (!isset($params['context'])) {
cf8f0fff 158 $params['context'] = [];
e2bef985 159 }
cf8f0fff 160 $specialFields = ['contact_id', 'hostname'];
22e263ad
TO
161 foreach ($specialFields as $specialField) {
162 if (isset($params[$specialField]) && !isset($params['context'])) {
e2bef985 163 $params['context'][$specialField] = $params[$specialField];
164 }
165 }
166 $returnValues = $log->log($params['level'], $params['message'], $params['context']);
167 return civicrm_api3_create_success($returnValues, $params, 'System', 'Log');
168}
169
170/**
d1b0d05e
EM
171 * Metadata for log function.
172 *
c490a46a 173 * @param array $params
e2bef985 174 */
4f8ccea0 175function _civicrm_api3_system_log_spec(&$params) {
cf8f0fff 176 $params['level'] = [
e2bef985 177 'title' => 'Log Level',
178 'description' => 'Log level as described in PSR3 (info, debug, warning etc)',
179 'type' => CRM_Utils_Type::T_STRING,
180 'api.required' => TRUE,
cf8f0fff
CW
181 ];
182 $params['message'] = [
e2bef985 183 'title' => 'Log Message',
184 'description' => 'Standardised message string, you can also ',
185 'type' => CRM_Utils_Type::T_STRING,
186 'api.required' => TRUE,
cf8f0fff
CW
187 ];
188 $params['context'] = [
e2bef985 189 'title' => 'Log Context',
190 'description' => 'An array of additional data to store.',
191 'type' => CRM_Utils_Type::T_LONGTEXT,
cf8f0fff
CW
192 'api.default' => [],
193 ];
194 $params['contact_id'] = [
e2bef985 195 'title' => 'Log Contact ID',
196 'description' => 'Optional ID of relevant contact',
197 'type' => CRM_Utils_Type::T_INT,
cf8f0fff
CW
198 ];
199 $params['hostname'] = [
e2bef985 200 'title' => 'Log Hostname',
201 'description' => 'Optional name of host',
202 'type' => CRM_Utils_Type::T_STRING,
cf8f0fff 203 ];
e2bef985 204}
42bf9336 205
91f1889e 206/**
d1b0d05e 207 * System.Get API.
91f1889e 208 *
24a70b66 209 * @param array $params
d1b0d05e 210 *
24a70b66 211 * @return array
91f1889e
TO
212 */
213function civicrm_api3_system_get($params) {
5bbcc823 214 $config = CRM_Core_Config::singleton();
cf8f0fff
CW
215 $returnValues = [
216 [
7c31ae57
SL
217 // deprecated in favor of civi.version
218 'version' => CRM_Utils_System::version(),
219 // deprecated in favor of cms.type
220 'uf' => CIVICRM_UF,
cf8f0fff 221 'php' => [
5bbcc823 222 'version' => phpversion(),
40278a8e 223 'time' => time(),
5bbcc823 224 'tz' => date_default_timezone_get(),
d7aad22f 225 'sapi' => php_sapi_name(),
5bbcc823
TO
226 'extensions' => get_loaded_extensions(),
227 'ini' => _civicrm_api3_system_get_redacted_ini(),
cf8f0fff
CW
228 ],
229 'mysql' => [
5bbcc823 230 'version' => CRM_Core_DAO::singleValueQuery('SELECT @@version'),
40278a8e 231 'time' => CRM_Core_DAO::singleValueQuery('SELECT unix_timestamp()'),
7163c128 232 'vars' => _civicrm_api3_system_get_redacted_mysql(),
cf8f0fff
CW
233 ],
234 'cms' => [
594260ad 235 'version' => $config->userSystem->getVersion(),
5bbcc823
TO
236 'type' => CIVICRM_UF,
237 'modules' => CRM_Core_Module::collectStatuses($config->userSystem->getModules()),
cf8f0fff
CW
238 ],
239 'civi' => [
5bbcc823 240 'version' => CRM_Utils_System::version(),
84d94b64 241 'dev' => (\Civi::settings()->get('environment') === 'Development'),
5bbcc823 242 'components' => array_keys(CRM_Core_Component::getEnabledComponents()),
7237222f 243 'extensions' => preg_grep('/^uninstalled$/', CRM_Extension_System::singleton()->getManager()->getStatuses(), PREG_GREP_INVERT),
41ccb6fc
C
244 'multidomain' => CRM_Core_DAO::singleValueQuery('SELECT count(*) FROM civicrm_domain') > 1,
245 'settings' => _civicrm_api3_system_get_redacted_settings(),
5bbcc823 246 'exampleUrl' => CRM_Utils_System::url('civicrm/example', NULL, TRUE, NULL, FALSE),
cf8f0fff
CW
247 ],
248 'http' => [
6b409353 249 'software' => $_SERVER['SERVER_SOFTWARE'] ?? NULL,
d7aad22f
C
250 'forwarded' => !empty($_SERVER['HTTP_X_FORWARDED_FOR']) || !empty($_SERVER['X_FORWARDED_PROTO']),
251 'port' => (empty($_SERVER['SERVER_PORT']) || $_SERVER['SERVER_PORT'] == 80 || $_SERVER['SERVER_PORT'] == 443) ? 'Standard' : 'Nonstandard',
cf8f0fff
CW
252 ],
253 'os' => [
d7aad22f
C
254 'type' => php_uname('s'),
255 'release' => php_uname('r'),
256 'version' => php_uname('v'),
257 'machine' => php_uname('m'),
cf8f0fff
CW
258 ],
259 ],
260 ];
5bbcc823 261
91f1889e
TO
262 return civicrm_api3_create_success($returnValues, $params, 'System', 'get');
263}
5bbcc823
TO
264
265/**
266 * Generate a sanitized/anonymized/redacted dump of the PHP configuration.
267 *
268 * Some INI fields contain site-identifying information (SII) -- e.g. URLs,
269 * hostnames, file paths, IP addresses, passwords, or free-form comments
270 * could be used to identify a site or gain access to its resources.
271 *
272 * A number of INI fields have been examined to determine whether they
273 * contain SII. Approved fields are put in a whitelist; all other fields
274 * are redacted.
275 *
276 * Redaction hides the substance of a field but does not completely omit
277 * all information. Consider the field 'mail.log' - setting this field
278 * has a functional effect (it enables or disables the logging behavior)
279 * and also points to particular file. Empty values (FALSE/NULL/0/"")
280 * will pass through redaction, but all other values will be replaced
281 * by a string (eg "REDACTED"). This roughly indicates whether the
282 * option is enabled/disabled without giving away its content.
283 *
284 * @return array
285 */
286function _civicrm_api3_system_get_redacted_ini() {
287 static $whitelist = NULL;
288 if ($whitelist === NULL) {
7163c128 289 $whitelist = _civicrm_api3_system_get_whitelist(__DIR__ . '/System/ini-whitelist.txt');
5bbcc823
TO
290 }
291
292 $inis = ini_get_all(NULL, FALSE);
cf8f0fff 293 $result = [];
5bbcc823
TO
294 foreach ($inis as $k => $v) {
295 if (empty($v) || in_array($k, $whitelist)) {
296 $result[$k] = $v;
297 }
298 else {
299 $result[$k] = 'REDACTED';
300 }
301 }
302
303 return $result;
304}
7163c128
TO
305
306/**
307 * Generate ae sanitized/anonymized/redacted dump of MySQL configuration.
308 *
309 * @return array
310 * @see _civicrm_api3_system_get_redacted_ini
311 */
312function _civicrm_api3_system_get_redacted_mysql() {
313 static $whitelist = NULL;
314 if ($whitelist === NULL) {
315 $whitelist = _civicrm_api3_system_get_whitelist(__DIR__ . '/System/mysql-whitelist.txt');
316 }
317
318 $inis = ini_get_all(NULL, FALSE);
cf8f0fff 319 $result = [];
7163c128
TO
320 $dao = CRM_Core_DAO::executeQuery('SHOW VARIABLES');
321 while ($dao->fetch()) {
322 if (empty($dao->Variable_name) || in_array($dao->Variable_name, $whitelist)) {
323 $result[$dao->Variable_name] = $dao->Value;
324 }
325 else {
326 $result[$dao->Variable_name] = 'REDACTED';
327 }
328 }
329
330 return $result;
331}
332
db01bf2f 333/**
334 * Get redacted settings.
335 *
336 * @return array
337 * @throws CiviCRM_API3_Exception
338 */
41ccb6fc
C
339function _civicrm_api3_system_get_redacted_settings() {
340 static $whitelist = NULL;
341 if ($whitelist === NULL) {
342 $whitelist = _civicrm_api3_system_get_whitelist(__DIR__ . '/System/setting-whitelist.txt');
343 }
344
cf8f0fff
CW
345 $apiResult = civicrm_api3('Setting', 'get', []);
346 $result = [];
41ccb6fc
C
347 foreach ($apiResult['values'] as $settings) {
348 foreach ($settings as $key => $value) {
349 if (in_array($key, $whitelist)) {
350 $result[$key] = $value;
351 }
352 }
353 }
354
355 return $result;
356}
357
7163c128
TO
358/**
359 * Read a whitelist.
360 *
361 * @param string $whitelistFile
362 * Name of a file. Each line is a field name. Comments begin with "#".
363 * @return array
364 */
365function _civicrm_api3_system_get_whitelist($whitelistFile) {
366 $whitelist = array_filter(
367 explode("\n", file_get_contents($whitelistFile)),
368 function ($k) {
369 return !empty($k) && !preg_match('/^\s*#/', $k);
370 }
371 );
372 return $whitelist;
373}
d7ea7150 374
375/**
376 * Update log table structures.
377 *
378 * This updates the engine type if defined in the hook and changes the field type
379 * for log_conn_id to reflect CRM-18193.
380 */
dd05020d 381function civicrm_api3_system_updatelogtables($params) {
d7ea7150 382 $schema = new CRM_Logging_Schema();
dd05020d
MWMC
383 $updatedTablesCount = $schema->updateLogTableSchema($params);
384 return civicrm_api3_create_success($updatedTablesCount);
385}
386
a0a5d4da 387/**
388 * Update log table structures.
389 *
390 * This updates the engine type if defined in the hook and changes the field type
391 * for log_conn_id to reflect CRM-18193.
392 *
393 * @param array $params
394 *
395 * @return array
396 *
397 * @throws \API_Exception
398 */
399function civicrm_api3_system_utf8conversion($params) {
aedfc3ed
MW
400 $params['patterns'] = explode(',', $params['patterns']);
401 $params['databases'] = empty($params['databases']) ? NULL : explode(',', $params['databases']);
402 if (CRM_Core_BAO_SchemaHandler::migrateUtf8mb4(
403 $params['is_revert'],
404 $params['patterns'],
405 $params['databases']
406 )
407 ) {
a0a5d4da 408 return civicrm_api3_create_success(1);
409 }
410 throw new API_Exception('Conversion failed');
411}
412
413/**
414 * Metadata for conversion function.
415 *
416 * @param array $params
417 */
418function _civicrm_api3_system_utf8conversion_spec(&$params) {
419 $params['is_revert'] = [
420 'title' => ts('Revert back from UTF8MB4 to UTF8?'),
421 'type' => CRM_Utils_Type::T_BOOLEAN,
422 'api.default' => FALSE,
423 ];
aedfc3ed
MW
424 $params['patterns'] = [
425 'title' => ts('CSV list of table patterns (defaults to "civicrm\_%")'),
426 'type' => CRM_Utils_Type::T_STRING,
427 'api.default' => 'civicrm\_%',
428 ];
429 $params['databases'] = [
430 'title' => ts('CSV list of database names (defaults to CiviCRM database)'),
431 'type' => CRM_Utils_Type::T_STRING,
432 ];
a0a5d4da 433}
434
dd05020d
MWMC
435/**
436 * Adjust Metadata for Flush action.
437 *
438 * The metadata is used for setting defaults, documentation & validation.
439 *
440 * @param array $params
441 * Array of parameters determined by getfields.
442 */
443function _civicrm_api3_system_updatelogtables_spec(&$params) {
444 $params['updateChangedEngineConfig'] = [
445 'title' => 'Update Engine Config if changed?',
446 'description' => 'By default, we only update if the ENGINE has changed, set this to TRUE to update if the ENGINE_CONFIG has changed.',
447 'type' => CRM_Utils_Type::T_BOOLEAN,
e26df891 448 'api.default' => FALSE,
dd05020d 449 ];
204aa6fb
PF
450 $params['forceEngineMigration'] = [
451 'title' => 'Force storage engine to upgrade to InnoDB?',
452 'description' => 'Older versions of CiviCRM used the ARCHIVE engine by default. Set this to TRUE to migrate the engine to the new default.',
453 'type' => CRM_Utils_Type::T_BOOLEAN,
e26df891 454 'api.default' => FALSE,
204aa6fb 455 ];
49186f94
AS
456}
457
458/**
459 * Update indexes.
460 *
461 * This adds any indexes that exist in the schema but not the database.
8e9480bb 462 *
463 * @param array $params
464 *
465 * @return array
49186f94 466 */
8e9480bb 467function civicrm_api3_system_updateindexes(array $params):array {
468 $tables = empty($params['tables']) ? FALSE : (array) $params['tables'];
469 CRM_Core_BAO_SchemaHandler::createMissingIndices(CRM_Core_BAO_SchemaHandler::getMissingIndices(TRUE, $tables));
49186f94 470 return civicrm_api3_create_success(1);
d7ea7150 471}
cb721356 472
8e9480bb 473/**
474 * Declare metadata for api System.getmissingindices
475 *
476 * @param array $params
477 */
478function _civicrm_api3_system_updateindexes_spec(array &$params) {
479 $params['tables'] = [
480 'type' => CRM_Utils_Type::T_STRING,
481 'api.default' => FALSE,
482 'title' => ts('Optional tables filter'),
483 ];
484}
485
a5e6535c 486/**
487 * Get an array of indices that should be defined but are not.
488 *
138b4c4c 489 * @param array $params
490 *
a5e6535c 491 * @return array
492 */
138b4c4c 493function civicrm_api3_system_getmissingindices($params) {
494 $tables = empty($params['tables']) ? FALSE : (array) $params['tables'];
495 $indices = CRM_Core_BAO_SchemaHandler::getMissingIndices(FALSE, $tables);
a5e6535c 496 return civicrm_api3_create_success($indices);
497}
498
138b4c4c 499/**
500 * Declare metadata for api System.getmissingindices
501 *
502 * @param array $params
503 */
504function _civicrm_api3_system_getmissingindices_spec(&$params) {
505 $params['tables'] = [
506 'type' => CRM_Utils_Type::T_STRING,
507 'api.default' => FALSE,
508 'title' => ts('Optional tables filter'),
509 ];
510}
511
cb721356
JP
512/**
513 * Creates missing log tables.
514 *
515 * CRM-20838 - This adds any missing log tables into the database.
516 */
517function civicrm_api3_system_createmissinglogtables() {
518 $schema = new CRM_Logging_Schema();
519 $missingLogTables = $schema->getMissingLogTables();
520 if (!empty($missingLogTables)) {
521 foreach ($missingLogTables as $tableName) {
fcc20cec 522 $schema->fixSchemaDifferencesFor($tableName);
cb721356
JP
523 }
524 }
525 return civicrm_api3_create_success(1);
526}
7fb9179d
SL
527
528/**
529 * Rebuild Multilingual Schema
530 *
531 */
532function civicrm_api3_system_rebuildmultilingualschema() {
394d18d3
CW
533 $locales = CRM_Core_I18n::getMultilingual();
534 if ($locales) {
7fb9179d
SL
535 CRM_Core_I18n_Schema::rebuildMultilingualSchema($locales);
536 return civicrm_api3_create_success(1);
537 }
538 else {
539 throw new API_Exception('Cannot call rebuild Multilingual schema on non Multilingual database');
540 }
541}