function gardens_site_data_refresh_domains in Acquia Cloud Site Factory Connector 8
Same name and namespace in other branches
- 8.2 acsf_init/lib/sites/g/sites.inc \gardens_site_data_refresh_domains()
Returns data for the specified domains directly from the JSON file.
Optionally also stores the data in APC.
Parameters
array $domains: The domain names to look up in the JSON file.
Return value
array An array keyed by the specified domains, whose values are site data arrays or 0 if no site was found for the given domain. If a domain is not present in the array keys, this indicates a sites.json read failure.
2 calls to gardens_site_data_refresh_domains()
- apc_rebuild.php in acsf_init/
lib/ sites/ g/ apc_rebuild.php - gardens_site_data_refresh_one in acsf_init/
lib/ sites/ g/ sites.inc - Returns data for a single domain.
File
- acsf_init/
lib/ sites/ g/ sites.inc, line 378 - ACSF helper functions for Drupal's multi-site directory aliasing feature.
Code
function gardens_site_data_refresh_domains(array $domains) {
$location = gardens_site_data_get_filepath();
$data = [];
foreach ($domains as $domain) {
$domain = trim($domain);
// Below code expects the JSON file to contain newlines such that
// - all data except the 'sites' data and the closing brace are on the first
// line;
// - all data for a key/value pair representing one single site, on a single
// line. (See below for example.)
// This way we can isolate data for one site by performing a grep command,
// which is much quicker than reading all data into one JSON object. The
// code is built to keep working if the formatting changes by accident; it
// will just be much slower. Also, our grep command does not assume that the
// key for a site is included in double quotes (apparently for fear of
// having a file in illegal JSON format, which does not double-quote its
// object keys...) so we may hit false positives.
// Acquia rules disallow exec() with dynamic arguments.
// phpcs:disable
exec(sprintf("grep %s %s --no-filename --color=never --context=0", escapeshellarg($domain), escapeshellarg($location)), $output_array, $exit_code);
// phpcs:enable
$result = trim(implode("\n", $output_array));
if (empty($result)) {
// Log an explicit fail in APC if we cannot find the domain, so that we
// can take advantage of APC caching the "fail" also. Differentiate
// between values for "site not found" and "read failure" so future
// requests can emit different responses for them. (From the docs about
// Gnu grep: exit status is 0 if a line is selected -which should never
// happen here-, 1 if no line is selected, 2 if error encountered.)
if ($exit_code === 1) {
$data[$domain] = 0;
}
}
else {
// $result is in the form of
// "example.com": {"name": "g123", "flags": {}},
// (with or without the trailing comma). Since we didn't include quotes,
// we may have more than 1 line returned from the grep command, typically
// if the searched-for site domain is a substring of another site domain.
// The "m" (multiline) modifier is used in the regular expression so that
// the begin and end anchors can match the beginning and end of any one of
// those lines, rather than having to match the entire string from
// beginning to end (which fails if there is more than 1 line of results).
$matches = [];
$pattern = '@^\\s*"' . preg_quote($domain, '@') . '": ({.+}),?$@m';
if (preg_match($pattern, $result, $matches)) {
$found_site = json_decode($matches[1], TRUE);
}
// Retrieve the first line of the JSON file, which contains the global
// site settings data.
$f = fopen($location, 'r');
$json = fgets($f);
fclose($f);
$json = rtrim($json, ",\n");
$json .= "}";
$global_map_data = json_decode($json, TRUE);
if (empty($found_site) || empty($global_map_data)) {
// This will happen if the domain appears in the JSON file, but the
// format of the file has changed such that the grep-based single-line
// parsing no longer works.
if (class_exists('Drupal') && \Drupal::hasService('logger.factory')) {
\Drupal::logger('acsf')
->alert('Unable to extract site data for site @site from sites.json line "@line".', [
'@site' => $domain,
'@line' => $result,
]);
}
elseif (function_exists('syslog')) {
syslog(LOG_ERR, sprintf('Unable to extract site data for site %s from sites.json line "%s".', $domain, $result));
}
if ($map = gardens_site_data_load_file()) {
if (!empty($map['sites'][$domain])) {
$data[$domain] = gardens_site_data_build_data($map['sites'][$domain], $map);
}
else {
// The domain isn't actually present; apparently $domain is a
// substring of the domain(s) matched by grep. (Or, who knows: the
// string might appear somewhere else on the line than the 'key'.)
$data[$domain] = 0;
}
}
// If $data[$domain] was not set here, the file is readable (or there's
// a race condition and the error just appeared) because we did get a
// line of data returned earlier. So the JSON is invalid.
}
else {
$data[$domain] = gardens_site_data_build_data($found_site, $global_map_data);
}
}
if (isset($data[$domain])) {
// Update the current record in place *if* we are using APC.
if (GARDENS_SITE_DATA_USE_APC) {
gardens_site_data_cache_set($domain, $data[$domain]);
}
}
else {
// Report the read failure, only if Drupal is bootstrapped.
if (function_exists('drupal_register_shutdown_function')) {
// Since reporting involves contacting the Site Factory it should be
// done in a way that does not affect pageload.
drupal_register_shutdown_function('gardens_site_data_json_alert_flag_set');
}
// Stop processing further domains.
break;
}
}
if (count($data) == count($domains)) {
// No read failure encountered; all domains were accounted for / cached.
if (gardens_site_data_json_alert_flag_check() && function_exists('drupal_register_shutdown_function')) {
// Clear the flag. Since it involves contacting the Site Factory it should
// be done in a way that does not affect pageload.
drupal_register_shutdown_function('gardens_site_data_json_alert_flag_clear');
}
}
else {
// If we were checking several domains and any check reported a read failure
// then don't try reading the file again for other domains; cache the failed
// domain plus any that were not processed yet, as "read failure". (It's
// unlikely that we gathered data for some domains before encountering a
// read failure for another one, but account for it.)
if (GARDENS_SITE_DATA_USE_APC) {
foreach ($domains as $domain) {
if (!isset($data[$domain])) {
gardens_site_data_cache_set($domain, NULL);
}
}
}
}
return $data;
}