Emmanuel Obeng
Everyday is a school day for me as a junior developer.
You will find that statement holds true regardless of your skill level, experience, or time in the field. Like a great many things web development is not a "learn it once, be set for life" skill. There's always something new to learn, something you didn't know, and a better way of doing things.
It's why I still say the most important skills any developer can have -- beginner or expert alike -- is the ability to research, to keep learning, and to use critical thinking to question what you've already learned and/or unfounded statements that can lead to bad practices.
See "frameworks" as an example of that last part. People say they're "easier" or "simpler" or "make them more productive" where if you bother learning the underlying languages at BEST it's card-stacked disinformation, at worst it's a barefaced lie.
But you have to learn enough about what lies underneath to recognize that. Many fail to accomplish this because they've drunk so deeply of propaganda they can't even question what they are using, no matter how many times you show them how wrong it is. Ends up a bit like dealing with cultists.
Keep learning, the day you stop learning is the day the rest of the world leaves you behind.
Your first obvious mistake is checking for empty() WITHOUT an isset(). It's possible to send with the field empty, and empty() will throw an error and stop execution if it's not SET. isset and empty are two DIFFERENT checks! Though I prefer array_key_exists since I've had isset go bits-up face-down in a few corner cases.
Not so much an error, as a question, does your name="send_btn" element actually have a value on it? If not, it won't be set. Oh look...
<button type="submit" class="btn btn-default" name="send_btn">Send</button>No value, it won't be set. Well there's your problem! You MUST set a value on said form element or it will NOT be set. A sneaky shortcut HTTP uses to save bandwidth is that empty fields are skipped during form construction -- that does NOT however mean you can skip the 'empty' check and just use 'isset' since hackers will often manually edit the URI for $_GET or fake their own http headers for $_POST. You must check BOTH!
Would probably also help if you got rid of the DIV for nothing, classes for nothing, used conditionals to output the errors instead of wasting bandwidth on empty "span for nothing", had a proper fieldset, and associated your labels with their inputs via for="" pointing at id's... basically just write the the form properly.
I also doubt you're down to a depth 3 heading for "contact", but I'd have to see the page it's going into in order to be certain of that. Likewise seems like a DIV for nothing around the FORM since the form itself is a perfectly good block-level container... and technically if XML parsing does occur required="" would disable the required attribute; which is why you should either be saying just required, or required="required" if for some bizzaroland reason you're trying to put HTML 5 attributes into an XHTML document. Whilst HTML 5 allows for XML structures to be valid, you are generally better off forgetting the abortive mess that was XHTML ever even existed!
Your validation functions also contain some just plain silly code. If you only have return conditions ternary operators are your FRIEND, USE THEM!
Now, some advice? Use an associative array for your error messages. That way you don't have to hard-code each and every single one on the "empty" if statement. If you did:
$formErrors = []; if ( !array_key_exists('info', $_POST) || empty($_POST['info'] ) { $formErrors['info'] = 'Field Required'; } else if (validate_string($_POST['info'])) { $formErrors['info'] = 'Enter Valid Comment'; } // again I prefer array_key_exists, it just makes more senseetc,etc for each of your inputs, when it came time to check for no errors you can just:
if (!$formErrors) {Since an empty array is loose false!
Also since you're not doing POEM, I'd suggest using the array pass to ->execute approach instead of the three separate bindParam... but that's just personal preference. (I should bench to see if there's a difference on that someday) Likewise just a nitpick, stick to the PDO naming convention of "$statement" / "$stmt" since $sql is the outdated reference to an sql string/query, and what you get back is a PDOStatement. It's minor, but it may confuse other developers.
But for all that your biggest problem is that BUTTON tag lacking a value, so $_POST['send_btn'] will never be set.