diff --git a/analysis.php b/analysis.php index 83d679c..32d5fc9 100755 --- a/analysis.php +++ b/analysis.php @@ -2,30 +2,28 @@ //============================================================================ // Name : analysis.php // Author : Patrick Reipschläger, Lucas Woltmann -// Version : 0.5 -// Date : 08-2013 +// Version : 1.0 +// Date : 01-2017 // Description : Analysis a ESE Evaluation log file. The file that is analysed // may be passed as parameter with the URL. //============================================================================ include_once 'libs/formLib.php'; include_once 'libs/questionnaireLib.php'; - include_once 'libs/loggingLib.php'; + include_once 'libs/dbLib.php'; include_once 'libs/chartLib.php'; // variables for the log data $questionData; $tutorData; $commentData; - // Default log file is the student log file defined in 'loggingLib.php' - $logFile = STUDENTLOGFILE; + // Default log file is the student log file defined in 'dbLib.php' + $logFile = LOGDB; // if a logFile parameter has been passed in the URL, than that value will // be used instead of the default value (with the added folder name) if (isset($_GET["logFile"])) - $logFile = "logs/" . $_GET["logFile"]; - // read the existing log file, if there is no existing log file, the RadLogFile - // function guarantees the initialization of the log variables, which will - // result in the same outcome as if an empty log file is read - ReadLogFile($logFile, $questionData, $tutorData, $commentData); + $logFile = "db/" . $_GET["logFile"]; + // read the database + ReadLogDatabase($logFile, 1, $questionData, $tutorData, $commentData); ?> diff --git a/analysisTut.php b/analysisTut.php index e5d958f..1834435 100644 --- a/analysisTut.php +++ b/analysisTut.php @@ -2,30 +2,28 @@ //============================================================================ // Name : analysisTut.php // Author : Patrick Reipschläger, Lucas Woltmann -// Version : 0.5 -// Date : 08-2013 +// Version : 1.0 +// Date : 01-2017 // Description : Analysis a ESE Evaluation tutor log file. The file that is analysed // may be passed as parameter with the URL. //============================================================================ include_once 'libs/formLib.php'; include_once 'libs/questionnaireLib.php'; - include_once 'libs/loggingLib.php'; + include_once 'libs/dbLib.php'; include_once 'libs/chartLib.php'; // variables for the log data $questionData; $tutorData; $commentData; - // Default log file is the student log file defined in 'loggingLib.php' - $logFile = TUTORLOGFILE; + // Default log file is the student log file defined in 'dbLib.php' + $logFile = LOGDB; // if a logFile parameter has been passed in the URL, than that value will // be used instead of the default value (with the added folder name) if (isset($_GET["logFile"])) - $logFile = "logs/" . $_GET["logFile"]; - // read the existing log file, if there is no existing log file, the RadLogFile - // function guarantees the initialization of the log variables, which will - // result in the same outcome as if an empty log file is read - ReadLogFile($logFile, $questionData, $tutorData, $commentData); + $logFile = "db/" . $_GET["logFile"]; + // read the database + ReadLogDatabase($logFile, 0, $questionData, $tutorData, $commentData); ?> diff --git a/db/schema.sql b/db/schema.sql new file mode 100644 index 0000000..d431c81 --- /dev/null +++ b/db/schema.sql @@ -0,0 +1,7 @@ +CREATE TABLE 'answers' +( + KeyId text primary key, + Status text, + Student int, + Answer +); diff --git a/keyTable.php b/keyTable.php index 1a43632..e6d3db3 100755 --- a/keyTable.php +++ b/keyTable.php @@ -1,22 +1,22 @@ 0) - { - $key = GenerateKey(); - $duplicate = false; - foreach($keyData as $entry) - if ($entry[0] == $key) - { - $duplicate = true; - break; - } - if ($duplicate) - continue; - array_push($keyData, array($key, KEYSTATE_UNISSUED)); - $amount--; - } - WriteKeyFile($keyFile, $keyData); + CreateKeys($amount, $keyFile); + $keyData = ReadKeys($keyFile); } else - $keyData = ReadKeyFile($keyFile); + $keyData = ReadKeys($keyFile); } // if the page was refreshed by the user, just load the key file else - $keyData = ReadKeyFile($keyFile); + $keyData = ReadKeys($keyFile); // generate a new submission id that is used within the form to prevent double posts $_SESSION["submissionId"] = rand(); ?> @@ -109,15 +98,15 @@ echo " \n"; echo "
\n"; - echo " \n"; + echo " \n"; echo "
\n"; echo "
\n"; echo " "; echo "
\n"; diff --git a/libs/dbLib.php b/libs/dbLib.php new file mode 100644 index 0000000..89b64ce --- /dev/null +++ b/libs/dbLib.php @@ -0,0 +1,302 @@ +prepare("SELECT Answer FROM answers WHERE student=:student;"); + if ($stmt) + { + $stmt->bindValue(':student', $student, SQLITE3_INTEGER); + + $result = $stmt->execute(); + //read to ararys, commentData does not need any further attention + PrepareAnswer($result, $questions, $tutors, $commentData); + } + else + { + $handle->close(); + return false; + } + + $handle->close(); + + //convert data into legacy data structure + ReadLogQuestionData($questions, $questionData); + ReadLogTutorData($tutors, $tutorData); + return true; + } + /** + * Writes the specified log arrays to a database with the specified name. + * Expects data in the same format as in the legacy version, but combines them to a single array + * which is going to be saved in the database. + * Returns true if the file was written successfully, otherwise false. + * + * @param string $fileName The name of the database to which the log data should be written. + * @param int $student Whether the user is a student(1) or a tutor(0). + * @param array $questionData The question data that should be written to the log file. Passed by reference. + * @param array $tutorData The tutor data that should be written to the log file. Passed by reference. + * @param array $commentData The list of comments that should be written to the log file. Passed by reference. + * @param string $key The key the user used. + * @return boolean + */ + function WriteLogDatabase($fileName, $student, &$questionData, &$tutorData, &$commentData, $key) + { + $answer = array($questionData, $tutorData, $commentData); + $handle = new SQLite3($fileName, SQLITE3_OPEN_READWRITE); + if (!$handle) + return false; + + $stmt = $handle->prepare("UPDATE answers SET Status='activated', Student=:student, Answer=:answer WHERE KeyId=:keyid;"); + if ($stmt) + { + $stmt->bindValue(':student', $student, SQLITE3_INTEGER); + $stmt->bindValue(':answer', serialize($answer), SQLITE3_BLOB); + $stmt->bindValue(':keyid', $key, SQLITE3_TEXT); + + $result = $stmt->execute(); + } + else + { + $handle->close(); + return false; + } + + $handle->close(); + return true; + } + /** + * Legacy data management for the question data. + * Generates an array of arrays with all the questions. + * The first index of each subarray is the full title and the remaining indices are the votes (answers). + * + * @param array $formData $_POST reference. Passed by reference. + * @param array $questionData The array data that should be written to. Passed by reference. + * @param array $questionnaire The general structure (questions) of the questionnaire. Passed by reference. + */ + function AddQuestionData(&$formData, &$questionData, &$questionnaire) + { + foreach($formData as $id => $value) + { + if (!isset($questionnaire[$id])) + continue; + // get the type of the element with the same id as the form element from the questionnaire + $type = $questionnaire[$id][0]; + // check if the element is a question on continue with the next one if that is not the case + if ($type != "Question") + continue; + // if there is not field for the current element in the question dsta array, create a new + // blank field containing the question and zeros for the number of times each answer was picked + if (array_key_exists($id, $questionData) == false) + $questionData[$id] = array($questionnaire[$id][1], 0, 0, 0, 0, 0, 0); + // increment the answer that was selected in the formular by one + $questionData[$id][(int)$value]++; + } + } + /** + * Legacy data management for the tutor data. + * Generates an array of arrays with the tutor. + * The first index of each subarray is the full name and the remaining indices are the votes (answers). + * + * @param array $formData $_POST reference. Passed by reference. + * @param array $tutorData The array data that should be written to. Passed by reference. + */ + function AddTutorData(&$formData, &$tutorData) + { + // get the name of the tutor from the form + $tutorName = $formData["tutorName"]; + // get the selected answer of the tutorRating from the form + $tutorValue = $formData["tutorRating"]; + // if there is no field for the current tutor in the tutor array, create a new + // nlank one with zeros for the number of times each answer was picked + if (array_key_exists($tutorName, $tutorData) == false) + $tutorData[$tutorName] = array(0, 0, 0, 0, 0, 0); + // increment the answer that was selected in the form by one + $tutorData[$tutorName][$tutorValue - 1]++; + } + /** + * Legacy data management for the comment data. + * Checks if a comment was left and writes it into the passed reference. + * + * @param array $formData $_POST reference. Passed by reference. + * @param string $commentData The array data that should be written to. Passed by reference. + */ + function AddCommentData(&$formData, &$commentData) + { + // if the comment field was filled, the comment + // array is appended by the new comment + if (trim($formData["comment"]) != "") + { + $commentData = $formData["comment"]; + } + } + /** + * Reads all question data out of a provided log file array from the database. + * This function should NOT BE CALLED directly, instead the ReadLogDatabase function should be + * used to read a log file as a whole. + * All data is written to the specified question data array and + * True is returned if a valid question data block was found, otherwise false. + * + * @param array $questions An array from the database. Passed by reference. + * @param array $questionData An array to which all question data is written to. Passed by reference. + * @return boolean. + */ + function ReadLogQuestionData(&$questions, &$questionData) + { + foreach ((array)$questions as $user) { + foreach ($user as $id => $values) { + if (isset($questionData[$id])) + { + $questionData[$id] = SumArrays($values, $questionData[$id]); + } + else + { + $questionData[$id] = $values; + } + } + } + return true; + } + /** + * Reads all tutor data out of a provided log file array from the database. + * This function should NOT BE CALLED directly, instead the ReadLogDatabase function should be + * used to read a log file as a whole. + * All data is written to the specified question data array and + * True is returned if a valid tutor data block was found, otherwise false. + * + * @param array $tutors An array from the database. Passed by reference. + * @param array $tutorData An array to which all question data is written to. Passed by reference. + * @return boolean. + */ + function ReadLogTutorData(&$tutors, &$tutorData) + { + foreach ((array)$tutors as $user) { + foreach ($user as $id => $values) { + if (isset($tutorData[$id])) + { + $tutorData[$id] = SumArrays($values, $tutorData[$id]); + } + else + { + $tutorData[$id] = $values; + } + } + } + return true; + } + /** + * Reads all comment data out of a provided log file array from the database. + * This function should NOT BE CALLED directly, instead the ReadLogDatabase function should be + * used to read a log file as a whole. + * All data is written to the specified question data array and + * True is returned if a valid comment data block was found, otherwise false. + * + * @param array $comments An array from the database. Passed by reference. + * @param array $commentData An array to which all question data is written to. Passed by reference. + * @return boolean. + */ + function ReadLogCommentData(&$comments, &$commentData) + { + foreach ((array)$comments as $user) { + foreach ($user as $id => $values) { + if (isset($commentData[$id])) + { + $commentData[$id] = SumArrays($values, $commentData[$id]); + } + else + { + $commentData[$id] = $values; + } + } + } + return true; + } + /** + * Splits the three arrays from the 'Answer' column in the database into the legacy ararys. + * + * @param array $resultSet An array from the database. Passed by reference. + * @param array $questionsa An array to which all question data is written to. Passed by reference. + * @param array $tutors An array to which all tutor data is written to. Passed by reference. + * @param array $comments An array to which all comments data is written to. Passed by reference. + */ + function PrepareAnswer(&$resultSet, &$questions, &$tutors, &$comments) + { + $i = 0; + + while($res = $resultSet->fetchArray(SQLITE3_ASSOC)) + { + $res = unserialize($res["Answer"]); + $questions[$i] = $res[0]; + $tutors[$i] = $res[1]; + $comments[$i] = $res[2]; + $i++; + } + } + /** + * Little helper function for adding up single user answers to a global statistic. + * Could be compared with a group by. + * + * @param array $array1 First array to merge/sum. + * @param array $array2 Second array to merge/sum. + * @return array Summed array by index. + */ + function SumArrays(&$array1, &$array2) + { + $result = array(); + //the name + $result[0] = $array2[0]; + $count = count($array2); + + //start one index into counting, because index 0 is the name + for ($i=1; $i < $count; $i++) { + $result[$i] = $array1[$i] + $array2[$i]; + } + + return $result; + } +?> diff --git a/libs/keyLib.php b/libs/keyLib.php index 113db0e..74386b6 100755 --- a/libs/keyLib.php +++ b/libs/keyLib.php @@ -1,15 +1,15 @@ 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 file with the specified name and reads all key data that the file contains. + * 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 file which should be read + * @param string $fileName The database which should be read. * @return array */ - function ReadKeyFile($fileName) + function ReadKeys($fileName) { if (!file_exists($fileName)) return null; - $handle = fopen($fileName, 'r'); + $handle = new SQLite3($fileName, SQLITE3_OPEN_READONLY); if (!$handle) return null; - $data = fread($handle, filesize($fileName)); - $lines = explode("\n", $data); - fclose($handle); - $keyData = array(); - for ($i = 1; $i < count($lines); $i++) - { - $tmp = explode(";", $lines[$i]); - array_push($keyData, array($tmp[1], $tmp[2])); - } - return $keyData; - } - /** - * Writes the specified key data to the file with the specified name. - * The data type of the $keyData should be an array of arrays consisting of the key and its state. - * Returns true if the key file was successfully written, otherwise false. - * - * @param string $fileName The name of the file to which the key data should be written. - * @param array $keyData The key data which should be written to the file. Passed by reference. - * @return boolean - */ - function WriteKeyFile($fileName, &$keyData) - { - if (!isset($fileName) || !isset($keyData)) - return false; - $handle = fopen($fileName, 'c'); - if ($handle == null) - return false; - // debug code - //echo ""; - $data = "Nr;Key;Status\n"; - $count = count($keyData) - 1; - for ($i = 0; $i < $count; $i++) - $data = $data . $i . ";" . $keyData[$i][0] . ";" . $keyData[$i][1] . "\n"; - $data = $data . $count . ";" . $keyData[$count][0] . ";" . $keyData[$count][1]; + $data = $handle->query("SELECT KeyId, Status FROM answers;"); + $data = PrepareResult($data); + $handle->close(); - //use exclusive lock for writing - flock($handle, LOCK_EX); - ftruncate($handle, 0); - $res = fwrite($handle, $data); - fflush($handle); - flock($handle, LOCK_UN); - // debug Code - //if ($res == false) - // echo ""; - //else - // echo ""; - fclose($handle); - if ($res) + if ($data) { - return true; - } - else - { - return false; + return $data; } + + return array(); } /** - * Get the current state of the specified key which will be one of the defines + * Get the current state of the specified key from the database, which will be one of the defines * KEYSTATE constants. - * The data type of the key data should be an array of arrays consisting of the key and its state. * - * @param array $keyData The key data array in which the key should be found. Passed by reference. + * @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(&$keyData, &$key) + function GetKeyState($fileName, &$key) { - for ($i = 0; $i < count($keyData); $i++) - if ($key == $keyData[$i][0]) - return $keyData[$i][1]; + 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. - * The data type of the $keyData should be an array of arrays consisting of the key and its state. * Returns true if the key was found within the key data and the state has been changed, otherwise false. * - * @param array $keyData The key data array in which the key should be found. Passed by reference. + * @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(&$keyData, &$key, $newState) + 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) { - for ($i = 0; $i < count($keyData); $i++) - if ($key == $keyData[$i][0]) - { - $keyData[$i][1] = $newState; - return true; + 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!=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; } - return false; + $i++; + } + + return $result; } ?> diff --git a/libs/loggingLib.php b/libs/loggingLib.php deleted file mode 100755 index 4a4bf7f..0000000 --- a/libs/loggingLib.php +++ /dev/null @@ -1,310 +0,0 @@ - $entry) - { - // the order is id, question and the number of times each of the six answers was picked - $fileData = $fileData . $id . ";"; - for ($i = 0; $i < 6; $i++) - $fileData = $fileData . $entry[$i] . ";"; - $fileData = $fileData . $entry[6] . "\n"; - } - // write tutor data block identifier - $fileData = $fileData . "###TutorData###\n"; - // write all tutor data to the file - foreach($tutorData as $id => $entry) - { - // the order is tutor name and the number of times each of the six answers was picked - $fileData = $fileData . $id . ";"; - for ($i = 0; $i < 5; $i++) - $fileData = $fileData . $entry[$i] . ";"; - $fileData = $fileData . $entry[5] . "\n"; - } - // write comment data block identifier - $fileData = $fileData . "###CommentData###"; - // write comment data - foreach($commentData as $comment) - // each comment is escapd by a new line containing three tilde characters - $fileData = $fileData . "\n" . $comment . "\n~~~"; - // write the generated data to the file and close it - // use exclusive lock - flock($handle, LOCK_EX); - ftruncate($handle, 0); - fwrite($handle, $fileData); - fflush($handle); - flock($handle, LOCK_UN); - fclose($handle); - return true; - } - /** - * Add the question data from the specified questionnaire form data to an existing form data array. - * - * @param array $formData The list of all form elements which for most cases will simply be the - * $_POST array that has been submitted by the questionnaire form. - * Passed by reference. - * @param array $commentData The list of existing question data that will be appended by the question - * Data of the form. Passed by reference. - */ - function AddQuestionData(&$formData, &$questionData, &$questionnaire) - { - foreach($formData as $id => $value) - { - if (!isset($questionnaire[$id])) - continue; - // get the type of the element with the same id as the form element from the questionnaire - $type = $questionnaire[$id][0]; - // check if the element is a question on continue with the next one if that is not the case - if ($type != "Question") - continue; - // if there is not field for the current element in the question dsta array, create a new - // blank field containing the question and zeros for the number of times each answer was picked - if (array_key_exists($id, $questionData) == false) - $questionData[$id] = array($questionnaire[$id][1], 0, 0, 0, 0, 0, 0); - // increment the answer that was selected in the formular by one - $questionData[$id][(int)$value]++; - } - } - /** - * Add the tutor data from the specified questionnaire form data to an existing tutor data array. - * - * @param array $formData The list of all form elements which for most cases will simply be the - * $_POST array that has been submitted by the questionnaire form. - * Passed by reference. - * @param array $commentData The list of existing tutor data that will be appended by the tutor - * Data of the form. Passed by reference. - */ - function AddTutorData(&$formData, &$tutorData) - { - // get the name of the tutor from the form - $tutorName = $formData["tutorName"]; - // get the selected answer of the tutorRating from the form - $tutorValue = $formData["tutorRating"]; - // if there is no field for the current tutor in the tutor array, create a new - // nlank one with zeros for the number of times each answer was picked - if (array_key_exists($tutorName, $tutorData) == false) - $tutorData[$tutorName] = array(0, 0, 0, 0, 0, 0); - // increment the answer that was selected in the form by one - $tutorData[$tutorName][$tutorValue - 1]++; - } - /** - * Add the comment data from the specified questionnaire form data to an existing comment data array. - * - * @param array $formData The list of all form elements which for most cases will simply be the - * $_POST array that has been submitted by the questionnaire form. - * Passed by reference. - * @param array $commentData The list of existing comments that will be appended by the comment - * Data of the form. Passed by reference. - */ - function AddCommentData(&$formData, &$commentData) - { - // if the comment field was filled, the comment - // array is appended by the new comment - if (array_key_exists("comment", $formData) && trim($formData["comment"]) != "") - array_push($commentData, $formData["comment"]); - } -?> diff --git a/student_questionnaire.php b/student_questionnaire.php index 42c04e1..862c891 100755 --- a/student_questionnaire.php +++ b/student_questionnaire.php @@ -1,9 +1,9 @@