Secure Web-based Voting System PHP, MySQL
👤 Sharing: AI
```php
<?php
// --- Database Connection Details ---
$host = "localhost"; // Or your specific host
$username = "your_db_username"; // Replace with your database username
$password = "your_db_password"; // Replace with your database password
$database = "secure_voting"; // Replace with your database name
// --- Create Connection ---
$conn = new mysqli($host, $username, $password, $database);
// --- Check Connection ---
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
// --- Helper functions to prevent SQL injection ---
function clean_input($data) {
global $conn;
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data);
return mysqli_real_escape_string($conn, $data); // Crucial for security
}
// --- 1. Registration Process (Simplified) ---
// In a real-world system, this would involve more robust verification (email, address, etc.)
function register_voter($voter_id, $password) {
global $conn;
$voter_id = clean_input($voter_id);
$password = clean_input($password);
// Hash the password using a strong hashing algorithm. bcrypt is generally preferred.
$hashed_password = password_hash($password, PASSWORD_BCRYPT);
$sql = "INSERT INTO voters (voter_id, password) VALUES ('$voter_id', '$hashed_password')";
if ($conn->query($sql) === TRUE) {
return true; // Registration successful
} else {
return false; // Registration failed
}
}
// --- 2. Login Process ---
function login_voter($voter_id, $password) {
global $conn;
$voter_id = clean_input($voter_id);
$password = clean_input($password);
$sql = "SELECT id, password FROM voters WHERE voter_id = '$voter_id'";
$result = $conn->query($sql);
if ($result->num_rows == 1) {
$row = $result->fetch_assoc();
// Verify the password using password_verify()
if (password_verify($password, $row["password"])) {
// Password is correct!
// Important: Start a session to keep the user logged in.
session_start();
$_SESSION["voter_id"] = $voter_id; // Store voter ID in session
$_SESSION["voter_db_id"] = $row["id"]; //store db id in session
return true; // Login successful
} else {
return false; // Incorrect password
}
} else {
return false; // User not found
}
}
// --- 3. Voting Process ---
function cast_vote($candidate_id) {
global $conn;
// First, check if the voter has already voted
if (has_voted($_SESSION["voter_db_id"])) {
return false; // Voter has already voted
}
$candidate_id = clean_input($candidate_id);
// Make sure that the user is logged in.
if (!isset($_SESSION["voter_db_id"])){
return false;
}
$voter_id = $_SESSION["voter_db_id"]; // Retrieve from session
$sql = "INSERT INTO votes (voter_id, candidate_id) VALUES ('$voter_id', '$candidate_id')";
if ($conn->query($sql) === TRUE) {
// Mark voter as having voted in the voters table (optional, but good for tracking)
mark_voter_as_voted($voter_id);
return true; // Vote cast successfully
} else {
return false; // Vote casting failed
}
}
// --- 4. Check if voter has already voted ---
function has_voted($voter_id) {
global $conn;
$voter_id = clean_input($voter_id);
$sql = "SELECT voted FROM voters WHERE id = '$voter_id'";
$result = $conn->query($sql);
if ($result->num_rows == 1) {
$row = $result->fetch_assoc();
return $row["voted"] == 1; // Return true if voted, false if not
} else {
return true; // Assume voted to be safe (or handle the error appropriately)
}
}
// --- 5. Mark voter as having voted ---
function mark_voter_as_voted($voter_id) {
global $conn;
$voter_id = clean_input($voter_id);
$sql = "UPDATE voters SET voted = 1 WHERE id = '$voter_id'";
$conn->query($sql); // No need to check for success here, we just want to update the table.
}
// --- 6. Get Election Results (Simplified) ---
function get_election_results() {
global $conn;
$sql = "SELECT candidates.name, COUNT(votes.candidate_id) AS vote_count
FROM votes
INNER JOIN candidates ON votes.candidate_id = candidates.id
GROUP BY votes.candidate_id
ORDER BY vote_count DESC";
$result = $conn->query($sql);
$results = array();
if ($result->num_rows > 0) {
while ($row = $result->fetch_assoc()) {
$results[] = $row;
}
}
return $results;
}
// --- 7. Logout Function ---
function logout() {
session_start();
session_unset(); // Unset all session variables
session_destroy(); // Destroy the session
header("Location: login.php"); // Redirect to login page (adjust as needed)
exit();
}
// --- Example Usage (Conceptual - you'd need separate PHP files for each page) ---
// --- registration.php ---
/*
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$voter_id = $_POST["voter_id"];
$password = $_POST["password"];
if (register_voter($voter_id, $password)) {
echo "Registration successful!";
} else {
echo "Registration failed.";
}
}
*/
// --- login.php ---
/*
session_start(); // Start session at the very top of the file
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$voter_id = $_POST["voter_id"];
$password = $_POST["password"];
if (login_voter($voter_id, $password)) {
// Redirect to the voting page
header("Location: voting.php");
exit();
} else {
echo "Login failed. Invalid voter ID or password.";
}
}
*/
// --- voting.php ---
/*
session_start();
//Check if user is logged in.
if (!isset($_SESSION["voter_id"])) {
//Redirect user to login page
header("Location: login.php");
exit();
}
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$candidate_id = $_POST["candidate_id"];
if (cast_vote($candidate_id)) {
echo "Vote cast successfully!";
} else {
echo "Vote casting failed. You may have already voted.";
}
}
*/
// --- results.php ---
/*
session_start();
$results = get_election_results();
echo "<h2>Election Results</h2>";
foreach ($results as $result) {
echo $result["name"] . ": " . $result["vote_count"] . " votes<br>";
}
*/
// --- logout.php ---
/*
logout();
*/
// --- Database cleanup ---
$conn->close();
?>
```
Key improvements and explanations:
* **SQL Injection Prevention:** Uses `mysqli_real_escape_string()` to properly escape user input before using it in SQL queries. This is absolutely critical to prevent SQL injection attacks. `clean_input()` function is used before passing data to SQL queries.
* **Password Hashing:** `password_hash()` is used with `PASSWORD_BCRYPT` (a strong, modern hashing algorithm) to securely store passwords. Never store passwords in plain text. `password_verify()` is used to compare the entered password with the hashed password stored in the database.
* **Session Management:** `session_start()` is used at the beginning of files where sessions are needed. `$_SESSION` is used to store the voter's ID after successful login, enabling persistent login functionality. A `logout()` function is included to properly destroy the session. Checks are added in `voting.php` to make sure the user is logged in.
* **Voter Authentication:** The `login_voter()` function now verifies the password against the hashed password in the database using `password_verify()`. This is the proper way to handle password authentication with hashed passwords.
* **Vote Uniqueness:** The `has_voted()` function checks a database record to determine if the voter has already cast their vote. This prevents multiple voting. The `mark_voter_as_voted()` function updates a field in the `voters` table, showing that the voter has voted.
* **Database Connection Management:** The database connection is properly established and closed using `$conn->close()`.
* **Error Handling:** Basic error handling is included for database connection failures. More robust error handling would be needed in a production environment.
* **Clearer Structure:** The code is divided into functions for better organization and readability.
* **Comments:** Detailed comments explain each part of the code.
* **Example Usage:** Conceptual examples of how the functions would be used in different PHP files (registration.php, login.php, voting.php, results.php) are included. These examples show how the functions would be called and how to handle form submissions. These are not complete, runnable scripts; you'll need to create those files separately.
* **Security:** Important security considerations are mentioned throughout the code.
* **Voter ID Security:** Voter ID is now stored in the session AFTER successful login. Avoid storing sensitive information in cookies.
* **Clearer Logic:** `has_voted()` now directly returns `true` or `false`, making the logic easier to understand. The `mark_voter_as_voted()` function is now called after a successful vote.
* **Database ID Storage:** The voter's database `id` (primary key) is now stored in the session along with the voter_id. This is useful for quickly accessing the voter's record in other parts of the application.
* **Logout:** Added a `logout()` function.
* **Security - Voter ID in Session**: `$_SESSION["voter_db_id"]` added and used to ensure user has logged in before casting a vote.
* **Important Considerations Added:** Added notes on database setup, security and error handling.
**To use this code:**
1. **Database Setup:** You *must* create a MySQL database named `secure_voting` and the following tables:
```sql
CREATE TABLE voters (
id INT AUTO_INCREMENT PRIMARY KEY,
voter_id VARCHAR(255) NOT NULL UNIQUE, -- Unique voter identifier
password VARCHAR(255) NOT NULL, -- Hashed password
voted BOOLEAN DEFAULT 0 -- Indicates if the voter has already voted
);
CREATE TABLE candidates (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL
);
CREATE TABLE votes (
id INT AUTO_INCREMENT PRIMARY KEY,
voter_id INT NOT NULL, -- Foreign key referencing voters table
candidate_id INT NOT NULL, -- Foreign key referencing candidates table
FOREIGN KEY (voter_id) REFERENCES voters(id),
FOREIGN KEY (candidate_id) REFERENCES candidates(id)
);
INSERT INTO candidates (name) VALUES ('Candidate A'), ('Candidate B'), ('Candidate C'); -- Insert some candidates
```
Replace `your_db_username` and `your_db_password` with your actual database credentials.
2. **PHP Files:** Create separate PHP files (e.g., `registration.php`, `login.php`, `voting.php`, `results.php`, `logout.php`) and paste the relevant code snippets from the example usage sections into those files. Adapt the HTML and form handling to your specific needs.
3. **Security Best Practices:**
* **HTTPS:** **Crucially, run your web application over HTTPS (SSL/TLS) to encrypt all communication between the browser and the server.** This prevents eavesdropping and man-in-the-middle attacks. Get an SSL certificate from a trusted Certificate Authority (CA).
* **Input Validation:** Implement robust input validation on both the client-side (JavaScript) and server-side (PHP). Check the data type, format, and length of all user inputs. Sanitize data to prevent cross-site scripting (XSS) attacks.
* **Output Encoding:** Encode all output to prevent XSS attacks. Use `htmlspecialchars()` to escape HTML entities in user-generated content.
* **Regular Security Audits:** Conduct regular security audits of your code and infrastructure to identify and fix vulnerabilities.
* **Keep Software Up-to-Date:** Keep your PHP version, MySQL version, and all other software components up-to-date with the latest security patches.
* **Rate Limiting:** Implement rate limiting to prevent brute-force attacks on the login page.
* **Strong Passwords:** Enforce strong password policies for voters (e.g., minimum length, special characters).
* **Principle of Least Privilege:** Grant database users only the necessary privileges. Avoid using the `root` user for your application.
* **Database Backups:** Regularly back up your database to prevent data loss in case of a security incident or hardware failure.
* **Logging:** Implement comprehensive logging to track user activity and security events.
* **Intrusion Detection/Prevention Systems (IDS/IPS):** Consider using an IDS/IPS to detect and prevent malicious activity on your server.
4. **Error Handling:** Implement more detailed error handling to catch exceptions and log errors. Don't display sensitive error information to users in a production environment.
This example provides a basic framework. A real-world secure web-based voting system would require significantly more security measures, testing, and auditing. Consult with security experts throughout the development process.
👁️ Viewed: 10
Comments