I run a small news upload site. One day I noticed an odd bug: if I typed anything except a real date say, blacklivesmatter
into the Date field, MySQL quietly stored 0000-00-00
. No error, no warning, just a fake date that broke every report downstream.
Below is the complete fix I shipped, step by step, written in the same “I am” voice I use on my dev blog.
Here is how I think the code should look like for the error:
echo "<script language='javascript'> alert('Date should be entered with YEAR-MONTH-DAY format only'); window.location='editnews.php'; </script>";
Here is the code for the PHP page:
Why MySQL Falls Back to 0000-00-00
When the database gets a string that doesn’t match the strict YYYY-MM-DD
pattern—and SQL-mode isn’t strict—it shrugs and saves all zeroes. In my original PHP I sent the user’s raw input straight to the query:
news SET DATE = '$date' WHERE ID = '$id';
So '$date' === "blacklivesmatter"
produced 0000-00-00
.
Front End Fix Catch It Before the Form Leaves
First I swapped the loose text box for an HTML5 date picker and added one small script.
<form id="newsForm" method="post" action="editnews_action.php">
<h3><b>Title:</b>
<input type="text" name="title" value="<?= htmlspecialchars($re['Title']) ?>">
<input type="hidden" name="id" value="<?= (int)$re['ID'] ?>">
</h3>
<h3><b>Detail:</b>
<input type="text" name="desc" value="<?= htmlspecialchars($re['story']) ?>">
</h3>
<h3><b>Date (YYYY-MM-DD):</b>
<input type="date" id="date" name="date"
value="<?= htmlspecialchars($re['DATE']) ?>" required>
<span id="dateError" style="color:red;display:none">
Date must look like 2025-05-14
</span>
</h3>
<input type="submit" id="submitBtn" name="submit" value="Submit">
</form>
<script>
document.getElementById('newsForm').addEventListener('submit', e => {
const dateInput = document.getElementById('date');
const ymdRegex = /^\d{4}-\d{2}-\d{2}$/;
if (!ymdRegex.test(dateInput.value)) {
e.preventDefault(); // stop the POST
document.getElementById('dateError').style.display = 'inline';
dateInput.focus();
}
});
</script>
Placing the script just before </body>
guarantees the HTML is already parsed, so the listener attaches without fuss
Back-End Fix Validate Again in PHP
JavaScript can be bypassed; the server is my last gate.
<?php
require 'connect.php';
session_start();
function isValidDate($d) {
return preg_match('/^\d{4}-\d{2}-\d{2}$/', $d)
&& DateTime::createFromFormat('Y-m-d', $d) !== false;
}
if (isset($_POST['submit'])) {
$id = (int)$_POST['id'];
$title = mysqli_real_escape_string($con, $_POST['title']);
$date = $_POST['date'];
$story = mysqli_real_escape_string($con, $_POST['desc']);
if (!isValidDate($date)) {
$_SESSION['flash'] = 'Date must be in YYYY-MM-DD format.';
header("Location: editnews.php?id=$id");
exit;
}
$stmt = $con->prepare(
"UPDATE news SET Title=?, story=?, DATE=? WHERE ID=?"
);
$stmt->bind_param('sssi', $title, $story, $date, $id);
$stmt->execute();
header('Location: adminside.php');
exit;
}
?>
Extra Practice Features I Added
Idea | Tiny Snippet | What It Teaches |
---|---|---|
Real-time feedback | dateInput.addEventListener('input', () => dateError.style.display = ymdRegex.test(dateInput.value)?'none':'inline'); | Instant UI signals. |
Disable Submit until valid | js\nsubmitBtn.disabled = !ymdRegex.test(dateInput.value);\ndateInput.addEventListener('input', () => submitBtn.disabled = !ymdRegex.test(dateInput.value)); | Prevents mistakes up front. |
Auto-format messy input | js\ndateInput.addEventListener('blur', () => {const d=new Date(dateInput.value);if(!isNaN(d)){dateInput.value=d.toISOString().slice(0,10);}}); | Converts 2025/5/14 to 2025-05-14 . |
Unit-test the PHP helper | PHPUnit → assertTrue(isValidDate('2025-12-31')) | Locks the rule in place. |
Turn on strict SQL mode | SET sql_mode='STRICT_TRANS_TABLES' | Makes MySQL reject bad dates outright. |
Explain
- Use
<input type="date">
for native browser checks. - Back it up with a regex in JavaScript.
- Re-validate in PHP with
DateTime::createFromFormat()
. - Prepared statements > string interpolation (good-bye SQL injection).
- Flip MySQL to STRICT_TRANS_TABLES so no more silent zero dates.
Final Thought
I used to think “it’s just a date field how bad can user input get?” Turns out, a single rogue string can ripple all the way to broken charts and confused editors. By layering validation browser, JavaScript, PHP, then the database itself I caught the bug at the door and gave my users a polite nudge instead of a silent data-corruption bomb.