Webprogramozás
Horváth Győző
Egyetemi docens
1117 Budapest, Pázmány Péter sétány 1/c., 2.408-as szoba
Tel: (1) 372-2500/8469
horvath.gyozo@inf.elte.hu
JsonStorage
)include('jsonio.php');
include('jsonstorage.php');
include('movierepository.php');
include('userrepository.php');
$movieRepository = new MovieRepository();
$userRepository = new UserRepository();
$userId = $userRepository->insert(["username" => "q"]);
$movieRepository->insert(["title" => "Something", "user_id" => $userId]);
var_dump($movieRepository->all());
class UserRepository extends JsonStorage {
public function __construct() {
parent::__construct('./data/users.json');
}
}
class MovieRepository extends JsonStorage {
public function __construct() {
parent::__construct('./data/movies.json');
}
}
explode($elválasztó, $s)
: elemekre bontásimplode($elválasztó, $tömb)
: összefűzéssubstr($s, $kezdet, $hossz)
: részszövegltrim($s)
, rtrim($s)
, trim($s)
: fehérszóköz-eltávolítás.strstr($miben, $mit)
, strpos($miben, $mit)
, strrpos($miben, $mit)
: részszöveg keresésepreg_match($minta, $s)
: regkif illeszkedésedate($formátum)
: az aktuális idő kiírása a megadott formátumban.time()
: Unix idő visszaadása másodpercben.strtotime($s)
: szövegként megadott dátum Unix időbe átalakítása.getdate()
: dátuminformációk visszaadása tömbként.date_*
: dátummal kapcsolatos további függvényekDateTime
, DateInterval
, DatePeriod
osztályokdate("Y:m:d G:i:s"); // 2019:11:24 17:18:59
time(); // 1574615959 (s)
strtotime('2019-12-12'); // 1576108800
strtotime('2019-12-12T12:34:12'); // 1576154052
strtotime('now'); // 1574616109
strtotime('last day of next month'); // 1577813072
$d1 = new DateTime('+2 days');
$d2 = new DateTime('-2 weeks');
$interval = $d1->diff($d2);
$interval->format('%R%a days'); // -16 days
$d1 = new DateTimeImmutable('+2 days');
$d2 = $d1->add(new DateInterval('P2Y4DT6H8M'));
$interval = $d2->diff($d1);
$interval->format('%R%a days'); // -735 days
header()
header('Location: index.php');
function redirect($page) {
header("Location: index.php?{$page}");
}
include($fájlnév)
– hiba esetén warning
gal továbbmegyinclude_once($fájlnév)
require($fájlnév)
– hiba esetén hibával megállrequire_once($fájlnév)
Mindegyik kliens ugyanazon az adaton osztozkodik
Kliensenkénti adattárolás
Tároljuk egy számláló értékét felhasználónként, és minden kérésnél növeljük a számláló értékét eggyel!
session_url.php?counter=1
<?php
print_r($_GET);
$counter = $_GET['counter'] ?? 0;
$counter += 1;
var_dump($counter);
?>
<a href="session_url.php?counter=<?php echo $counter; ?>">Increment</a>
→ űrlap rejtett mezője
<input type="hidden" name="counter" value="4">
<?php
print_r($_POST);
$counter = $_POST['counter'] ?? 0;
$counter += 1;
var_dump($counter);
?>
<form action="" method="post">
<input type="hidden" name="counter" value="<?= $counter ?>">
<button>Increment</button>
</form>
<a href="session_hidden.php">Increment (not working)</a>
HTTP kérés és PHP ($_COOKIES
)
Cookie: név1=érték1; név2=érték2; név3=érték3
HTTP válasz és PHP:
Set-Cookie: név=érték[; expires=dátum][; domain=domain][; path=path][; secure]
// Általános formája
$siker = setcookie($név[, $érték [, $expires = 0 [, $path [, $domain [, $secure = false]]]]]);
// Néhány példa
setcookie('alma', 'piros');
setcookie('körte', 'sárga', time() + 60); //lejárat 60 mp múlva
<?php
var_dump($_COOKIE);
$counter = $_COOKIE['counter'] ?? 0;
$counter += 1;
setcookie('counter', $counter);
var_dump($counter);
?>
<a href="session_cookie.php">Increment</a>
Több kliens
Egy kliens különböző kérései
$_SESSION
session_start()
session_destroy()
<?php
session_start();
var_dump($_SESSION);
$counter = $_SESSION['counter'] ?? 0;
$counter += 1;
$_SESSION['counter'] = $counter;
var_dump($counter);
?>
<a href="session_php.php">Increment</a>
session_start();
$_SESSION = [];
session_destroy();
.htaccess
, .htpasswd
class UserRepository extends JsonStorage {
public function __construct() {
parent::__construct('./data/users.json');
}
}
Űrlap
<?php if (isset($errors['global'])) : ?>
<p><span class="error"><?= $errors['global'] ?></span></p>
<?php endif; ?>
<form action="" method="post">
Username:
<input type="text" name="username">
<?php if (isset($errors['username'])) : ?>
<span class="error"><?= $errors['username'] ?></span>
<?php endif; ?>
<br>
Password:
<input type="password" name="password">
<?php if (isset($errors['password'])) : ?>
<span class="error"><?= $errors['password'] ?></span>
<?php endif; ?>
<br>
<button>Register</button>
</form>
$userRepository = new UserRepository();
function validate($input, &$data, &$errors, $userRepository) {
// username, password not empty
// ...
if (count($errors) === 0) {
if (user_exists($userRepository, $input['username'])) {
$errors['global'] = "User already exists";
}
}
return count($errors) === 0;
}
function user_exists($userRepository, $username) {
$users = $userRepository->filter(function ($user) use ($username) {
return $user['username'] === $username;
});
return count($users) >= 1;
}
function add_user($userRepository, $user) {
$user['password'] = password_hash($user['password'], PASSWORD_DEFAULT);
return $userRepository->insert($user);
}
$data = [];
$errors = [];
if ($_POST) {
if (validate($_POST, $data, $errors, $userRepository)) {
add_user($userRepository, $data);
header('Location: login.php');
exit();
}
}
Űrlap
<?php if (isset($errors['global'])) : ?>
<p><span class="error"><?= $errors['global'] ?></span></p>
<?php endif; ?>
<form action="" method="post">
Username:
<input type="text" name="username">
<?php if (isset($errors['username'])) : ?>
<span class="error"><?= $errors['username'] ?></span>
<?php endif; ?>
<br>
Password:
<input type="password" name="password">
<?php if (isset($errors['password'])) : ?>
<span class="error"><?= $errors['password'] ?></span>
<?php endif; ?>
<br>
<button>Login</button>
</form>
function validate($input, &$data, &$errors, $userRepository) {
// username, password not empty
// ...
if (count($errors) === 0) {
if (!check_user($userRepository, $input['username'], $input['password'])) {
$errors['global'] = "Login error";
}
}
return count($errors) === 0;
}
function check_user($userRepository, $username, $password) {
$users = $userRepository->filter(function ($user) use ($username) {
return $user['username'] === $username;
});
if (count($users) === 1) {
$user = array_values($users)[0];
return password_verify($password, $user["password"])
? $user
: false;
}
return false;
}
function login($user) {
$_SESSION["user"] = $user;
}
session_start();
$userRepository = new UserRepository();
$data = [];
$errors = [];
if ($_POST) {
if (validate($_POST, $data, $errors, $auth)) {
login($data);
header('Location: login.php');
exit();
}
}
session_start();
function is_authenticated() {
return isset($_SESSION["user"]);
}
function logout() {
unset($_SESSION["user"]);
}
Egyszerűsített
session_start();
if (!is_authenticated()) {
header("Location: login.php");
exit();
}
class Auth {
private $userRepository;
public function __construct() {
$this->userRepository = new UserRepository();
}
public function register($user) {
$user['password'] = password_hash($user['password'], PASSWORD_DEFAULT);
return $this->userRepository->insert($user);
}
public function user_exists($username) {
$users = $this->userRepository->filter(function ($user) use ($username) {
return $user['username'] === $username;
});
return count($users) >= 1;
}
public function login($user) {
$_SESSION["user"] = $user;
}
public function check_credentials($username, $password) {
$users = $this->userRepository->filter(function ($user) use ($username) {
return $user['username'] === $username;
});
if (count($users) === 1) {
$user = array_values($users)[0];
return password_verify($password, $user["password"])
? $user
: false;
}
return false;
}
public function is_authenticated() {
return isset($_SESSION["user"]);
}
public function logout() {
unset($_SESSION["user"]);
}
}
Regisztráció
function validate($input, &$data, &$errors, $auth) {
// ...
if (count($errors) === 0) {
if ($auth->user_exists($input['username'])) {
$errors['global'] = "User already exists";
}
}
return count($errors) === 0;
}
$auth = new Auth();
$data = [];
$errors = [];
if ($_POST) {
if (validate($_POST, $data, $errors, $auth)) {
$auth->register($data);
header('Location: login.php');
exit();
}
}
Beléptetés
function validate($input, &$data, &$errors, $auth) {
// ...
if (count($errors) === 0) {
if (!$auth->check_credentials($input['username'], $input['password'])) {
$errors['global'] = "Login error";
}
}
return count($errors) === 0;
}
session_start();
$auth = new Auth();
$data = [];
$errors = [];
if ($_POST) {
if (validate($_POST, $data, $errors, $auth)) {
$auth->login($data);
header('Location: login.php');
exit();
}
}
if ($_POST) {
if (validate($_POST, $data, $errors)) {
$todoRepository->insert([
'title' => $data['title'],
]);
}
}
$todos = $todoRepository->all();
Ötlet: POST konvertálása GET-té átirányítással
if ($_POST) {
if (validate($_POST, $data, $errors)) {
$todoRepository->insert([
'title' => $data['title'],
]);
header('Location: todo.php');
exit();
}
}
$todos = $todoRepository->all();
“Laza” PRG
function validate($input, &$data, &$errors) {
// ...
}
$todoRepository = new TodoRepository();
$data = [];
$errors = [];
if ($_POST) {
if (validate($_POST, $data, $errors)) {
$todoRepository->insert([
'title' => $data['title'],
]);
header('Location: todo.php');
exit();
}
}
$todos = $todoRepository->all();
?>
<form action="" method="post">
Movie: <input type="text" name="title">
<?php if (isset($errors['title'])) : ?>
<span class="error"><?= $errors['title'] ?></span>
<?php endif ?>
<button>Add todo</button>
</form>
<ul>
<?php foreach($todos as $todo) : ?>
<li><?= $todo['title'] ?></li>
<?php endforeach ?>
</ul>
“Extrém” PRG: oldalt megjeleníteni csak GET metódussal lehet!
Olyan adatok, amelyek csak egy kérés idejéig élnek a munkamenetben
(Nálunk: amíg ki nem vesszük őket)
function set_flash_data($key, $value) {
$_SESSION[$key] = $value;
}
function get_flash_data($key) {
$value = $_SESSION[$key] ?? null;
unset($_SESSION[$key]);
return $value;
}
session_start();
$todoRepository = new TodoRepository();
$data = [];
$errors = get_flash_data('errors') ?? [];
$input = get_flash_data('input') ?? [];
if ($_POST) {
if (validate($_POST, $data, $errors)) {
$todoRepository->insert([
'title' => $data['title'],
]);
header('Location: todo.php');
exit();
} else {
set_flash_data('errors', $errors);
set_flash_data('input', $_POST);
header('Location: todo.php');
exit();
}
}
$todos = $todoRepository->all();
?>
<form action="" method="post">
Todo:
<input type="text" name="title" value="<?= $input['title'] ?? '' ?>">
<?php if (isset($errors['title'])) : ?>
<span class="error"><?= $errors['title'] ?></span>
<?php endif; ?>
<button>Add todo</button>
</form>
<ul>
<?php foreach($todos as $todo) : ?>
<li><?= $todo['title'] ?></li>
<?php endforeach ?>
</ul>
<?php var_dump($errors) ?>
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<button>Upload</button>
</form>
$errors = [];
if ($_FILES) {
if (array_key_exists('file', $_FILES) &&
$_FILES['file']['error'] == 0) {
$from = $_FILES['file']['tmp_name'];
$to = 'files\\' . $_FILES['file']['name'];
move_uploaded_file($from, $to);
} else {
$errors[] = 'Error during upload!';
}
}
Array
(
[file] => Array
(
[name] => Desert_small.jpg
[type] => image/jpeg
[tmp_name] => C:\eltescorm\tmp\php1750.tmp
[error] => 0
[size] => 18218
)
)
<ul>
<?php foreach($files as $file) : ?>
<li><?= $file ?></li>
<?php endforeach ?>
</ul>
function getFiles($dir) {
$fajls = [];
$d = opendir($dir);
while (($f = readdir($d)) !== false) {
$fajls[] = $f;
}
closedir($d);
return $fajls;
}
$files = getFiles('files\\');
php -S localhost:3000
session_start()
, $_SESSION