diff options
Diffstat (limited to 'inc/property.inc.php')
-rw-r--r-- | inc/property.inc.php | 159 |
1 files changed, 104 insertions, 55 deletions
diff --git a/inc/property.inc.php b/inc/property.inc.php index 3911b0d4..aaf03254 100644 --- a/inc/property.inc.php +++ b/inc/property.inc.php @@ -1,5 +1,7 @@ <?php +declare(strict_types=1); + /** * Get or set simple key-value-pairs, backed by the database * to make them persistent. @@ -16,12 +18,13 @@ class Property * @param mixed $default value to return if $key does not exist in the property store * @return mixed the value attached to $key, or $default if $key does not exist */ - public static function get($key, $default = false) + public static function get(string $key, $default = false) { if (self::$cache === false) { + self::$cache = []; $NOW = time(); $res = Database::simpleQuery("SELECT name, dateline, value FROM property"); - while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + foreach ($res as $row) { if ($row['dateline'] != 0 && $row['dateline'] < $NOW) continue; self::$cache[$row['name']] = $row['value']; @@ -33,24 +36,30 @@ class Property } /** - * Set value in property store. + * Set value in property store. Passing null or false as the value deletes the + * entry from the property table. * * @param string $key key of value to set - * @param string $value the value to store for $key + * @param string|null|false $value the value to store for $key * @param int $maxAgeMinutes how long to keep this entry around at least, in minutes. 0 for infinite */ - public static function set($key, $value, $maxAgeMinutes = 0) + public static function set(string $key, $value, int $maxAgeMinutes = 0): void { - if (self::$cache === false || self::get($key) != $value) { // Simple compare, so it works for numbers accidentally casted to string somewhere + if ($value === false || $value === null) { + Database::exec("DELETE FROM property WHERE name = :key", ['key' => $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)", array( + . " 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; + ]); + if (self::$cache !== false) { + self::$cache[$key] = $value; + } } } @@ -60,33 +69,76 @@ class Property * @param string $key Key of list to get all items for * @return array All the items matching the key */ - public static function getList($key) + public static function getList(string $key): array { - $res = Database::simpleQuery("SELECT dateline, value FROM property_list WHERE name = :key", compact('key')); + $res = Database::simpleQuery("SELECT subkey, dateline, value FROM property_list + WHERE `name` = :key", compact('key')); $NOW = time(); - $return = array(); - while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + $return = []; + foreach ($res as $row) { if ($row['dateline'] != 0 && $row['dateline'] < $NOW) continue; - $return[] = $row['value']; + $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($key, $value, $maxAgeMinutes = 0) + 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; } /** @@ -97,7 +149,7 @@ class Property * @param string $value item to remove * @return int number of items removed */ - public static function removeFromList($key, $value) + 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, @@ -106,12 +158,28 @@ class Property } /** + * 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($key) + public static function clearList(string $key): int { return Database::exec("DELETE FROM property_list WHERE name = :key", compact('key')); } @@ -120,12 +188,12 @@ class Property * Legacy getters/setters */ - public static function getServerIp() + public static function getServerIp(): string { - return self::get('server-ip', 'none'); + return self::get('server-ip', 'invalid'); } - public static function setServerIp($value, $automatic = false) + public static function setServerIp(string $value, bool $automatic = false): bool { if ($value === self::getServerIp()) return false; @@ -135,19 +203,15 @@ class Property return true; } - public static function getBootMenu() - { - return json_decode(self::get('ipxe-menu'), true); - } - - public static function setBootMenu($value) - { - self::set('ipxe-menu', json_encode($value)); - } - - public static function getVmStoreConfig() + public static function getVmStoreConfig(): array { - return json_decode(self::get('vmstore-config'), true); + $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() @@ -169,21 +233,6 @@ class Property self::set('vmstore-config', json_encode($value)); } - public static function getDownloadTask($name) - { - return self::get('dl-' . $name); - } - - public static function setDownloadTask($name, $taskId) - { - self::set('dl-' . $name, $taskId, 5); - } - - public static function getCurrentSchemaVersion() - { - return self::get('webif-version'); - } - public static function setLastWarningId($id) { self::set('last-warn-event-id', $id); @@ -194,22 +243,22 @@ class Property return self::get('last-warn-event-id', 0); } - public static function setNeedsSetup($value) + public static function setNeedsSetup(bool $value) { - self::set('needs-setup', $value); + self::set('needs-setup', (int)$value); } - public static function getNeedsSetup() + public static function getNeedsSetup(): bool { - return self::get('needs-setup'); + return self::get('needs-setup') != 0; } - public static function setPasswordFieldType($value) + public static function setPasswordFieldType(string $value) { self::set('password-type', $value); } - public static function getPasswordFieldType() + public static function getPasswordFieldType(): string { return self::get('password-type', 'password'); } |