3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
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 |
9 +--------------------------------------------------------------------+
13 * This api exposes CiviCRM system functionality.
15 * Includes caching, logging, and checking system functionality.
17 * @package CiviCRM_APIv3
21 * Flush all system caches.
23 * @param array $params
25 * - triggers: bool, whether to drop/create SQL triggers; default: FALSE
26 * - session: bool, whether to reset the CiviCRM session data; default: FALSE
30 function 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)
35 return civicrm_api3_create_success();
39 * Adjust Metadata for Flush action.
41 * The metadata is used for setting defaults, documentation & validation.
43 * @param array $params
44 * Array of parameters determined by getfields.
46 function _civicrm_api3_system_flush_spec(&$params) {
47 $params['triggers'] = [
48 'title' => 'Triggers',
49 'description' => 'rebuild triggers (boolean)',
50 'type' => CRM_Utils_Type
::T_BOOLEAN
,
52 $params['session'] = [
53 'title' => 'Sessions',
54 'description' => 'refresh sessions (boolean)',
55 'type' => CRM_Utils_Type
::T_BOOLEAN
,
60 * System.Check API specification (optional).
62 * This is used for documentation and validation.
65 * Description of fields supported by this API call.
67 * @see http://wiki.civicrm.org/confluence/display/CRM/API+Architecture+Standards
69 function _civicrm_api3_system_check_spec(&$spec) {
72 'description' => 'Not a real identifier - do not use',
73 'type' => CRM_Utils_Type
::T_INT
,
77 'description' => 'Unique identifier',
78 'type' => CRM_Utils_Type
::T_STRING
,
82 'description' => 'Short title text',
83 'type' => CRM_Utils_Type
::T_STRING
,
87 'description' => 'Long description html',
88 'type' => CRM_Utils_Type
::T_STRING
,
92 'description' => 'Optional extra help (html string)',
93 'type' => CRM_Utils_Type
::T_STRING
,
96 'title' => 'Severity',
97 'description' => 'Psr\Log\LogLevel string',
98 'type' => CRM_Utils_Type
::T_STRING
,
99 'options' => array_combine(CRM_Utils_Check
::getSeverityList(), CRM_Utils_Check
::getSeverityList()),
101 $spec['severity_id'] = [
102 'title' => 'Severity ID',
103 'description' => 'Integer representation of Psr\Log\LogLevel',
104 'type' => CRM_Utils_Type
::T_INT
,
105 'options' => CRM_Utils_Check
::getSeverityList(),
107 $spec['is_visible'] = [
108 'title' => 'is visible',
109 'description' => '0 if message has been hidden by the user',
110 'type' => CRM_Utils_Type
::T_BOOLEAN
,
112 $spec['hidden_until'] = [
113 'title' => 'Hidden_until',
114 'description' => 'When will hidden message be visible again?',
115 'type' => CRM_Utils_Type
::T_DATE
,
122 * @param array $params
125 * API result descriptor; return items are alert codes/messages
126 * @see civicrm_api3_create_success
127 * @see civicrm_api3_create_error
128 * @throws API_Exception
130 function civicrm_api3_system_check($params) {
131 // array(array('name'=> $, 'severity'=>$, ...))
133 $returnValues = $fields = [];
134 _civicrm_api3_system_check_spec($fields);
136 // array(CRM_Utils_Check_Message)
137 $messages = CRM_Utils_Check
::checkAll();
139 foreach ($messages as $msg) {
140 $returnValues[] = $msg->toArray() +
['id' => $id++
];
143 return _civicrm_api3_basic_array_get('systemCheck', $params, $returnValues, "id", array_keys($fields));
147 * Log entry to system log table.
149 * @param array $params
153 function civicrm_api3_system_log($params) {
154 $log = new CRM_Utils_SystemLogger();
155 // This part means fields with separate db storage are accepted as params which kind of seems more intuitive to me
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?
157 if (!isset($params['context'])) {
158 $params['context'] = [];
160 $specialFields = ['contact_id', 'hostname'];
161 foreach ($specialFields as $specialField) {
162 if (isset($params[$specialField]) && !isset($params['context'])) {
163 $params['context'][$specialField] = $params[$specialField];
166 $returnValues = $log->log($params['level'], $params['message'], $params['context']);
167 return civicrm_api3_create_success($returnValues, $params, 'System', 'Log');
171 * Metadata for log function.
173 * @param array $params
175 function _civicrm_api3_system_log_spec(&$params) {
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,
182 $params['message'] = [
183 'title' => 'Log Message',
184 'description' => 'Standardised message string, you can also ',
185 'type' => CRM_Utils_Type
::T_STRING
,
186 'api.required' => TRUE,
188 $params['context'] = [
189 'title' => 'Log Context',
190 'description' => 'An array of additional data to store.',
191 'type' => CRM_Utils_Type
::T_LONGTEXT
,
194 $params['contact_id'] = [
195 'title' => 'Log Contact ID',
196 'description' => 'Optional ID of relevant contact',
197 'type' => CRM_Utils_Type
::T_INT
,
199 $params['hostname'] = [
200 'title' => 'Log Hostname',
201 'description' => 'Optional name of host',
202 'type' => CRM_Utils_Type
::T_STRING
,
209 * @param array $params
213 function civicrm_api3_system_get($params) {
214 $config = CRM_Core_Config
::singleton();
217 // deprecated in favor of civi.version
218 'version' => CRM_Utils_System
::version(),
219 // deprecated in favor of cms.type
222 'version' => phpversion(),
224 'tz' => date_default_timezone_get(),
225 'sapi' => php_sapi_name(),
226 'extensions' => get_loaded_extensions(),
227 'ini' => _civicrm_api3_system_get_redacted_ini(),
230 'version' => CRM_Core_DAO
::singleValueQuery('SELECT @@version'),
231 'time' => CRM_Core_DAO
::singleValueQuery('SELECT unix_timestamp()'),
232 'vars' => _civicrm_api3_system_get_redacted_mysql(),
235 'version' => $config->userSystem
->getVersion(),
236 'type' => CIVICRM_UF
,
237 'modules' => CRM_Core_Module
::collectStatuses($config->userSystem
->getModules()),
240 'version' => CRM_Utils_System
::version(),
241 'dev' => (\Civi
::settings()->get('environment') === 'Development'),
242 'components' => array_keys(CRM_Core_Component
::getEnabledComponents()),
243 'extensions' => preg_grep('/^uninstalled$/', CRM_Extension_System
::singleton()->getManager()->getStatuses(), PREG_GREP_INVERT
),
244 'multidomain' => CRM_Core_DAO
::singleValueQuery('SELECT count(*) FROM civicrm_domain') > 1,
245 'settings' => _civicrm_api3_system_get_redacted_settings(),
246 'exampleUrl' => CRM_Utils_System
::url('civicrm/example', NULL, TRUE, NULL, FALSE),
249 'software' => $_SERVER['SERVER_SOFTWARE'] ??
NULL,
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',
254 'type' => php_uname('s'),
255 'release' => php_uname('r'),
256 'version' => php_uname('v'),
257 'machine' => php_uname('m'),
262 return civicrm_api3_create_success($returnValues, $params, 'System', 'get');
266 * Generate a sanitized/anonymized/redacted dump of the PHP configuration.
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.
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
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.
286 function _civicrm_api3_system_get_redacted_ini() {
287 static $whitelist = NULL;
288 if ($whitelist === NULL) {
289 $whitelist = _civicrm_api3_system_get_whitelist(__DIR__
. '/System/ini-whitelist.txt');
292 $inis = ini_get_all(NULL, FALSE);
294 foreach ($inis as $k => $v) {
295 if (empty($v) ||
in_array($k, $whitelist)) {
299 $result[$k] = 'REDACTED';
307 * Generate ae sanitized/anonymized/redacted dump of MySQL configuration.
310 * @see _civicrm_api3_system_get_redacted_ini
312 function _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');
318 $inis = ini_get_all(NULL, FALSE);
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
;
326 $result[$dao->Variable_name
] = 'REDACTED';
334 * Get redacted settings.
337 * @throws CiviCRM_API3_Exception
339 function _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');
345 $apiResult = civicrm_api3('Setting', 'get', []);
347 foreach ($apiResult['values'] as $settings) {
348 foreach ($settings as $key => $value) {
349 if (in_array($key, $whitelist)) {
350 $result[$key] = $value;
361 * @param string $whitelistFile
362 * Name of a file. Each line is a field name. Comments begin with "#".
365 function _civicrm_api3_system_get_whitelist($whitelistFile) {
366 $whitelist = array_filter(
367 explode("\n", file_get_contents($whitelistFile)),
369 return !empty($k) && !preg_match('/^\s*#/', $k);
376 * Update log table structures.
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.
381 function civicrm_api3_system_updatelogtables($params) {
382 $schema = new CRM_Logging_Schema();
383 $updatedTablesCount = $schema->updateLogTableSchema($params);
384 return civicrm_api3_create_success($updatedTablesCount);
388 * Update log table structures.
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.
393 * @param array $params
397 * @throws \API_Exception
399 function civicrm_api3_system_utf8conversion($params) {
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'],
408 return civicrm_api3_create_success(1);
410 throw new API_Exception('Conversion failed');
414 * Metadata for conversion function.
416 * @param array $params
418 function _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,
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\_%',
429 $params['databases'] = [
430 'title' => ts('CSV list of database names (defaults to CiviCRM database)'),
431 'type' => CRM_Utils_Type
::T_STRING
,
436 * Adjust Metadata for Flush action.
438 * The metadata is used for setting defaults, documentation & validation.
440 * @param array $params
441 * Array of parameters determined by getfields.
443 function _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
,
448 'api.default' => FALSE,
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
,
454 'api.default' => FALSE,
461 * This adds any indexes that exist in the schema but not the database.
463 * @param array $params
467 function 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));
470 return civicrm_api3_create_success(1);
474 * Declare metadata for api System.getmissingindices
476 * @param array $params
478 function _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'),
487 * Get an array of indices that should be defined but are not.
489 * @param array $params
493 function civicrm_api3_system_getmissingindices($params) {
494 $tables = empty($params['tables']) ?
FALSE : (array) $params['tables'];
495 $indices = CRM_Core_BAO_SchemaHandler
::getMissingIndices(FALSE, $tables);
496 return civicrm_api3_create_success($indices);
500 * Declare metadata for api System.getmissingindices
502 * @param array $params
504 function _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'),
513 * Creates missing log tables.
515 * CRM-20838 - This adds any missing log tables into the database.
517 function civicrm_api3_system_createmissinglogtables() {
518 $schema = new CRM_Logging_Schema();
519 $missingLogTables = $schema->getMissingLogTables();
520 if (!empty($missingLogTables)) {
521 foreach ($missingLogTables as $tableName) {
522 $schema->fixSchemaDifferencesFor($tableName);
525 return civicrm_api3_create_success(1);
529 * Rebuild Multilingual Schema
532 function civicrm_api3_system_rebuildmultilingualschema() {
533 $locales = CRM_Core_I18n
::getMultilingual();
535 CRM_Core_I18n_Schema
::rebuildMultilingualSchema($locales);
536 return civicrm_api3_create_success(1);
539 throw new API_Exception('Cannot call rebuild Multilingual schema on non Multilingual database');