public function validateValues($variables, $roleId = 0, $farmId = 0, $farmRoleId = 0, $serverId = "")
{
$this->errors = [];
$usedNames = [];
$existedNames = [];
$currentValues = $this->_getValues($roleId, $farmId, $farmRoleId, $serverId);
foreach ($currentValues as $v) {
$existedNames[strtolower($v['name'])] = $v['name'];
}
foreach ($variables as $variable) {
$deleteFlag = isset($variable['flagDelete']) && $variable['flagDelete'] == 1;
$name = $variable['name'];
if (empty($name)) {
continue;
}
$lowerName = strtolower($name);
if (!empty($variable['current'])) {
$variable = $variable['current'];
}
// check for required variable
if (!empty($currentValues[$name]['locked']) && $currentValues[$name]['locked']['flagRequired'] == $this->scope) {
if (!($currentValues[$name]['default']['value'] != '' || isset($variable['value']) && trim($variable['value']) != '')) {
$this->setError($name, 'value', sprintf('%s is required variable', $name));
}
}
$variable['value'] = isset($variable['value']) ? trim($variable['value']) : "";
if ($variable['value'] == '' && isset($currentValues[$name]['default'])) {
$deleteFlag = true;
}
if ($deleteFlag) {
continue;
}
$errorByteMessage = "Variable " . $variable['name'] . " contains invalid non-printable characters (e.g. NULL characters).\n You might have copied it from another application that submitted invalid characters.\n To solve this issue, you can type in the variable manually.";
if (strpos($variable['value'], chr(0)) !== false) {
$this->setError($name, 'value', $errorByteMessage);
}
if (!preg_match('/^[A-Za-z]{1,1}[A-Za-z0-9_]{1,127}$/', $name)) {
$this->setError($name, 'name', "Name should contain only letters, numbers and underscores, start with letter and be from 2 to 128 chars long.");
} else {
if (in_array($name, $usedNames)) {
$this->setError($name, 'name', "This variable name is already in use.");
} else {
$usedNames[] = $lowerName;
}
}
if (array_key_exists($lowerName, $existedNames) && $existedNames[$lowerName] != $name) {
if ($this->doNotValidateNameCaseSensitivity) {
\Scalr::getContainer()->logger(\LOG_CATEGORY::FARM)->warn(new \FarmLogMessage(!empty($farmId) ? $farmId : null, sprintf('Variable "%s" has been already defined as "%s"', !empty($name) ? $name : null, !empty($existedNames[$lowerName]) ? $existedNames[$lowerName] : null), !empty($serverId) ? $serverId : null, null, !empty($farmRoleId) ? $farmRoleId : null));
} else {
$this->setError($name, 'name', sprintf("Name has been already defined as \"%s\"", $existedNames[$lowerName]));
}
}
if (substr($lowerName, 0, 6) == 'scalr_' && !array_key_exists($lowerName, $existedNames) && !array_key_exists($name, $this->configurationVars) || array_key_exists($name, $this->configurationVars) && !in_array($this->scope, [ScopeInterface::SCOPE_SCALR, ScopeInterface::SCOPE_ACCOUNT, ScopeInterface::SCOPE_ENVIRONMENT])) {
$this->setError($name, 'name', "Prefix 'SCALR_' is reserved and cannot be used for user GVs");
}
if (array_key_exists($name, $this->configurationVars) && empty($currentValues[$name]['default'])) {
$variable = array_merge($variable, $this->configurationVarsDefaults, $this->configurationVars[$name]);
}
// set advanced flags only on first level
if (!empty($currentValues[$name]['default'])) {
$msg = "You can't redefine advanced settings (flags, format, validator, category)";
if (!empty($variable['flagRequired'])) {
$this->setError($name, 'flagRequired', $msg);
}
if (!empty($variable['flagFinal']) && $variable['flagFinal'] == 1) {
$this->setError($name, 'flagFinal', $msg);
}
if (!empty($variable['flagHidden']) && $variable['flagHidden'] == 1) {
$this->setError($name, 'flagHidden', $msg);
}
if (!empty($variable['format'])) {
$this->setError($name, 'format', $msg);
}
if (!empty($variable['validator'])) {
$this->setError($name, 'validator', $msg);
}
if (!empty($variable['category'])) {
$this->setError($name, 'category', $msg);
}
} else {
if (!empty($variable['flagRequired'])) {
if ($this->scope == ScopeInterface::SCOPE_FARMROLE || $this->scope == ScopeInterface::SCOPE_SERVER) {
$this->setError($name, 'flagRequired', "You can't set required flag on farmrole or server level");
} else {
$sc = $this->listScopes;
array_pop($sc);
// exclude SERVER scope
$sc = array_slice($sc, array_search($this->scope, $sc) + 1);
if (!in_array($variable['flagRequired'], $sc)) {
$this->setError($name, 'flagRequired', 'Wrong required scope');
}
}
}
if (!empty($variable['flagFinal']) && $variable['flagFinal'] == 1 && !empty($variable['flagRequired'])) {
$this->setError($name, 'flagFinal', "You can't set final and required flags both");
$this->setError($name, 'flagRequired', "You can't set final and required flags both");
}
if (!empty($variable['validator'])) {
if (strpos($variable['validator'], chr(0)) !== false) {
$this->setError($name, 'validator', "Validation pattern is not valid (NULL byte)");
} else {
$this->errorHandlerLastError = '';
if (preg_match('/^\\/(.*)\\/[imsxADSUXu]*$/', $variable['validator']) == 1) {
set_error_handler([$this, 'errorHandler']);
preg_match($variable['validator'], 'test');
restore_error_handler();
} else {
$this->errorHandlerLastError = 'invalid structure';
}
if ($this->errorHandlerLastError) {
$this->setError($name, 'validator', sprintf("Validation pattern is not valid: %s", $this->errorHandlerLastError));
} else {
if ($variable['value'] != '') {
if (preg_match($variable['validator'], $variable['value']) != 1) {
$this->setError($name, 'value', "Value isn't valid because of validation pattern");
}
}
}
}
}
if (!empty($variable['format'])) {
if ($variable['format'] == self::FORMAT_JSON) {
json_decode($variable['value']);
if (json_last_error() !== JSON_ERROR_NONE) {
$this->setError($name, 'value', "The value is not valid JSON");
}
} else {
$cnt = count_chars($variable['format']);
if ($cnt[ord('%')] != 1) {
$this->setError($name, 'format', "Format isn't valid");
}
}
}
if (!empty($variable['category'])) {
if (preg_match('/^[A-Za-z0-9]+[A-Za-z0-9-_]*[A-Za-z0-9]+$/i', $variable['category']) != 1 || strlen($variable['category']) > 31) {
$this->setError($name, 'category', "Category should contain only letters, numbers, dashes and underscores, start and end with letter and be from 2 to 32 chars long");
}
if (substr(strtolower($variable['category']), 0, 6) == 'scalr_' && !array_key_exists($name, $this->configurationVars)) {
$this->setError($name, 'category', "Prefix 'SCALR_' is reserved and cannot be used for user GVs");
}
}
}
if (!empty($currentValues[$name]['locked'])) {
if ($currentValues[$name]['locked']['flagFinal'] && $variable['value'] != '') {
$this->setError($name, 'value', sprintf('You can\'t change final variable locked on %s level', $currentValues[$name]['locked']['scope']));
}
if ($currentValues[$name]['locked']['validator'] && $variable['value'] != '') {
$validator = $currentValues[$name]['locked']['validator'];
if (preg_match($validator, $variable['value']) != 1) {
$this->setError($name, 'value', "Value isn't valid because of validation pattern");
}
}
if ($currentValues[$name]['locked']['format'] == self::FORMAT_JSON) {
json_decode($variable['value']);
if (json_last_error() !== JSON_ERROR_NONE) {
$this->setError($name, 'value', "The value is not valid JSON");
}
}
}
}
return count($this->errors) ? $this->errors : true;
}