<?php //============================================================================ // Name : keyLib.php // Author : Patrick Reipschläger, Lucas Woltmann // Version : 2.0 // Date : 01-2017 // Description : Provides several functions for creating and handling keys // for the ESE evaluation for students and tutors. //============================================================================ // Constant for the file which contains the keys, should be used by all other scripts so it can easily be changed define ("KEYFILE", "db/eseeva.db"); // Constants for the different key states that are possible, should always be used when altering or checking the state of a key define ("KEYSTATE_NONEXISTENT", "nonexistent"); define ("KEYSTATE_UNISSUED", "unissued"); define ("KEYSTATE_ISSUED", "issued"); define ("KEYSTATE_ACTIVATED", "activated"); define ("KEYSTATE_USED", "used"); /** * Generates a key from the specified hash value. * * @return string */ function GenerateKey() { // create a hash using a unique id based on the servers system time and the sha1 hashing algorithm $hash = strtoupper(hash("sha1", uniqid())); // extract the desired number of digits out of the hash to generate the key return substr($hash, 0, 4) . "-" . substr($hash, 4, 4) . "-" . substr($hash, 8, 4) . "-" . substr($hash, 12, 4); //return substr($hash, 0, 2) . "-" . substr($hash, 2, 2) . "-" . substr($hash, 4, 2) . "-" . substr($hash, 6, 2); } /** * Generates the specified amount of keys. Be aware that this function just * creates an array of keys with no state assigned. * * @param integer $amount The amount of keys that should be generated * @return array */ function GenerateKeys($amount) { $keys = array(); for ($i = 0; $i < $amount; $i++) { array_push($keys, GenerateKey()); usleep(1); } return array_unique($keys); } /** * Generates a new keys in the database. * Returns true if the key file was created successfully, otherwise false. * * @param integer $keyAmount The amount of keys that should be generated. * @param string $fileName The name of the key database that should be created. */ function CreateKeys($keyAmount, $fileName) { $handle = new SQLite3($fileName); if (!$handle) return false; $handle->exec("DROP TABLE IF EXISTS answers;"); $handle->exec("CREATE TABLE IF NOT EXISTS 'answers'(KeyId text primary key,Status text,Student int,Answer);"); $keys = GenerateKeys($keyAmount); $count = count($keys); for ($i = 0; $i < $count; $i++) { $stmt = $handle->prepare("INSERT INTO answers (KeyId, Status) VALUES (:key,:status);"); if ($stmt) { $stmt->bindValue(':key', $keys[$i], SQLITE3_TEXT); $stmt->bindValue(':status', KEYSTATE_UNISSUED, SQLITE3_TEXT); $result = $stmt->execute(); } else { $handle->close(); return false; } } $handle->close(); return true; } function AppendKeys($keyAmount, $fileName) { $handle = new SQLite3($fileName, SQLITE3_OPEN_READWRITE); if (!$handle) return false; $keys = GenerateKeys($keyAmount); $count = count($keys); for ($i = 0; $i < $count; $i++) { $stmt = $handle->prepare("INSERT INTO answers (KeyId, Status) VALUES (:key,:status);"); if ($stmt) { $stmt->bindValue(':key', $keys[$i], SQLITE3_TEXT); $stmt->bindValue(':status', KEYSTATE_UNISSUED, SQLITE3_TEXT); $result = $stmt->execute(); } else { $handle->close(); return false; } } $handle->close(); return true; } /** * Opens the database with the specified name and reads all key data that the database contains. * The resulting data type will be an array of arrays consisting of the key and its state. * Returns null if the key file could not be found or read. * * @param string $fileName The database which should be read. * @return array */ function ReadKeys($fileName) { if (!file_exists($fileName)) return null; $handle = new SQLite3($fileName, SQLITE3_OPEN_READONLY); if (!$handle) return null; $data = $handle->query("SELECT KeyId, Status FROM answers;"); $data = PrepareResult($data); $handle->close(); if ($data) { return $data; } return array(); } /** * Get the current state of the specified key from the database, which will be one of the defines * KEYSTATE constants. * * @param array $fileName The database with the keys. * @param string $key The key which state should be got. Passed by reference. * @return integer */ function GetKeyState($fileName, &$key) { if (!file_exists($fileName)) return null; $handle = new SQLite3($fileName, SQLITE3_OPEN_READONLY); if (!$handle) return null; $stmt = $handle->prepare("SELECT Status FROM answers WHERE KeyId=:keyid;"); if ($stmt) { $stmt->bindValue(':keyid', $key, SQLITE3_TEXT); $result = $stmt->execute(); $result = $result->fetchArray(SQLITE3_ASSOC); $handle->close(); return $result["Status"]; } $handle->close(); return KEYSTATE_NONEXISTENT; } /** * Set the state of the specified key to the specified state. * Returns true if the key was found within the key data and the state has been changed, otherwise false. * * @param array $fileName The database in which the key should be found. * @param string $key The key which state should be changed. * @param integer $newState The new state of the specified key. Must be on of the KEYSTATE constants. * @return boolean */ function SetKeyState($fileName, &$key, $newState) { if (!file_exists($fileName)) return false; $handle = new SQLite3($fileName, SQLITE3_OPEN_READWRITE); if (!$handle) return false; //secure override by checking if key has been uesed already $stmt = $handle->prepare("UPDATE answers SET Status=:status WHERE KeyId=:keyid AND Status!=:status;"); if ($stmt) { $stmt->bindValue(':keyid', $key, SQLITE3_TEXT); $stmt->bindValue(':status', $newState, SQLITE3_TEXT); $result = $stmt->execute(); $handle->close(); return true; } $handle->close(); return false; } /** * Deletes a single key in the database if it has not been used yet. * Returns true if the key was deleted, otherwise false. * * @param array $fileName The database in which the key should be found. * @param string $key The key which should be deleted. * @return boolean */ function DeleteKey($fileName, &$key) { if (!file_exists($fileName)) return false; $handle = new SQLite3($fileName, SQLITE3_OPEN_READWRITE); if (!$handle) return false; //secure deleting by checking if key has been uesed already $stmt = $handle->prepare("DELETE FROM answers WHERE KeyId=:keyid AND Answer IS NULL;"); if ($stmt) { $stmt->bindValue(':keyid', $key, SQLITE3_TEXT); $result = $stmt->execute(); $handle->close(); return true; } $handle->close(); return false; } /** * Prepares the results from the database to an array of keys with their state. * * @param array $resultSet Cursor from the sqlite database. Passed by reference. * @return array */ function PrepareResult(&$resultSet) { $result = array(); $i = 0; while($res = $resultSet->fetchArray(SQLITE3_ASSOC)) { foreach ($res as $key => $value) { $result[$i][$key] = $value; } $i++; } return $result; } ?>