This commit is contained in:
Joshua Ashton
2025-03-06 23:08:52 -07:00
parent 86d501c980
commit 551abb66b5
12 changed files with 514 additions and 20 deletions
+4 -1
View File
@@ -1,2 +1,5 @@
</body> <?php
echo '
</body>
</html> </html>
';
+46
View File
@@ -0,0 +1,46 @@
<?php
include_once('includes/functions.php');
/*
* Creates a form from an associative array of fields.
*
* See includes/input_validation.php for the structure of a fields array.
*/
function generate_form($fields, $error)
{
$form = '
<div class="standard_box outer_shadow form_container">
<form method="' . $fields['method'] . '" action="' . $fields['action'] . '">
';
foreach ($fields as $field => $metadata) {
if ($field == 'method' || $field == 'action')
continue;
$form .= '
<div class="input_box inner_shadow">
<label for="' . $field . '">' . ucwords($metadata['label']) . '</label>
<input id="' . $field . '" name="' . $field . '" type="' . $metadata['type'] . '" placeholder="' . $metadata['placeholder'] . '">
</div>
';
}
$form .= '
<input type="submit" class="submit_button">
</form>
';
if (!empty($error)) {
$form .= '
<div class="standard_box inner_shadow error">
<p class="error">' . ucwords($error) . ' information!</p>
</div>
';
}
$form .= '
</div>
';
return $form;
}
+10 -6
View File
@@ -1,10 +1,14 @@
<?php
echo '
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<title>Dummy Title</title> <title>Vintage Coding</title>
<link href="css/styles.css" type="text/css" rel="stylesheet"> <link href="css/styles.css" type="text/css" rel="stylesheet">
<script src="js/index.js"></script> <script src="js/index.js"></script>
</head> </head>
<body> <body>
';
include_once('nav.php');
+8 -8
View File
@@ -1,14 +1,14 @@
<?php <?php
$nav = ' $nav = '
<nav> <nav>
<ul> <ul>
<li><a href="home.php">Home</a></li> <li><a href="home.php">Home</a></li>
<li><a href="account.php">Account</a></li> <li><a href="account.php">Account</a></li>
<li><a href="admin.php">Admin</a></li> <li><a href="admin.php">Admin</a></li>
<li><a href="articles.php">Articles</a></li> <li><a href="articles.php">Articles</a></li>
</ul> </ul>
</nav> </nav>
'; ';
echo $nav; echo $nav;
+25
View File
@@ -0,0 +1,25 @@
<?php
$login_fields = [
'method' => 'post',
'action' => 'process.php?action=login',
'login_username' => [
'label' => 'username',
'type' => 'text',
'placeholder' => 'e.g., jsmith',
'validators' => [
'no_spaces',
// 'check_sql',
],
],
'login_password' => [
'label' => 'password',
'type' => 'password',
'placeholder' => '',
'validators' => [
'no_spaces',
// 'pw_strength',
// 'no_backslash',
// 'check_sql',
],
],
];
+28 -2
View File
@@ -1,4 +1,30 @@
<?php <?php
include_once ('includes/sql.php'); include_once('sql.php');
function login($username, $password_hash) {} function authorize($username, $password_hash)
{
$pw_hash = get_account_login($username);
pretty_print($pw_hash);
if (!empty($pw_hash)) {
if ($password_hash == $pw_hash) {
$user = get_account_info($username);
pretty_print($user);
// $_SESSION['is_logged_in'] = true;
// $_SESSION['username'] = $username;
return true;
}
}
return false;
}
function pretty_print($input)
{
echo '
<pre>
' . print_r($input) . '
</pre>
';
}
+239
View File
@@ -0,0 +1,239 @@
<?php
/*
* This file provides functions for validating form input data. For any given
* field in an associative array, provide an array of validation requirements.
* This is to enable modular data fields while ensuring data integrity and
* safety from SQL injection.
*
* Each function accepts at least an input string, and will return either true
* or false. It is up to the client to interpret that and create error messages
* and ensure data format consistency accordingly.
*
* EXAMPLE CLIENT DATA IMPLEMENTATION
*
* $standard_fields = [
* 'ca-username' => [
* // Placeholder text
* 'e.g., jsmith',
*
* // Validation requirements
* [
* 'no_spaces',
* 'checkSQL',
* ],
* ],
* ];
*
* EXAMPLE CLIENT IMPLEMENTATION
*
* function validate($standard_fields, $admin_fields) {
* include('includes/input_validation.php');
* $error = '';
* foreach($standard_fields as $field => $arr) {
* // Get the requirements from the associative array.
* $validationRequirements = $arr[1];
*
* foreach($validationRequirements as $validReq) {
* switch($validReq) {
* case 'no_spaces':
* if(no_spaces($_POST[$field])) {
* $error .= '<p>' . $field . ' does not allow spaces.</p>';
* }
* break;
* default:
* $error .= '<p>Something went wrong...</p>';
* break;
* }
* }
* }
* }
*/
function no_spaces($input)
{
return !str_contains($input, ' ');
}
function no_digits($input)
{
for ($i = 0; $i < strlen($input); $i++)
if (is_numeric($input[$i]))
return false;
return true;
}
function no_backslash($input)
{
for ($i = 0; $i < strlen($input); $i++)
if ($input[$i] === '\\')
return false;
return true;
}
/*
* This checks for the following characters:
* ' ' ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [
* \ ] ^ _ ` { | } ~
*
* TODO: Add support for additional special characters available through
* other means.
*/
function no_special($input)
{
$special = [
'!',
'"',
'#',
'$',
'%',
'&',
"'",
'(',
')',
'*',
'+',
',',
'-',
'.',
'/',
':',
';',
'<',
'=',
'>',
'?',
'@',
'[',
'\\',
']',
'^',
'_',
'`',
'{',
'|',
'}',
'~',
];
for ($i = 0; $i < strlen($input); $i++)
if (in_array($input[$i], $special))
return false;
return true;
}
function only_digits($input)
{
for ($i = 0; $i < strlen($input); $i++)
if (!is_numeric($input[$i]))
return false;
return true;
}
function only_digits_x($input, $x)
{
if (strlen($input) != $x)
return false;
for ($i = 0; $i < strlen($input); $i++)
if (!is_numeric($input[$i]))
return false;
return true;
}
function only_letters($input)
{
return (preg_match('/[^A-Za-z]*/', $input) == 1 ? true : false);
}
function only_letters_x($input, $x)
{
if (strlen($input) != $x)
return false;
return (preg_match('/[^A-Za-z]*/', $input) ? true : false);
}
// TODO: Add additional step which tests if the email exists.
function valid_email($input)
{
if (!str_contains($input, '@'))
return false;
$email = explode('@', $input);
if (count($email) != 2)
return false;
return true;
}
/*
* Note: While this function handles the most common variations of a phone
* number (and potential missed or inconsistent entry), it does not apply
* any formatting. The client must handle data consistency themselves.
*/
function valid_phone($input)
{
$formats = [
'/^\d{10}$/', // xxxxxxxxxx
'/^\d{3}-\d{7}$/', // xxx-xxxxxxx
'/^\d{6}-\d{4}$/', // xxxxxx-xxxx
'/^\d{3}-\d{3}-\d{4}$/', // xxx-xxx-xxxx
'/^\(\d{3}\)\d{7}$/', // (xxx)xxxxxxx
'/^\(\d{3}\)\d{3}-\d{4}$/', // (xxx)xxx-xxxx
'/^\(\d{3}\) \d{3}-\d{4}$/', // (xxx) xxx-xxxx
'/^\(\d{3}\)\d{3} -\d{4}$/', // (xxx)xxx -xxxx
'/^\(\d{3}\)\d{3}- \d{4}$/', // (xxx)xxx- xxxx
'/^\(\d{3}\)\d{3} - \d{4}$/', // (xxx)xxx - xxxx
'/^\(\d{3}\) \d{3} -\d{4}$/', // (xxx) xxx -xxxx
'/^\(\d{3}\) \d{3}- \d{4}$/', // (xxx) xxx- xxxx
'/^\(\d{3}\) \d{3} - \d{4}$/', // (xxx) xxx - xxxx
'/^\d{3} \d{7}$/', // xxx xxxxxxx
'/^\d{6} \d{4}$/', // xxxxxx xxxx
'/^\d{3} \d{3} \d{4}$/', // xxx xxx xxxx
'/^\d{3} \d{3}-\d{4}$/', // xxx xxx-xxxx
'/^\d{3}-\d{3} \d{4}$/', // xxx-xxx xxxx
'/^\d{3}\.\d{7}$/', // xxx.xxxxxxx
'/^\d{6}\.\d{4}$/', // xxxxxx.xxxx
'/^\d{3}\.\d{3}\.\d{4}$/', // xxx.xxx.xxxx
];
foreach ($formats as $regex)
if (preg_match($regex, $input))
return true;
return false;
}
/*
* TODO: This should ensure the user's password consists of the following:
* - length > 8,
* - 1+ uppercase letters,
* - 1+ lowercase letters,
* - 1+ digits,
* - 1+ special characters
*/
function pw_strength($input)
{
return true;
}
/*
* TODO: Need to implement SQL Injection prevention.
*
* Note: This should have the additional step of blacklisting a user who
* attempts SQL Injection. At least adding any valid submitted information
* to a DB table in case they attempt to create a 'valid' account, or
* flagging a 'valid' account that attempts SQL Injection. This will require
* a lot of research and therefore time. For now, since this isn't public
* facing, I'll operate with some trust in the user.
*
* Also, this might be better in a database functions file instead.
*/
function check_sql($input)
{
return false;
}
+24
View File
@@ -26,6 +26,30 @@ function get_all_accounts()
return $results; return $results;
} }
function get_account_login($username)
{
$conn = mysqli_connect(HOST, USER, PASS, DB);
$query = 'SELECT password_hash FROM accounts WHERE username = "' . $username . '";';
$results = mysqli_query($conn, $query);
return $results;
}
function get_account_info($username)
{
$conn = mysqli_connect(HOST, USER, PASS, DB);
$query = 'SELECT * FROM accounts WHERE username = "' . $username . '";';
$results = mysqli_query($conn, $query);
return $results;
}
function get_account_role($username)
{
$conn = mysqli_connect(HOST, USER, PASS, DB);
$query = 'SELECT * FROM accounts WHERE username = "' . $username . '";';
$results = mysqli_query($conn, $query);
return $results;
}
function get_all_article_cards() function get_all_article_cards()
{ {
$conn = mysqli_connect(HOST, USER, PASS, DB); $conn = mysqli_connect(HOST, USER, PASS, DB);
+2 -3
View File
@@ -1,7 +1,6 @@
<?php <?php
include_once('includes/components/head.php'); include_once('includes/components/head.php');
include_once('includes/components/nav.php');
include_once('includes/sql.php'); include_once('login.php');
get_article_cards();
include_once('includes/components/foot.php'); include_once('includes/components/foot.php');
+8
View File
@@ -0,0 +1,8 @@
<?php
include_once ('includes/fields/login_fields.php');
include_once ('includes/components/form.php');
if (isset($_GET['error']))
echo generate_form($login_fields, $_GET['error']);
else
echo generate_form($login_fields, '');
+6
View File
@@ -0,0 +1,6 @@
<?php
include_once('../includes/components/head.php');
echo '<h1>Home</h1>';
include_once('../includes/components/foot.php');
+114
View File
@@ -0,0 +1,114 @@
<?php
if (!isset($_GET['action']))
header('Location: .');
include_once('includes/functions.php');
$action = $_GET['action'];
switch ($action) {
case 'login':
$error_location = 'login.php?error=';
$success_location = 'pages/home.php';
// If fields are empty, redirect to login with error state.
if (empty($_POST['login_username']) || empty($_POST['login_password']))
header('Location: ' . $error_location . 'empty');
include_once('fields/login_fields.php');
// If field inputs are invalid, redirect to login with error state.
foreach ($_POST as $field => $value) {
if (!validate($value, $login_fields[$field]['validators']))
header('Location: ' . $error_location . 'invalid');
}
$username = $_POST['login_username'];
$password_hash = hash('sha256', $_POST['login_password']);
// If username/password hash are incorrect, redirect to login with error state.
if (!authorize($username, $password_hash))
header('Location: ' . $error_location . 'incorrect');
unset($_POST['login_username']);
unset($_POST['login_password']);
// auth() handles setting $_SESSION variables, user is now OK to proceed to home.php.
// header('Location: ' . $success_location);
default:
// code...
break;
}
function validate($input, $validators)
{
include_once('includes/input_validation.php');
foreach ($validators as $v) {
switch ($v) {
case 'no_spaces':
if (!no_spaces($input))
return false;
break;
case 'no_digits':
if (!no_digits($input))
return false;
break;
case 'no_backslash':
if (!no_backslash($input))
return false;
break;
case 'no_special':
if (!no_special($input))
return false;
break;
case 'only_digits':
if (!only_digits($input))
return false;
break;
// TODO: Need to get x.
case 'only_digits_x':
if (!only_digits_x($input, 5))
return false;
break;
case 'only_letters':
if (!only_letters($input))
return false;
break;
// TODO: Need to get x.
case 'only_letters_x':
if (!only_letters_x($input, 5))
return false;
break;
case 'valid_email':
if (!valid_email($input))
return false;
break;
case 'valid_phone':
if (!valid_phone($input))
return false;
break;
case 'pw_strength':
if (!pw_strength($input))
return false;
break;
case 'check_sql':
if (check_sql($input))
return false;
break;
}
}
return true;
}