I'm kinda new to PHP and I'm trying to make a script to validate a HTML form only with PHP (I know there are options to do so with JS, but I guess it's better to have a "cover" with a server-side script).
Project folder structure:
project/ classes/ #contains classes to validate and process the HTML form DB.php #contains the connection to the MySQL server Rules.php #contains all rules to validate the form Validate.php #contains methods to validate each field Register.php #is the registration class ini.php #contains the spl_autoload_register() function index.php #contains the HTML form
HTML form code, which is located in the project folder:
<?php include_once 'lib/csrf-magic/csrf-magic.php; ?>
<form method="POST" action="classes/Register.php">
<fieldset>
<legend><strong>register:</strong></legend>
* <input type="text" name="fname" placeholder="First Name"/><br/>
<div style="float:left;">
<?php
// I want to put here all the validation errors for the fname field, if any
?>
</div>
<input type="submit" name="submit" value="Register"/>
</fieldset>
</form>
classes/ini.php
error_reporting(E_ALL);
ini_set('display_errors','On');
spl_autoload_register(function($class){
require_once $class.'.php';
});
classes/DB.php
class DB
{
private $driver = 'mysql';
private $host = '127.0.0.1';
private $user = 'root';
private $pass = '';
private $name = 'project';
public $db;
public function __construct()
{
try
{
$this->db = new PDO("$this->driver:host=$this->host;dbname=$this->name;charset=utf8", $this->user, $this->pass);
//Error reporting. Throw exceptions
$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
//Use native prepared statements
$this->db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
//Don't use persistent connections across multiple server sessions
$this->db->setAttribute(PDO::ATTR_PERSISTENT, false);
//Set default fetch mode
$this->db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
//Return the connection object
return $this->db;
} catch (PDOException $e)
{
#echo 'Sorry. We have some problemes. Try again later!';
echo $e->getMessage();
}
}
}
classes/Rules.php
class Rules
{
/**
* used for displaying in the page the user input text
*/
public static function escape($str)
{
return htmlspecialchars(trim($str),ENT_QUOTES,'UTF-8');
}
/**
* used to allow only numbers, letters (lc+uc), a space, an underscore, and a dash for a username. this will be stored into db
*/
public static function filter($str)
{
return preg_replace('#[^0-9a-z _-]#i', "", trim($str));
}
/**
* used to determine if the input has a certain minimum length
*/
public static function minlen($str, $value)
{
return mb_strlen(trim($str)) < $value ? true : false;
}
/**
* used to determine if the input has a certain maximum length
*/
public static function maxlen($str, $value)
{
return mb_strlen(trim($str)) > $value ? true : false;
}
/**
* used to determine if the password has a certain minimum length
*/
public static function passLen($str)
{
return mb_strlen(trim($str)) < 6 ? true : false;
}
/**
* used to determine if two passwords are equal
*/
public static function equals($pass1, $pass2)
{
return trim($pass2) === trim($pass1) ? true : false;
}
/**
* used to determine if a textbox contain a valid email
*/
public static function email($email)
{
return filter_var(trim($email),FILTER_VALIDATE_EMAIL) ? true : false;
}
/**
* used to determine if a user has wrote some date into the textbox
*/
public static function required($str)
{
return trim($str) === '' ? true : false;
}
}
classes/Validation.php
require 'ini.php';
class Validation{
public static function validateName($name){
$errors['name'] = [];
$name = Rules::filter($name);
if (Rules::required($name)) {
$errors['name'][] = 'The Name field is mandatory<br/>';
}
if (Rules::minlen($name, 3)) {
$errors['name'][] = 'The Name field is too short<br/>';
}
if (Rules::maxlen($name, 50)) { // this field is 50 chars long into the db table
$errors['name'][] = 'The Name field is too long<br/>';
}
if (isset($errors['name'])) {
return $errors['name'];
} else {
return true;
}
}
}
classes/Register.php
require_once 'ini.php';
class Register
{
private $db;
public function __construct(DB $db)
{
$this->db = $db->db;
}
public function reg()
{
$fname = isset($_POST['fname']) ? $_POST['fname'] : ''; // I' use HTMLPurifier for this variable
if (isset($_POST['submit'])) {
if (Validation::validateName($fname)) {
$stmt = $this->db->prepare('INSERT INTO users SET fname=:fn, lname=:ln');
$stmt->bindValue(':fn', $fname, PDO::PARAM_STR);
$stmt->exeecute();
} else {
foreach (Validation::validateName($fname) as $e) {
return $e;
}
}
}
}
$d = new DB();
$r = new Register($d);
echo $r->reg();
Now, I want to put all the validation errors that will occur when the user submits the form w/o filling accordingly all the fields required, into the <div>
located down under the <input type="text" name="fname">
field. The errors are in the foreach
loop located into the Register
class. Another major aspect is the security: how should I improve my code?