PHPPOT User Login működése
írta: btz, 4 éve
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!