---
title: "DB-Write MySQL with PHP (Data from an HTML Form) (en)"
description: This guide shows how to accept data from an HTML form with PHP and insert it into MySQL, using prepared statements to prevent SQL injection.
url: "https://aaronchan.com/kb/php-write-mysql-form-data/"
updated: "2026-09-18"
category: "Code-php+MySQL (en)"
---

# DB-Write MySQL with PHP (Data from an HTML Form) (en)

This guide shows how to accept data sent from an HTML form with PHP and insert it into a MySQL database, using prepared statements to prevent SQL injection.

## 🧩 Concept & Data Flow

When a user submits the form, the data is sent to a PHP script via `POST`, which then writes it to MySQL. The flow:

| Step | Action |
| --- | --- |
| 1 | The HTML form sends data to the PHP script via `method="post"` (`action` points to `insert.php`) |
| 2 | PHP reads each field's value with `$_POST` |
| 3 | Validate and clean (`trim`, `filter_var`) |
| 4 | Bind parameters with a prepared statement and run `INSERT` |
| 5 | Return a success/failure message and close the connection |

⚠️ **The most common mistake**: concatenating `$_POST` values straight into the SQL string. This is how SQL injection happens — any user input must go through a prepared statement.

---

## 📋 Setup: Create the Database & Table

Create the table first, and use the `utf8mb4` charset to support Chinese characters:

 Copy

```
CREATE DATABASE IF NOT EXISTS demo
  CHARACTER SET utf8mb4
  COLLATE utf8mb4_unicode_ci;

CREATE TABLE contacts (
  id         INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  name       VARCHAR(100) NOT NULL,
  email      VARCHAR(190) NOT NULL,
  message    TEXT NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
```

---

## 📝 HTML Form Example

Each input's `name` attribute becomes the key PHP reads from `$_POST`:

 Copy

```
<!-- index.html: the form sends data to insert.php via POST -->
<form action="insert.php" method="post">
  <label>Name: <input type="text" name="name" required></label><br>
  <label>Email: <input type="email" name="email" required></label><br>
  <label>Message: <textarea name="message" required></textarea></label><br>
  <button type="submit">Submit</button>
</form>
```

---

## 💾 Write to MySQL (procedural mysqli + Prepared Statement)

 Copy

```
<?php
// insert.php — write form data into MySQL (mysqli, prepared statement)
$conn = mysqli_connect('localhost', 'app_user', 'password', 'demo');
if (!$conn) {
    die('Connection failed: ' . mysqli_connect_error());
}
mysqli_set_charset($conn, 'utf8mb4');   // support Chinese, avoid mojibake

// 1. Read and validate form data
$name    = trim($_POST['name'] ?? '');
$email   = trim($_POST['email'] ?? '');
$message = trim($_POST['message'] ?? '');

if ($name === '' || $message === '' || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
    exit('Invalid input');             // stop if any required field is missing
}

// 2. Prepare an INSERT statement with ? placeholders
$stmt = mysqli_prepare($conn, 'INSERT INTO contacts (name, email, message) VALUES (?, ?, ?)');

// 3. Bind variables: "sss" = three strings, in order
mysqli_stmt_bind_param($stmt, 'sss', $name, $email, $message);

// 4. Execute and check the result
if (mysqli_stmt_execute($stmt)) {
    $new_id = mysqli_insert_id($conn);   // id of the newly inserted row
    echo "Saved successfully. New record id: $new_id";
} else {
    echo 'Error: ' . mysqli_stmt_error($stmt);
}

mysqli_stmt_close($stmt);
mysqli_close($conn);
?>
```

The first argument of `mysqli_stmt_bind_param()` is a type string — one character per column:

| Char | Type | Meaning |
| --- | --- | --- |
| s | string | text (most common) |
| i | integer | whole number |
| d | double | floating-point number |
| b | blob | binary (images, PDFs, etc.) |

---

## 🛡️ PDO Version (recommended)

PDO supports many databases and lets you use named placeholders (`:name`), which are easier to maintain:

 Copy

```
<?php
// insert.php — write form data into MySQL (PDO, recommended)
$dsn = 'mysql:host=localhost;dbname=demo;charset=utf8mb4';
$pdo = new PDO($dsn, 'app_user', 'password', [
    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,  // throw exceptions on error
    PDO::ATTR_EMULATE_PREPARES   => false,                  // use native prepared statements
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);

// Read and validate form data
$name    = trim($_POST['name'] ?? '');
$email   = trim($_POST['email'] ?? '');
$message = trim($_POST['message'] ?? '');

if ($name === '' || $message === '' || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
    exit('Invalid input');
}

// Prepared statement with named placeholders
$sql  = 'INSERT INTO contacts (name, email, message) VALUES (:name, :email, :message)';
$stmt = $pdo->prepare($sql);
$stmt->execute([
    ':name'    => $name,
    ':email'   => $email,
    ':message' => $message,
]);

$new_id = (int) $pdo->lastInsertId();   // id of the newly inserted row
echo "Saved successfully. New record id: $new_id";
?>
```

---

## 🔀 mysqli vs PDO Quick Comparison

| Item | mysqli | PDO |
| --- | --- | --- |
| Placeholder | `?` (positional) | `?` or `:name` (named) |
| Bind parameters | `mysqli_stmt_bind_param()` | `execute(array)` or `bindParam()` |
| Databases | MySQL only | many databases |
| Error handling | manual checks | can throw Exception (try-catch) |
| Recommendation | fair | ✅ recommended (portable, easier to maintain) |

---

## ⚠️ Notes

| Note | Explanation |
| --- | --- |
| Always use prepared statements | Concatenating strings is an SQL injection risk; binding parameters is safe |
| Validate input | Check required fields and email format (`filter_var`) |
| Set charset `utf8mb4` | Otherwise Chinese characters turn into mojibake |
| Least privilege | Give the DB user only `INSERT` permission, not root |
| Don't output raw SQL errors | Log errors and return a generic message to users |
| CSRF protection | Add a token to the form to prevent cross-site request forgery |
| Prevent duplicate submits | Use the PRG pattern (POST-Redirect-GET) to avoid re-inserting on refresh |

---

## 🔗 References

| Source | Link |
| --- | --- |
| PHP Manual — mysqli Prepared Statements | [php.net](https://www.php.net/manual/en/mysqli.quickstart.prepared-statements.php) |
| PHP Manual — PDO Prepared Statements | [php.net](https://www.php.net/manual/en/pdo.prepared-statements.php) |
| W3Schools — PHP MySQL Prepared Statements | [w3schools.com](https://www.w3schools.com/php/php_mysql_prepared_statements.asp) |
| Tutorial Republic — Prepared Statements | [tutorialrepublic.com](https://www.tutorialrepublic.com/php-tutorial/php-mysql-prepared-statements.php) |
| IONOS — Insert HTML form into MySQL | [ionos.com](https://www.ionos.com/digitalguide/websites/web-development/use-php-to-insert-information-into-a-mysqlmariadb-database-from-an-html-form) |
