Enhance README and refactor code structure for improved functionality
🚀 Deploy website via FTP / 🎉 Deploy (push) Failing after 8s

- Updated README.md with detailed project description, features, and installation instructions.
- Refactored functions.php to include configuration settings and improved database handling.
- Modified index.php for better user experience and added pagination controls.
- Introduced new utility functions for API handling and database interactions.
- Added CSS styles for improved layout and visibility of elements.
- Removed vault.csv as data is now managed through the database.
- Implemented FTP deployment workflow for automated deployment.
- Added exception handling classes for better error management.
- Created JavaScript functions for pagination of transaction records.
This commit is contained in:
Keith Solomon
2026-08-03 11:26:55 -05:00
parent 6e63c37071
commit 7f1f4de553
14 changed files with 692 additions and 267 deletions
+174 -204
View File
@@ -1,229 +1,199 @@
<?php
// Set usernames and keys here
const USER1_KEY = 'user1Key';
const USER2_KEY = 'user2Key';
// Include settings from a separate configuration file
require_once __DIR__ . '/config.php';
const USER1_NAME = 'user1';
const USER2_NAME = 'user2';
// Include utility functions
require_once 'includes/exceptions.php';
require_once 'includes/utilities.php';
// Set locale for monetary functions.
setlocale(LC_MONETARY, "en_US");
/** Returns a PDO connection to the database
* This function creates the database connection and creates the database
* file if it doesn't exist, and the vault table if it doesn't exist.
*
* @return PDO
*/
function getDatabaseConnection() {
static $pdo = null;
// Open CSV file in read & append mode ('a+')
$fp = fopen('vault.csv', 'a+');
// SQL to create the vault table if it doesn't exist
$createTableSQL = "CREATE TABLE IF NOT EXISTS vault (
id TEXT PRIMARY KEY,
user TEXT NOT NULL,
timestamp INTEGER NOT NULL,
description TEXT NOT NULL,
amount REAL NOT NULL
);";
// Read transactions from CSV
$csvVault = [];
$csv = [];
if ($pdo === null) {
try {
$pdo = new PDO(DB_DSN, DB_USER, DB_PASSWORD);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$lines = file('vault.csv', FILE_IGNORE_NEW_LINES);
foreach ($lines as $key => $value) {
$csv[$key] = str_getcsv($value);
}
// Get user log entries.
$user1Txn = getLog(USER1_NAME, $csv);
$user2Txn = getLog(USER2_NAME, $csv);
// Merge user arrays into transaction array
$txnVault = array_merge($user1Txn, $user2Txn);
// Build array of entries not already in the CSV
foreach ($txnVault as $key => $value) {
$csvComp = searchForId($value['timestamp'], $csv);
if (!$csvComp) {
$csvVault[] = $value;
}
}
// Store new trasnactions in CSV
foreach ($csvVault as $fields) {
fputcsv($fp, $fields);
}
fclose($fp);
// searchForID(): Serach CSV array for timestamp ID
function searchForId($id, $array) {
foreach ($array as $key => $val) {
if ($val[1] == $id) {
return true;
$pdo->exec($createTableSQL);
} catch (PDOException $e) {
die("Database connection failed: " . $e->getMessage());
}
}
return false;
return $pdo;
}
// formatMoney(): Format raw transaction vaule to display as money
// cents: 0=never, 1=if needed, 2=always
function formatMoney($number, $cents = 1) {
if (is_numeric($number)) {
if (!$number) {
$money = ($cents == 2 ? '0.00' : '0');
} else {
if (floor($number) == $number) {
$money = number_format($number, ($cents == 2 ? 2 : 0));
} else {
$money = number_format(round($number, 2), ($cents == 0 ? 0 : 2));
}
/** Pulls and stores all vault transaction logs for a user from the Torn API.
*
* This function retrieves all transaction logs related to vault deposits and
* withdrawals for a specified user. It continues fetching logs until no more
* entries are available, and stores each entry in the database. Each log entry
* is uniquely identified by its ID and includes details such as timestamp,
* description, and amount. The function requires the user's API key to
* authenticate requests to the Torn API.
*
* @param string $user The user whose transaction logs are to be retrieved and stored.
*/
function firstRun($user) {
$apiKey = USER_KEYS[$user];
$pdo = getDatabaseConnection();
$to = time();
do {
$url = "https://api.torn.com/v2/user?selections=log&log=5850,5851&to=$to";
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'accept: application/json',
"Authorization: ApiKey $apiKey"
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
if (empty($data['log'])) { break; }
foreach ($data['log'] as $key => $entry) {
$description = $entry['title'];
$timestamp = $entry['timestamp'];
$amount = isset($entry['data']['deposited']) ? $entry['data']['deposited'] : -$entry['data']['withdrawn'];
$stmt = $pdo->prepare('INSERT INTO vault (ID, user, timestamp, description, amount) VALUES (:id, :user, :timestamp, :description, :amount)');
$stmt->bindValue(':id', $key);
$stmt->bindValue(':user', $user);
$stmt->bindValue(':timestamp', $timestamp);
$stmt->bindValue(':description', $description);
$stmt->bindValue(':amount', $amount);
$stmt->execute();
}
if (substr($number,0,1) == '-') {
$money = ltrim($money, '-');
$sign = '-$';
} else {
$sign = '$';
}
return $sign.$money;
}
$to = end($data['log'])['timestamp'];
} while (true);
}
// getLog(): Get log entries for user. Returns array.
function getLog($user, $csv) {
$tornURL = 'https://api.torn.com/user/?selections=log&key=';
$i = 0;
/** Retrieves the user's log entries from the Torn API
*
* @param string $user The user to retrieve the log for
* @param boolean $debug Whether to output debug information (default: false)
*
* @throws Exception If the user does not have an API key configured,
* if the API call fails, or if the log data is invalid
*/
function getLog($user, $debug = false) {
$pdo = getDatabaseConnection();
if ($user == USER1_NAME) {
$usrKey = USER1_KEY;
$user = USER1_NAME;
ensureUserHasApiKey($user);
$stmt = $pdo->query("SELECT MAX(timestamp) AS max_timestamp FROM vault WHERE user = '$user'");
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$from = $row['max_timestamp'];
$to = time();
$apiKey = USER_KEYS[$user];
$apiEndpoint = "https://api.torn.com/user/?selections=log&log=5850,5851&to=$to&from=$from&key=$apiKey";
$responseData = executeApiCall($apiEndpoint);
validateApiResponse($responseData);
$checkStmt = prepareCheckStatement($pdo);
$insertStmt = prepareInsertStatement($pdo);
processLogEntries($responseData['log'], $user, $checkStmt, $insertStmt, $debug);
}
/** Generate the current balance for a user or all users
*
* @param string $name (optional) The user to get the balance for. If not provided, all users' balances will be added.
*
* @return string The balance as a formatted string
*/
function generateBalance($name=null) {
$balance = vaultLoop($name);
return number_format($balance, 0); // Format the balance as an integer
}
/** Calculate the available vault space for a user or all users.
*
* This function calculates the remaining space in the vault based on the
* transactions for a specific user or all users. If a user is specified,
* the available space is calculated against a limit of 500,000,000.
* If no user is specified, the available space is calculated against a
* total vault limit of 1,000,000,000.
*
* @param string|null $name (optional) The user to calculate the vault space for.
* If not provided, calculates for all users.
*
* @return string The available vault space as a formatted string.
*/
function getSpace($name=null) {
$space = vaultLoop($name);
if ($name === null) {
$space = 1000000000 - $space;
} else {
$usrKey = USER2_KEY;
$user = USER2_NAME;
$space = 500000000 - $space;
}
$usrURL = $tornURL . $usrKey;
$usrLog = json_decode(file_get_contents($usrURL));
$usrData = $usrLog->log;
$usrVault = [];
return number_format($space, 0); // Format the balance as an integer
}
foreach ($usrData as $entry) {
if ($entry->log == 5851) {
$usrVault[$i]['user'] = $user;
$usrVault[$i]['timestamp'] = $entry->timestamp;
$usrVault[$i]['operation'] = $entry->title;
$usrVault[$i]['amount'] = '-'.$entry->data->withdrawn;
} elseif ($entry->log == 5850) {
$usrVault[$i]['user'] = $user;
$usrVault[$i]['timestamp'] = $entry->timestamp;
$usrVault[$i]['operation'] = $entry->title;
$usrVault[$i]['amount'] = $entry->data->deposited;
/** Builds an HTML table of all transactions in the vault
*
* Loops over all records in the vault and builds a table of the user, timestamp,
* description and amount of each transaction. Amounts are formatted as integers.
*
* @return void
*/
function buildTable () {
$records = fetchVaultRecords();
foreach ($records as $entry) {
$user = $entry['user'];
$timestamp = $entry['timestamp'];
$description = $entry['description'];
$amount = $entry['amount'];
$sign = getSign($amount);
if ($description == 'Vault withdraw') {
$class = 'debit';
$amount = substr($amount, 1); // Remove the negative sign
} else {
continue;
$class = 'credit';
}
$i++;
$amount = number_format($amount, 0); // Format the amount as an integer
echo '<tr class="'.$class.'">';
echo '<td>'.$user.'</td>';
echo '<td>'.date("F j, Y / H:i", $timestamp).'</td>';
echo '<td>'.$description.'</td>';
echo '<td>'.$sign.$amount.'</td>';
echo '</tr>';
}
return $usrVault;
}
// vaultTxns(): Show all vault transactions
function vaultTxns($csv) {
$output = '';
$output .= '<table id="data">';
$output .= ' <thead>';
$output .= ' <td><h4>User</h4></td>';
$output .= ' <td><h4>Timestamp</h4></td>';
$output .= ' <td><h4>Operation</h4></td>';
$output .= ' <td><h4>Amount</h4></td>';
$output .= ' </thead>';
$output .= ' <tbody>';
$csv = array_reverse($csv);
foreach ($csv as $entry) {
if ($entry[2] == 'Vault withdraw') {
$class = 'debit';
} else {
$class = 'credit';
}
$output .= '<tr class="' . $class . '">';
$output .= '<td>';
$output .= $entry[0]; // User
$output .= '</td>';
$output .= '<td>';
$output .= date("d/m/Y", $entry[1]); // Transaction Date
$output .= '</td>';
$output .= '<td>';
$output .= $entry[2]; // Transaction Type
$output .= '</td>';
$output .= '<td>';
$output .= formatMoney($entry[3]); // Transaction Amount
$output .= '</td>';
$output .= '</tr>';
}
$output .= ' </tbody>';
$output .= '</table>';
echo $output;
}
// splitVault(): split CSV array into two separate arrays based on the user
function splitVault($csv, $field, $user): array {
$usrVault = [];
$usr2Vault = [];
foreach ($csv as $entry) {
if (isset($entry[$field]) && $entry[$field] == $user) {
$usr1Vault[] = $entry;
} else {
continue;
}
}
return $usr1Vault;
}
// arrBalance(): Calculate balance of arrays
function arrBalance($array, $field) {
$total = 0;
foreach ($array as $item) {
$total += $item[$field];
}
return $total;
}
// vaultBalance(): Calculate overall vault balance
function vaultBalance($csv) {
$vaultBalance = arrBalance($csv,3);
$vaultSpace = formatMoney(1000000000-$vaultBalance);
echo '<section class="vault">';
echo ' <h2>Vault Balance: '.formatMoney($vaultBalance).'</h2>';
echo ' <h3>Vault space left: '.$vaultSpace.'</h3>';
echo '</section>';
}
// userBalances(): Calculate per-user vault balances
function userBalances($csv) {
$usr1 = 'Zarathos';
$usr1Vault = splitVault($csv, '0', $usr1);
$usr1Balance = arrBalance($usr1Vault,3);
$usr1Share = formatMoney(500000000-$usr1Balance);
$usr2 = 'Symos';
$usr2Vault = splitVault($csv, '0', $usr2);
$usr2Balance = arrBalance($usr2Vault,3);
$usr2Share = formatMoney(500000000-$usr2Balance);
echo '<section class="user1">';
echo ' <h3>'.$usr1.' balance: '.formatMoney($usr1Balance).'</h3>';
echo ' <h4>'.$usr1.' share left: '.$usr1Share.'</h4>';
echo '</section>';
echo '<section class="user2">';
echo ' <h3>'.$usr2.' balance: '.formatMoney($usr2Balance).'</h3>';
echo ' <h4>'.$usr2.' share left: '.$usr2Share.'</h4>';
echo '</section>';
}
?>