Customizable Online Poll Maker JavaScript, PHP

👤 Sharing: AI
```php
<?php

// Database Configuration (Adjust to your needs)
$host = "localhost";
$username = "root";
$password = "";
$database = "online_poll";

// Create Connection
$conn = new mysqli($host, $username, $password, $database);

// Check Connection
if ($conn->connect_error) {
  die("Connection failed: " . $conn->connect_error);
}

// --- Handle New Poll Submission ---
if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST["create_poll"])) {

  // Sanitize Input
  $question = htmlspecialchars(trim($_POST["question"]));
  $options = array_map('htmlspecialchars', array_map('trim', $_POST["options"])); //trim and sanitize

  // Validate Input (Basic validation.  More thorough validation is recommended)
  if (empty($question) || count($options) < 2) {
    $error_message = "Please enter a question and at least two options.";
  } else {

    // Prepare SQL statement to insert poll question
    $stmt = $conn->prepare("INSERT INTO polls (question, created_at) VALUES (?, NOW())");
    $stmt->bind_param("s", $question);

    if ($stmt->execute()) {
      $poll_id = $conn->insert_id; // Get the ID of the newly created poll

      // Insert Options
      $stmt_option = $conn->prepare("INSERT INTO poll_options (poll_id, option_text) VALUES (?, ?)");
      $stmt_option->bind_param("is", $poll_id, $option_text);

      foreach ($options as $option_text) {
        $stmt_option->execute();
      }

      $stmt_option->close();
      $stmt->close();

      header("Location: index.php?poll_id=" . $poll_id . "&message=Poll created successfully!"); // Redirect to poll viewing page
      exit();


    } else {
      $error_message = "Error creating poll: " . $stmt->error;
    }

    $stmt->close();
  }
}


// --- Handle Voting ---
if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST["vote"])) {
    $poll_id = $_POST["poll_id"];
    $selected_option_id = $_POST["option"];

    // Check if user has already voted (Basic implementation using cookies)
    if (isset($_COOKIE["poll_voted_" . $poll_id])) {
        $error_message = "You have already voted in this poll.";
    } else {

        // Prepare SQL statement to update the vote count
        $stmt = $conn->prepare("UPDATE poll_options SET vote_count = vote_count + 1 WHERE id = ? AND poll_id = ?");
        $stmt->bind_param("ii", $selected_option_id, $poll_id);

        if ($stmt->execute()) {
            // Set a cookie to prevent multiple votes from the same user (basic)
            setcookie("poll_voted_" . $poll_id, true, time() + (86400 * 30), "/"); // Cookie expires in 30 days
            $stmt->close();
            header("Location: index.php?poll_id=" . $poll_id . "&message=Vote cast successfully!"); // Redirect to poll viewing page
            exit();
        } else {
            $error_message = "Error casting vote: " . $stmt->error;
        }

        $stmt->close();
    }
}

// --- Fetch Poll Data (if poll_id is set) ---
$poll = null;
$options = [];
if (isset($_GET["poll_id"])) {
    $poll_id = $_GET["poll_id"];

    // Fetch Poll Question
    $stmt = $conn->prepare("SELECT id, question FROM polls WHERE id = ?");
    $stmt->bind_param("i", $poll_id);
    $stmt->execute();
    $result = $stmt->get_result();
    if ($result->num_rows > 0) {
        $poll = $result->fetch_assoc();
    } else {
        $error_message = "Poll not found.";
    }
    $stmt->close();

    // Fetch Poll Options
    if ($poll) {
        $stmt = $conn->prepare("SELECT id, option_text, vote_count FROM poll_options WHERE poll_id = ?");
        $stmt->bind_param("i", $poll_id);
        $stmt->execute();
        $result = $stmt->get_result();
        while ($row = $result->fetch_assoc()) {
            $options[] = $row;
        }
        $stmt->close();
    }
}


$conn->close();
?>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Online Poll Maker</title>
    <style>
        body { font-family: sans-serif; }
        .error { color: red; }
        .message { color: green; }
        .poll-results {
            margin-top: 20px;
            border: 1px solid #ccc;
            padding: 10px;
        }
        .poll-results ul {
            list-style: none;
            padding: 0;
        }
        .poll-results li {
            margin-bottom: 5px;
        }

        .poll-results .bar-container {
            background-color: #f0f0f0;
            height: 20px;
            width: 100%;
            position: relative;
        }

        .poll-results .bar {
            background-color: #4CAF50;
            height: 100%;
            position: absolute;
            left: 0;
            top: 0;
        }

        .poll-results .percentage {
            position: absolute;
            right: 5px;
            top: 0;
            line-height: 20px;
        }
    </style>
</head>
<body>

    <h1>Online Poll Maker</h1>

    <?php if (isset($error_message)): ?>
        <p class="error"><?php echo $error_message; ?></p>
    <?php endif; ?>

    <?php if (isset($_GET["message"])): ?>
        <p class="message"><?php echo htmlspecialchars($_GET["message"]); ?></p>
    <?php endif; ?>


    <h2>Create a New Poll</h2>
    <form method="POST">
        <label for="question">Question:</label><br>
        <input type="text" id="question" name="question" required><br><br>

        <label for="options">Options (one per line):</label><br>
        <div id="options-container">
            <input type="text" name="options[]" required><br>
            <input type="text" name="options[]" required><br>
        </div>
        <button type="button" onclick="addOption()">Add Option</button>
        <button type="button" onclick="removeOption()">Remove Option</button>
        <br><br>

        <input type="submit" name="create_poll" value="Create Poll">
    </form>

    <hr>

    <?php if ($poll): ?>
        <h2><?php echo htmlspecialchars($poll["question"]); ?></h2>

        <form method="POST">
            <input type="hidden" name="poll_id" value="<?php echo $poll["id"]; ?>">
            <?php foreach ($options as $option): ?>
                <input type="radio" id="option_<?php echo $option["id"]; ?>" name="option" value="<?php echo $option["id"]; ?>" required>
                <label for="option_<?php echo $option["id"]; ?>"><?php echo htmlspecialchars($option["option_text"]); ?></label><br>
            <?php endforeach; ?>
            <br>
            <input type="submit" name="vote" value="Vote">
        </form>

        <h3>Results:</h3>
        <div class="poll-results">
            <ul>
            <?php
                $total_votes = array_sum(array_column($options, 'vote_count'));

                foreach ($options as $option):
                    $percentage = ($total_votes > 0) ? round(($option['vote_count'] / $total_votes) * 100, 2) : 0;
                    ?>
                    <li>
                        <?php echo htmlspecialchars($option['option_text']); ?>:
                        <div class="bar-container">
                            <div class="bar" style="width: <?php echo $percentage; ?>%;"></div>
                            <span class="percentage"><?php echo $percentage; ?>% (<?php echo $option['vote_count']; ?> votes)</span>
                        </div>
                    </li>
                <?php endforeach; ?>
            </ul>
            <?php if ($total_votes == 0) : ?>
                <p>No votes yet.</p>
            <?php endif; ?>

        </div>
    <?php else: ?>
        <?php if (isset($_GET["poll_id"])): ?>
            <p>No poll selected or poll not found.</p>
        <?php else: ?>
            <p>Create a poll or select one from the list.</p>
        <?php endif; ?>
    <?php endif; ?>


    <script>
        function addOption() {
            var container = document.getElementById("options-container");
            var input = document.createElement("input");
            input.type = "text";
            input.name = "options[]";
            input.required = true;
            var br = document.createElement("br");
            container.appendChild(input);
            container.appendChild(br);
        }

        function removeOption() {
            var container = document.getElementById("options-container");
            // Remove the last input field and line break
            var inputs = container.getElementsByTagName("input");
            var breaks = container.getElementsByTagName("br");
            if (inputs.length > 2) { // Keep at least two options
                container.removeChild(inputs[inputs.length - 1]);
                container.removeChild(breaks[breaks.length - 1]);
            }
        }
    </script>

</body>
</html>
```

**Explanation:**

1.  **Database Setup:**

    *   The code starts by defining the database connection details (`$host`, `$username`, `$password`, `$database`).  **Important:**  Update these values to match your MySQL database configuration.  You'll also need to create the database and tables as described later.
    *   It establishes a connection to the database using `mysqli`.
    *   Error handling is included to check if the connection was successful.  If it fails, the script will terminate with an error message.

2.  **New Poll Creation (POST request with `create_poll`):**

    *   **Input Handling:** The code checks if the request method is POST and if the `create_poll` parameter is set, indicating a new poll submission.
    *   **Sanitization and Validation:**
        *   `htmlspecialchars()`:  Crucially, input data from the form (question and options) are sanitized using `htmlspecialchars()` to prevent cross-site scripting (XSS) vulnerabilities. This converts special characters like `<`, `>`, `&`, `"` and `'` into their corresponding HTML entities.
        *   `trim()`:  Leading and trailing whitespace is removed from the input using `trim()`.
        *   Basic validation: The script checks if the question is empty and if there are at least two options.  **Important:**  You should implement more robust validation, especially on the option fields to prevent empty or excessively long options.
    *   **Database Insertion:**
        *   **Prepared Statements:** Prepared statements are used to prevent SQL injection attacks. The SQL queries are prepared with placeholders (`?`), and the actual values are bound to the statement using `bind_param()`. This ensures that the input data is treated as data and not as part of the SQL query.
        *   The code first inserts the poll question into the `polls` table.  The `created_at` column is set to the current timestamp using `NOW()`.
        *   After inserting the poll question, the code retrieves the auto-generated ID of the new poll using `$conn->insert_id`. This ID is needed to associate the poll options with the correct poll.
        *   The code then iterates through the array of options and inserts each option into the `poll_options` table.  The `poll_id` is used to link the options to the correct poll.
    *   **Redirection:** After successfully creating the poll, the user is redirected to the poll viewing page (`index.php?poll_id=...`) with a success message. This is done using `header("Location: ...")` and `exit()`.

3.  **Voting (POST request with `vote`):**

    *   **Input Handling:** Checks if the request is POST and if the `vote` parameter is set.
    *   **Basic Vote Prevention (Cookie-based):**
        *   The code checks if a cookie named `poll_voted_` + the poll ID exists.  If it does, the user has already voted in that poll, and an error message is displayed.  **Important:** This is a very basic and easily bypassed method of preventing multiple votes.  For a more robust solution, consider using user accounts or IP address tracking (with appropriate privacy considerations) and storing vote information in the database.
    *   **Database Update:**
        *   A prepared statement is used to increment the `vote_count` in the `poll_options` table for the selected option.
    *   **Cookie Setting:** A cookie is set to indicate that the user has voted.
    *   **Redirection:**  The user is redirected to the poll viewing page with a success message.

4.  **Fetching Poll Data (GET request with `poll_id`):**

    *   **Check for `poll_id`:** The code checks if a `poll_id` is present in the GET request.
    *   **Fetch Poll Question:** If a `poll_id` is provided, the code retrieves the poll question from the `polls` table.
        *   Again, a prepared statement is used.
    *   **Fetch Poll Options:** The code then fetches the options associated with the poll from the `poll_options` table.
        *   Prepared statement is used again.
    *   **Error Handling:** If the poll is not found, an error message is displayed.

5.  **HTML Structure:**

    *   The HTML provides the structure for the poll creation form, the poll voting form, and the display of results.
    *   **Form for Creating Polls:**  A form with input fields for the poll question and options. The options are dynamically added and removed using JavaScript.
    *   **Form for Voting:**  A form with radio buttons for each option, allowing the user to select their choice.  The `poll_id` is passed as a hidden input.
    *   **Displaying Results:** If a poll has been selected, the results are displayed in an unordered list. A simple bar graph is created using HTML and CSS to visually represent the vote percentages.  Includes logic to handle the case where there are no votes yet.
    *   **Error/Message Display:** Displays any error or success messages.

6.  **JavaScript:**

    *   The JavaScript code provides the functionality for dynamically adding and removing options from the poll creation form.
    *   `addOption()`: Creates a new input field for an option and appends it to the options container.
    *   `removeOption()`: Removes the last input field from the options container, ensuring there are always at least two options.

**Database Tables:**

You need to create the following tables in your MySQL database:

```sql
CREATE TABLE polls (
    id INT AUTO_INCREMENT PRIMARY KEY,
    question VARCHAR(255) NOT NULL,
    created_at DATETIME
);

CREATE TABLE poll_options (
    id INT AUTO_INCREMENT PRIMARY KEY,
    poll_id INT NOT NULL,
    option_text VARCHAR(255) NOT NULL,
    vote_count INT DEFAULT 0,
    FOREIGN KEY (poll_id) REFERENCES polls(id)
);
```

**Important Considerations and Improvements:**

*   **Security:**
    *   **SQL Injection:** The provided code uses prepared statements, which is a crucial step in preventing SQL injection. **However, carefully review the entire code base to ensure prepared statements are used correctly everywhere you interact with the database.**
    *   **Cross-Site Scripting (XSS):** The code uses `htmlspecialchars()` to sanitize user input, which is good.  Make sure you sanitize output *everywhere* that user-provided data is displayed.  Use the correct escaping function for the context (e.g., `htmlspecialchars()` for HTML, `urlencode()` for URLs).
    *   **Cross-Site Request Forgery (CSRF):** Implement CSRF protection to prevent malicious websites from making requests on behalf of authenticated users.  This typically involves adding a hidden CSRF token to your forms and validating it on the server.
*   **Input Validation:**
    *   **Server-Side Validation:** The basic validation provided (checking for empty fields) is not sufficient.  You should implement more comprehensive validation on the server-side:
        *   **Data Types:** Ensure that data is of the expected type (e.g., integers for IDs, strings for text).
        *   **Length Limits:** Limit the length of input fields to prevent excessively long data from being stored in the database.
        *   **Regular Expressions:** Use regular expressions to validate the format of input fields (e.g., email addresses).
    *   **Client-Side Validation (Optional):** Client-side validation (using JavaScript) can provide immediate feedback to the user, but it should not be relied upon for security.  Always perform validation on the server-side.
*   **Vote Prevention:**
    *   The cookie-based vote prevention is easily bypassed.  Consider the following alternatives:
        *   **User Accounts:** Require users to create accounts and log in before voting. This provides a more reliable way to track votes.
        *   **IP Address Tracking:** Track the IP addresses of voters.  However, be aware that IP addresses can change, and users may share the same IP address (e.g., on a corporate network).  Also, consider privacy implications.
        *   **Database Storage:** Store the vote information in the database, linking the vote to a user account or IP address.
*   **Error Handling:**
    *   The error handling is basic.  Implement more robust error handling to catch exceptions and log errors.  This will help you identify and fix issues in your code.  Display user-friendly error messages to the user.
*   **User Interface (UI):**
    *   Improve the user interface to make the poll creation and voting process more intuitive and user-friendly.
*   **Accessibility:**
    *   Make sure your poll application is accessible to users with disabilities.  Use semantic HTML, provide alternative text for images, and ensure that your forms are properly labeled.
*   **Scalability:**
    *   If you expect a large number of users, consider using a database that is designed for high scalability, such as MySQL with replication or a NoSQL database.
*   **Code Organization:**
    *   For a larger application, consider separating the code into multiple files (e.g., database connection, poll creation, voting, display).  Use functions and classes to organize the code and make it more maintainable.
*   **Configuration:**
    *   Move the database connection details to a separate configuration file so that they can be easily changed without modifying the code.
*   **Security Best Practices:**
    *   Keep your PHP installation and libraries up to date to patch security vulnerabilities.
    *   Use a strong password for your database user.
    *   Disable error reporting in production.
    *   Enable HTTPS to encrypt traffic between the client and server.

This improved example provides a more secure and robust foundation for your online poll maker. Remember to address the security and scalability considerations as your application grows. Good luck!
👁️ Viewed: 9

Comments