PHPPOT User Login működése

Egy egyszerű PHP alapú felhasználó beléptetőrendszer file-jainak elemzése. Főleg magam részére, de publikusan, hátha másnak is hasznos lesz ez a leírás, esetleg ez alapján jobban megérti, hogyan is működik egy ilyen beléptető rendszer. Egyszerűsége végett könnyű megérteni a működését kezdő PHP-vel ismerkedők számára is.

1. /view/login-form.php
<html>
<head>
<title>User Login</title>
<link href="./view/css/style.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div>
<form action="login-action.php" method="post" id="frmLogin" onSubmit="return validate();">
<div class="demo-table">

<div class="form-head">Login</div>
<?php
if(isset($_SESSION["errorMessage"])) {
?>
<div class="error-message"><?php echo $_SESSION["errorMessage"]; ?></div>
<?php
unset($_SESSION["errorMessage"]);
}
?>
<div class="field-column">
<div>
<label for="username">Username</label><span id="user_info" class="error-info"></span>
</div>
<div>
<input name="user_name" id="user_name" type="text"
class="demo-input-box">
</div>
</div>
<div class="field-column">
<div>
<label for="password">Password</label><span id="password_info" class="error-info"></span>
</div>
<div>
<input name="password" id="password" type="password"
class="demo-input-box">
</div>
</div>
<div class=field-column>
<div>
<input type="submit" name="login" value="Login"
class="btnLogin"></span>
</div>
</div>
</div>
</form>
</div>
<script>
function validate() {
var $valid = true;
document.getElementById("user_info").innerHTML = "";
document.getElementById("password_info").innerHTML = "";

var userName = document.getElementById("user_name").value;
var password = document.getElementById("password").value;
if(userName == "")
{
document.getElementById("user_info").innerHTML = "required";
$valid = false;
}
if(password == "")
{
document.getElementById("password_info").innerHTML = "required";
$valid = false;
}
return $valid;
}
</script>
</body>
</html>

- HTML form. Ez a form van illesztve minden jelszó által védett lapra, ha az user nincs bejelentkezve, ezzel találkozik minden lapon.
- A következő adatokat küldi a login-action.php akció fájlnak POST metódussal: Username (user_name ID-vel), Password (password ID-vel)
- $_SESSION["errorMessage"]-ben hibaüzenetet fogad, amit a login-action.php küld vissza, ha az User/Password nem található az adatbázisban, vagy bármi egyéb panasza van. Majd unseteli azt, hogy a következő frissítésnél már ne legyen benne a sessionban az error message.
- onSubmit eseménynél egy Javascript kóddal ellenőrzést végez. Megakadályozza a form adatok nélküli elküldését.
- Ha minden rendben és az adatok nem üresek, akkor elküldésre kerülnek a login akció fájlnak, ami feldolgozza azokat.

2. /login-action.php

<?php
namespace Phppot;

use \Phppot\Member;
if (! empty($_POST["login"])) {
session_start();
$username = filter_var($_POST["user_name"], FILTER_SANITIZE_STRING);
$password = filter_var($_POST["password"], FILTER_SANITIZE_STRING);
require_once (__DIR__ . "/class/Member.php");

$member = new Member();
$isLoggedIn = $member->processLogin($username, $password);
if (! $isLoggedIn) {
$_SESSION["errorMessage"] = "Invalid Credentials";
}
if (!empty($_SERVER['HTTP_REFERER']))
header("Location: ".$_SERVER['HTTP_REFERER']);
else
header("Location: ./index.php");
exit();
}

- Ez is ellenőrzi, hogy megérkeztek e a szükséges adatok a belépéshez, ha nem, akkor nem teszt semmit. Fehér lapot ad vissza. Ez főleg akkor lehetséges, ha direktben megnyitjuk a login-action.php fájlt a böngészőben, ekkor értelemszerűen semmilyen adatot nem kap a formtól, így egy fehér lapot kapunk eredményül.
- Ha vannak adatok a login submit folyamatból, akkor elindítja a sessiont, felveszi POST metódusból kapott változókat a $username $password változókba
- Meghívja az egyszer és mindenképp szükséges fájlt a /class/Member.php-t, amiben a processLogin funkció található.
- Új Member osztály példányt kreál $member változóban.
- $isLoggedIn értéke a Member.php processLogin funkciójából kinyert $username, $password értéket kapja, ennek értéke IGAZ vagy HAMIS lesz. Ha hamis akkor "Invalid Credentials"; értéket veszi fel a $_SESSION["errorMessage"] globális változóba. Ha igaz, akkor ezt a lépést kihagyva visszaküld minket oda ahonnan jöttünk vagy az index oldalra. Ekkor már be vagyunk lépve és van értéke a $_SESSION["userId"] szuperglobális változónak a felhasználó ID számával, azaz a belépés megtörtént.
- Ha végzett, refer oldal létezése esetén visszaküld oda ahonnan jöttünk, ellenkező esetben az index oldalra. Ha hibával akkor újra a login form jelenik meg, ami kiadja a $_SESSION["errorMessage"] értéket is, amit unsetel, ahogy fent írtam, ha eredménnyel akkor megjeleníti a session létezése esetén megjeleníthető dolgokat. Pl hogy Hurrá, sikerrel beléptél $user.

3. /class/Memeber.php

<?php
namespace Phppot;

use \Phppot\DataSource;

class Member
{

private $dbConn;

private $ds;

function __construct()
{
require_once "DataSource.php";
$this->ds = new DataSource();
}

function getMemberById($memberId)
{
$query = "select * FROM registered_users WHERE id = ?";
$paramType = "i";
$paramArray = array($memberId);
$memberResult = $this->ds->select($query, $paramType, $paramArray);

return $memberResult;
}

public function processLogin($username, $password) {
$passwordHash = md5($password);
$query = "select * FROM registered_users WHERE user_name = ? AND password = ?";
$paramType = "ss";
$paramArray = array($username, $passwordHash);
$memberResult = $this->ds->select($query, $paramType, $paramArray);
if(!empty($memberResult)) {
$_SESSION["userId"] = $memberResult[0]["id"];
return true;
}
}
}

- Ebben a fájlban található a login-action.php-ben kért processLogin funkció, ami feldolgozza az akció fájl által küldött usernevet és jelszót.
- Alkalmazza a \Phppot\DataSource-t, követeli egyszer a DataSource.php fájlt, amiben az adatbázishoz való kapcsolódási információk és előkészített adatbázis lekérdezési funkciók is találhatók.
- Ha nem üresen jön vissza a select lekérése, akkor $memberResult megkapja azt az ID értéket, amit az User bejelentkezési neve alapján az adatbázisban megtalál és ezt egyenlővé teszi a $_SESSION["userId"] -vel és a funkció visszatérési értékét Treue-ra (azaz IGAZ-ra) állítja
- $this->ds->select($query, $paramType, $paramArray); kéri a DataSource.php-tól a select funkciót az adatokkal, így kapja meg az adatokat a $memberResult

4. /class/DataSource.php

<?php
namespace Phppot;

/**
* Generic datasource class for handling DB operations.
* Uses MySqli and PreparedStatements.
*
* @version 2.3
*/
class DataSource
{

// PHP 7.1.0 visibility modifiers are allowed for class constants.
// when using above 7.1.0, declare the below constants as private
const HOST = 'localhost'; // Change to your own DATA

const USERNAME = 'DB-USERAME'; // Change to your own DATA

const PASSWORD = 'YOUR-DB-PASS'; // Change to your own DATA

const DATABASENAME = 'YOUR-DB-NAME'; // Change to your own DATA

private $conn;

/**
* PHP implicitly takes care of cleanup for default connection types.
* So no need to worry about closing the connection.
*
* Singletons not required in PHP as there is no
* concept of shared memory.
* Every object lives only for a request.
*
* Keeping things simple and that works!
*/
function __construct()
{
$this->conn = $this->getConnection();
}

/**
* If connection object is needed use this method and get access to it.
* Otherwise, use the below methods for insert / update / etc.
*
* @return \mysqli
*/
public function getConnection()
{
$conn = new \mysqli(self::HOST, self::USERNAME, self::PASSWORD, self::DATABASENAME);

if (mysqli_connect_errno()) {
trigger_error("Problem with connecting to database.");
}

$conn->set_charset("utf8");
return $conn;
}

/**
* To get database results
* @param string $query
* @param string $paramType
* @param array $paramArray
* @return array
*/
public function select($query, $paramType="", $paramArray=array())
{
$stmt = $this->conn->prepare($query);

if(!empty($paramType) && !empty($paramArray)) {
$this->bindQueryParams($stmt, $paramType, $paramArray);
}

$stmt->execute();
$result = $stmt->get_result();

if ($result->num_rows > 0) {
while ($row = $result->fetch_assoc()) {
$resultset[] = $row;
}
}

if (! empty($resultset)) {
return $resultset;
}
}

/**
* To insert
* @param string $query
* @param string $paramType
* @param array $paramArray
* @return int
*/
public function insert($query, $paramType, $paramArray)
{
print $query;
$stmt = $this->conn->prepare($query);
$this->bindQueryParams($stmt, $paramType, $paramArray);
$stmt->execute();
$insertId = $stmt->insert_id;
return $insertId;
}

/**
* To execute query
* @param string $query
* @param string $paramType
* @param array $paramArray
*/
public function execute($query, $paramType="", $paramArray=array())
{
$stmt = $this->conn->prepare($query);

if(!empty($paramType) && !empty($paramArray)) {
$this->bindQueryParams($stmt, $paramType="", $paramArray=array());
}
$stmt->execute();
}

/**
* 1. Prepares parameter binding
* 2. Bind prameters to the sql statement
* @param string $stmt
* @param string $paramType
* @param array $paramArray
*/
public function bindQueryParams($stmt, $paramType, $paramArray=array())
{
$paramValueReference[] = & $paramType;
for ($i = 0; $i < count($paramArray); $i ++) {
$paramValueReference[] = & $paramArray[$i];
}
call_user_func_array(array(
$stmt,
'bind_param'
), $paramValueReference);
}

/**
* To get database results
* @param string $query
* @param string $paramType
* @param array $paramArray
* @return array
*/
public function numRows($query, $paramType="", $paramArray=array())
{
$stmt = $this->conn->prepare($query);

if(!empty($paramType) && !empty($paramArray)) {
$this->bindQueryParams($stmt, $paramType, $paramArray);
}

$stmt->execute();
$stmt->store_result();
$recordCount = $stmt->num_rows;
return $recordCount;
}
}

- Ez a fájl már további fájl meghívását nem követeli.
- Funkció az adatbázis kapcsolódásra, funkciók a select, insert SQL műveletekhez.

5. Index.php

<?php
session_start();
if(!empty($_SESSION["userId"])) {
require_once './view/dashboard.php';
} else {
require_once './view/login-form.php';
}
?>

Az Index lap egy egyszerű rövid példa a jelszóval védett lapok egyikére.
Ha nem üres $_SESSION["userId"] akkor a dashboardot hívja, ha nincs akkor a login formot.
Ezt el lehet játszani minden levédendő user protected lappal, így levédve a benne lévő tartalmat az illetéktelen felhasználók elől. Az User ID birtokában pedig különböző tartalmakat tudunk megjeleníteni a felhasználóknak.

Kommentben írjátok meg, hogy mennyire jó ez a megoldás, ez a folyamat az user beléptetésére, tudtok e jobbat, láttok e benne hibát stb... Köszönöm a figyelmet!

Hirdetés

3 pénzügyi döntés, amit minden kisvállalkozónak érdemes átgondolnia az év végéig

PR Ahogy az év vége közeledik, itt az ideje, hogy egy pillanatra megálljunk és áttekintsük vállalkozásunk pénzügyi helyzetét. Ne hagyjuk, hogy az év utolsó hónapjai elússzanak a sürgető feladatok és elfeledett határidők között!

Tovább a fórumba.