$key]); if (self::$cache !== false) { unset(self::$cache[$key]); } } else { Database::exec("INSERT INTO property (name, value, dateline) VALUES (:key, :value, :dateline)" . " ON DUPLICATE KEY UPDATE value = VALUES(value), dateline = VALUES(dateline)", [ 'key' => $key, 'value' => $value, 'dateline' => ($maxAgeMinutes === 0 ? 0 : time() + ($maxAgeMinutes * 60)) ]); if (self::$cache !== false) { self::$cache[$key] = $value; } } } /** * Retrieve property list from the store. * * @param string $key Key of list to get all items for * @return array All the items matching the key */ public static function getList(string $key): array { $res = Database::simpleQuery("SELECT subkey, dateline, value FROM property_list WHERE `name` = :key", compact('key')); $NOW = time(); $return = []; foreach ($res as $row) { if ($row['dateline'] != 0 && $row['dateline'] < $NOW) continue; $return[$row['subkey']] = $row['value']; } return $return; } /** * @return ?string entry from property list */ public static function getListEntry(string $key, int $subkey): ?string { $row = Database::queryFirst("SELECT dateline, `value` FROM property_list WHERE `name` = :key AND subkey = :subkey", ['key' => $key, 'subkey' => $subkey]); if ($row === false || ($row['dateline'] != 0 && $row['dateline'] < time())) return null; return $row['value']; } /** * Add item to property list. * * @param string $key key of value to set * @param string $value the value to add for $key * @param int $maxAgeMinutes how long to keep this entry around at least, in minutes. 0 for infinite * @return int The auto generated sub-key */ public static function addToList(string $key, string $value, int $maxAgeMinutes = 0): int { Database::exec("INSERT INTO property_list (name, value, dateline) VALUES (:key, :value, :dateline)", array( 'key' => $key, 'value' => $value, 'dateline' => ($maxAgeMinutes === 0 ? 0 : time() + ($maxAgeMinutes * 60)) )); return Database::lastInsertId(); } /** * Update existing entry in property list. * * @param string $key key of list * @param int $subkey subkey of entry in list * @param string $value new value to set entry to * @param int $maxAgeMinutes the new lifetime of that entry * @param ?string $expectedValue if not null, the value will only be updated if it currently has this value * @return bool whether the entry existed and has been updated */ public static function updateListEntry(string $key, int $subkey, string $value, int $maxAgeMinutes = 0, string $expectedValue = null): bool { $args = [ 'name' => $key, 'subkey' => $subkey, 'newvalue' => $value, 'dateline' => ($maxAgeMinutes === 0 ? 0 : time() + ($maxAgeMinutes * 60)), ]; if ($expectedValue !== null) { $args['oldvalue'] = $expectedValue; return Database::exec("UPDATE property_list SET `value` = :newvalue, dateline = :dateline WHERE `name` = :name AND subkey = :subkey AND `value` = :oldvalue", $args) > 0; } return Database::exec("UPDATE property_list SET `value` = :newvalue, dateline = :dateline WHERE `name` = :name AND subkey = :subkey", $args) > 0; } /** * Remove given item from property list. If the list contains this item * multiple times, they will all be removed. * * @param string $key Key of list * @param string $value item to remove * @return int number of items removed */ public static function removeFromListByVal(string $key, string $value): int { return Database::exec("DELETE FROM property_list WHERE name = :key AND value = :value", array( 'key' => $key, 'value' => $value, )); } /** * Remove given item from property list. If the list contains this item * multiple times, they will all be removed. * * @param string $key Key of list * @param int $value item to remove * @return bool whether item was found and removed */ public static function removeFromListByKey(string $key, int $subkey): bool { return Database::exec("DELETE FROM property_list WHERE name = :key AND subkey = :subkey", array( 'key' => $key, 'subkey' => $subkey, )) > 0; } /** * Delete entire list with given key. * * @param string $key Key of list * @return int number of items removed */ public static function clearList(string $key): int { return Database::exec("DELETE FROM property_list WHERE name = :key", compact('key')); } /* * Legacy getters/setters */ public static function getServerIp(): string { return self::get('server-ip', 'invalid'); } public static function setServerIp(string $value, bool $automatic = false): bool { if ($value === self::getServerIp()) return false; EventLog::info('Server IP changed from ' . self::getServerIp() . ' to ' . $value . ($automatic ? ' (auto detected)' : '')); self::set('server-ip', $value); Event::serverIpChanged(); return true; } public static function getVmStoreConfig(): array { $data = self::get('vmstore-config'); if (!is_string($data)) return []; $data = json_decode($data, true); if (!is_array($data)) return []; return $data; } public static function getVmStoreUrl() { $store = self::getVmStoreConfig(); if (!isset($store['storetype'])) return false; if ($store['storetype'] === 'nfs') return $store['nfsaddr']; if ($store['storetype'] === 'cifs') return $store['cifsaddr']; if ($store['storetype'] === 'internal') return ''; return ''; } public static function setVmStoreConfig($value) { self::set('vmstore-config', json_encode($value)); } public static function setLastWarningId($id) { self::set('last-warn-event-id', $id); } public static function getLastWarningId() { return self::get('last-warn-event-id', 0); } public static function setNeedsSetup(bool $value) { self::set('needs-setup', (int)$value); } public static function getNeedsSetup(): bool { return self::get('needs-setup') != 0; } public static function setPasswordFieldType(string $value) { self::set('password-type', $value); } public static function getPasswordFieldType(): string { return self::get('password-type', 'password'); } }