Webprogramozás

Szerveroldali webprogramozás, HTTP, PHP, kimenet generálá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

Szerveroldali dinamikus webprogramozás

Világháló

A világháló (angolul World Wide Web, röviden web) egy olyan információs rendszer, amelyben

  • dokumentumokat és más erőforrásokat
  • egységes címmel azonosítunk,
  • ezeket hiperhivatkozásokkal kötjük össze,
  • elérhetőségüket internetre kötött szerverek segítségével biztosítjuk,
  • megtekintésük pedig speciális kliensprogramokban, böngészőkben történik.

Web komponensei, szabványai

  • HTML (dokumentumok, hiperhivatkozások)
  • URL (erőforrások egységes címe)
  • webszerver (erőforrások elérhetővé tétele)
  • webkliens, webböngésző (erőforrások megjelenítése)
  • HTTP (kliens-szerver kommunikáció)

Webes szabványok

Kliensoldali webprogramozás

  • Kliens-szerver architektúra
  • Statikus kliens
  • Dinamikus kliens
  • Nem érdekes a szerver, csak az onnan érkező tartalom
  • Nem is kell szerver, dolgozhatunk lokálisan
  • Programozás a böngészőben
  • JavaScript, DOM, stb.

Kliens-szerver architektúra

Több komponens

  • kliens
  • szerver
  • HTTP (kommunikáció)

Kliens-szerver architektúra

Térben és időben elválhatnak

Statikus szerveroldali tartalom

  • Kérés pillanatában a szerveren megtalálható az a tartalom, amely leküldésre kerül a válaszban
  • Fájlkiszolgálás
  • Kiterjesztés alapján
    • .html
    • .jpg, .png, .gif
    • .css
    • .js

Dinamikus szerveroldali tartalom

A leküldendő tartalmat egy program állítja elő.

Architektúrák

Szerveroldali webprogramozás

  • Nem egyszerű fájlkiszolgálás
  • Indítás
    • cgi-bin könyvtár
    • kiterjesztés (pl. .cgi, .php)
  • Program
    • bármilyen
    • bináris (c++, pas)
    • szkript (php, python, ruby)

Szerveroldali webprogramozás

  • Program célja, kimenete
    • HTML generálás (általában)
    • HTTP protokoll betartásával
  • Program helyességét a generált tartalom, a megkapott oldal forrása alapján ellenőrizhetjük.

URL, HTTP, CGI

URL

URL az MDN-en

HTTP protokoll

  • Kérés-válasz alapú protokoll a kliens és szerver között
  • Mindig a kliens kezdeményez
  • Kliens: kérés
    • kérést küld a 80-as TCP portra
    • jellemzően böngésző (hivatkozások, formok)
  • Szerver: válasz
  • TCP/IP réteg feletti protokoll
  • Szabvány

HTTP üzenetstruktúra

HTTP áttekintése, HTTP üzenetstruktúra, HTTP referencia

HTTP kérés

METÓDUS ERŐFORRÁS VERZIÓ
FEJLÉC: ÉRTÉK
FEJLÉC: ÉRTÉK
FEJLÉC: ÉRTÉK

ÜZENETTEST (opcionális)
  • Metódusok
    • GET: Megadott erőforrás letöltése
    • POST: Feldolgozandó adat felküldése
    • HEAD: Ld. GET, de csak a válasz fejléceket kéri le
    • PUT: Feltölt a megadott erőforrást
    • DELETE: Törli a megadott erőforrást
    • TRACE: Visszaküldi a kapott kérést
    • OPTIONS: A szerver által támogatott HTTP metódusok listája
    • CONNECT: Kérést transzparens tunnellé alakítja (SSL)

HTTP kérés példa

GET /index.html HTTP/1.1
Host: webprogramozas.inf.elte.hu
GET / HTTP/1.1
Host: webprogramozas.inf.elte.hu
User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:19.0) Gecko/20100101 Firefox/19.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: hu-hu,hu;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Cookie: __utma=159741371.1255432553.1308299517.1308299517.1308299517.1; __utma=32143338.2145495546.1326532899.1361177845.1362134456.25; __utmz=32143338.1361177845.24.12.utmcsr=google|utmccn=(organic)|utmcmd=organic|utmctr=(not%20provided)
Connection: keep-alive

HTTP válasz

VERZIÓ STÁTUSZKÓD INDOKLÁS
FEJLÉC: ÉRTÉK
FEJLÉC: ÉRTÉK
FEJLÉC: ÉRTÉK

ÜZENETTEST (opcionális)
  • Státuszkód
    • 1xx: Informatív (kérés megkapva)
    • 2xx: Siker (kérés megérkezett, elfogadva)
      • 200 OK
    • 3xx: Átirányítás (további műveletre van szükség)
    • 4xx: Kliens hiba (kérés hibás, nem teljesíthető)
      • 404 Not found
    • 5xx: Szerver hiba (nem tudja teljesíteni a kérést)
      • 500 Internal Server Error

HTTP válasz példa

HTTP/1.1 200 OK
Date: Wed, 03 Apr 2013 07:11:56 GMT
Server: Apache/2.2.10 (Linux/SUSE)
Last-Modified: Wed, 20 Feb 2013 08:39:44 GMT
ETag: "fe8438-6d6-4d623e65e9400"
Accept-Ranges: bytes
Content-Length: 1750
Content-Type: text/html

<!DOCTYPE html>
<html>
    ...
</html>

HTTP eszközök

Webfejlesztési eszköztár Hálózat füle

DEMO

Common Gateway Interface (CGI)

Azt határozza meg, hogy egy webszerver hogyan indíthat el egy programot és milyen módon cserél adatot vele.

  • Indítás: program futtatása
  • Adatok
    • környezeti változók
    • standard I/O
  • Program eredménye
    • standard kimeneten

Példa – C++

#include <iostream>
using namespace std;
int main()
{
    cout << "Content-Type: text/html" << endl;
    cout << endl;

    cout << "<!doctype html>" << endl;
    cout << "<html>" << endl;
    cout << "    <head>" << endl;
    cout << "        <meta charset=\"utf-8\">" << endl;
    cout << "        <title></title>" << endl;
    cout << "    </head>" << endl;
    cout << "    <body>" << endl;
    cout << "        <p>Hello vilag!</p>" << endl;
    cout << "    </body>" << endl;
    cout << "</html>" << endl;

    return 0;
}

Példa – C++

  • Egyszerűen futtatva (a program kimenete)
Content-Type: text/html

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
    </head>
    <body>
        <p>Hello vilag!</p>
    </body>
</html>
  • Böngészőből futtatva
  • http://localhost/cgi-bin/hello.exe

Példa – C++

int main()
{
    cout << "Content-Type: text/html" << endl;
    cout << endl;

    cout << "<!doctype html>" << endl;
    cout << "<html>" << endl;
    cout << "    <head>" << endl;
    cout << "        <meta charset=\"utf-8\">" << endl;
    cout << "        <title></title>" << endl;
    cout << "    </head>" << endl;
    cout << "    <body>" << endl;

    for (int i = 1; i<=10; i++) {
        cout << "        <p>Hello vilag!</p>" << endl;
    }

    cout << "    </body>" << endl;
    cout << "</html>" << endl;
    return 0;
}

Példa – C++

Content-Type: text/html

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
    </head>
    <body>
        <p>Hello vilag!</p>
        <p>Hello vilag!</p>
        <p>Hello vilag!</p>
        <p>Hello vilag!</p>
        <p>Hello vilag!</p>
        <p>Hello vilag!</p>
        <p>Hello vilag!</p>
        <p>Hello vilag!</p>
        <p>Hello vilag!</p>
        <p>Hello vilag!</p>
    </body>
</html>

Példa – C++

cout << "    <ul>" << endl;
ifstream f("lista.txt");
while (!f.eof()) {
    string sor;
    getline(f, sor);
    cout << "        <li>" << sor << "</li>" << endl;
}
f.close();
cout << "    <ul>" << endl;
alma
korte
szilva

DEMO

PHP

PHP a webprogramozásban

http://szerver/peldak/pelda.php

PHP

  • PHP
    • Personal Home Page
    • PHP: Hypertext Preprocesszor
  • Dokumentáció
    • nyelvi és függvényreferencia, kódolási tanácsok
  • Jellemzői
    • nyílt forráskódú
    • általános célú
    • szkriptnyelv
    • HTML-be ágyazható

PHP használata

  • Szerveroldali dinamikus webprogramozás
    • weboldalak generálása
    http://szerver/peldak/pelda.php
  • CLI – Command Line Interface
    • PHP szkriptek parancssori futtatása
    > php pelda.php

JavaScript vs PHP

//declaration 
const x=[1,3,5,7,9]
let s
//process 
s=0
for(let i=0; i<x.length; i++) {
    s=s+x[i]
}
//write output 
console.log('Sum: ', s)
//declaration 
const $x=[1,3,5,7,9];

//process 
$s=0;
for($i=0; $i<count($x); $i++) {
    $s=$s+$x[$i];
}
//write output 
echo 'Sum: ', $s;

Változók neve $ jellel kezdődik.

PHP mint programozási nyelv

  • Dinamikusan típusos
    • változók típusa a benne tárolt értéktől függ
    • automatikus típuskonverziók
  • Értelmezett
  • Szkriptnyelv
  • Részben case sensitive
  • Utasítások végén ;
  • Többparadigmás nyelv
    • procedurális
    • OOP
    • funkcionális
  • C alapú szintaxis
  • Nincs főprogram
  • Hasonló a JavaScripthez
    • szintaxis
    • vezérlési szerkezetek, operátorok
    • viselkedés

Megjegyzések

// egysoros megjegyzés

#  Perl szintaktikájú egysoros megjegyzés

/*
többsoros
megjegyzés
*/

Típusok

  • Egyszerű típusok
    • logikai (bool)
    • egész (int)
    • lebegőpontos (float)
    • szöveg (string)
  • Összetett típusok
    • tömb (array)
    • objektum (object)
    • függvény (callable)
  • Speciális típusok
    • erőforrás
    • NULL

Literálok

//Logikai
true
false

//Egész
12     //decimális
-34
0123   //oktális
0x0F   //hexadecimális
0b0101 //bináris

//Lebegőpontos
3.1415
5.6e12
-7E-2
$a = 12;
// Aposztróf: nem helyettesít be
'alma\t${a} alma' // alma\t{$a} alma
'Több
sor is lehet benne'

// Macskaköröm: behelyettesít
"alma\t${a} alma" // alma   12 alma
"Ez egy
több soros szöveg"

// Heredoc: behelyettesít
<<<EOT
Több soros {$a}
szöveg
EOT

// Nowdoc: nem helyettesít be
<<<'EOT'
Ez is lehet {$a}
több soros.
EOT

Típusokkal kapcsolatos fontos függvények

  • Típusbeállítás
    • típuskényszerítés (int)$a
    • settype()
$a = '12';
gettype($a);  // 'string'
$a = (int)$a; // cast to int
gettype($a);  // 'integer'
  • Típuslekérdezés
    • gettype()
    • is_integer()
    • is_float()
    • is_numeric()
    • is_string()
    • is_bool()
  • Speciális függvények
    • isset()
    • is_null()
    • empty()

Operátorok

  • Referencia
  • Kb. ugyanaz, mint JavaScriptben
  • Különbség
    • + kizárólag összeadás
    • . szövegösszefűzés
  • Újdonság
    • $a <=> $b: összehasonlítás (-1, 0, 1)
    • $a ?? $b ?? $c: az első nem NULL
    • $a ?: $b: megegyezik $a ? $a : $b
"piros " + "alma"; // 0
"piros " . "alma"; // "piros alma"
1 <=> 1; // 0
1 <=> 2; // -1
2 <=> 1; // 1

NULL ?? 1 ?? 2; // 1

false ?: 'alma'; // 'alma'

Vezérlési szerkezetek

Ld. C++ vagy JavaScript

Továbbá:

foreach ($tomb as $ertek) {
  utasítások;
}

foreach ($tomb as $kulcs => $ertek) {
  utasítások;
}

Függvények

Függvények

// C++
int add(int a, int b) {
  return a + b;
}
// JavaScript
function add(a, b) {
  return a + b;
}
function add($a, $b) {
  return $a + $b;
}
// or
declare(strict_types=1);
function add(int $a, int $b): int {
  return $a + $b;
}

Függvények

// Default value
function greet($name = 'somebody') {
  return "Hello ${name}!";
}
greet();    // "Hello somebody!"

// Pass by reference
$szam = 41;
function novel(&$szam) {
  $szam += 1;
}
novel($szam);
echo $szam;    // 42

// Anonymous function literal
$add = function ($a, $b) {
  return $a + $b;
}
echo $add(10, 32); // 42

// Accessing global scope
$globus = 'Föld';
function zartFuggveny() {
  global $globus;
  echo "Gyönyörű a {$globus}!";
}
// or
function zartFuggveny() {
  echo "Gyönyörű a {$GLOBALS['globus']}!";
}
// or, accessing just the parent scope
$zartFuggveny = function () use ($globus) {
  echo "Gyönyörű a {$globus}!";
}

Típusannotációk

// Szigorú típusosság
declare(strict_types=1);

function add(int $a, int $b): int {
    return $a + $b;
}

var_dump(add(1, 2));
var_dump(add(1.5, 2.5)); // Hibát dob

// Gyenge típusosságnál automatikus konverziók történnek
function sum(int $a, int $b) {
    return $a + $b;
}

var_dump(sum(1.5, 2.5)); // 3

Tömb

Tömb

  • Gyűjtemények általános objektuma
  • Asszociatív tömb: kulcs-érték párokból áll
    • kulcs: integer vagy string
    • érték: bármilyen típusú lehet
  • Összetett adatszerkezet megvalósítása
    • rekord
    • indexelt tömb
    • asszociatív tömb
    • többdimenziós tömb
    • fa, sor, verem, stb.

Tömb

//Üres tömb
$arr = array();
//vagy
$arr = [];

//Indexelt tömb létrehozása
$arr = array('alma', 'korte', 'szilva');
//vagy
$arr = ['alma', 'korte', 'szilva'];

//A tömb hosszának lekérdezése
count($arr);    // => 3

//Hivatkozás
$arr[0]; //'alma'

//Elemek módosítás
$arr[1] = 13;
$arr[1];        //13

//Új elem beszúrása a tömb végére
$arr[] = 'új';

//Elem törlése
unset($arr[1]);

// Mátrix: tömbök tömbje
$matrix = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9],
);

// Index beállítása
$other = [ 1 => 'alma', 'korte', 'szilva'];

Asszociatív tömb

// Asszociatív tömb
$asszTomb = array(
  'alma'    => 'piros',
  'korte'   => 'sarga',
  'szilva'  => 'kek',
);

// Hivatkozás
$asszTomb['alma']; //piros

Tömbök bejárása

  • foreach
  • reset(), next(), prev(), current(), key(), each()
$gyumolcsok = array(
    'alma'      => 'piros',
    'korte'     => 'sárga',
    'szilva'    => 'kék',
);

//foreach
foreach ($gyumolcsok as $gyumolcs => $szin) {
    echo "{$szin} {$gyumolcs}\n";
}
/*
piros alma
sárga korte
kék szilva
*/

//tömbműveletekkel
reset($gyumolcsok);
while (list($kulcs, $ertek) = each($gyumolcsok)) {
  echo "{$ertek} {$kulcs}\n";
}

Összegzés tétel

function osszegzes($tomb) {
  $s = 0;
  foreach ($tomb as $szam) {
    $s = $s + $szam;
  }
  return $s;
}

$x = [1, 3, -2, 8];
$result = osszegzes($x);

Eldöntés tétel

function eldontes(array $tomb, callable $fn): bool {
  $i = 0;
  while ($i < count($tomb) && !$fn($tomb[$i])) {
    $i += 1;
  }
  return $i < count($tomb);
}
// or
function eldontes(array $tomb, callable $fn): bool {
  reset($tomb);
  while ((list(, $e) = each($tomb)) && !$fn($e)) { }
  return $e !== NULL;
}

$x = [1, 3, -2, 8];
$result = eldontes($x, function($e) { return $e < 0; });

Adatszerkezetek

Tömb

$kutyuk = [
  'telefon',
  'fülhallgató',
  'pendrive',
  'e-könyv olvasó',
];

Rekord

$hallgato = [
  'nev'     => 'Mosolygó Napsugár',
  'neptun'  => 'kod123',
  'szak'    => 'Informatika BSc',
];

Adatszerkezetek

// Rekordok tömbje
$hallgatok = [
  [
    'nev'     => 'Mosolygó Napsugár',
    'neptun'  => 'kod123',
    'szak'    => 'Informatika BSc',
  ],
  [
    'nev'     => 'Kék Ibolya',
    'neptun'  => 'kod456',
    'szak'    => 'Informatika BSc',
  ],
];

Adatszerkezetek

// Rekordok tömbje
$hallgatok = [
  [
    'nev'    => 'Mosolygó Napsugár',
    'neptun'  => 'kod123',
    'szak'    => 'Informatika BSc',
    'targyak'  => [
      'Programozás',
      'Webfejlesztés 2.',
      'Számítógépes alapismeretek',
    ],
  ],
  [
    'nev'    => 'Kék Ibolya',
    'neptun'  => 'kod456',
    'szak'    => 'Informatika BSc',
    'targyak'  => [
      'Programozás',
      'Webfejlesztés 2.',
      'Diszkrét matematika',
      'Testnevelés',
    ],
  ],
];

Osztályok

Klasszikus OOP

Osztályok létrehozása

class Gyerek {
  public $kor;
  public $nev;

  public function __construct($nev, $kor) {
    $this->nev = $nev;
    $this->kor = $kor;
  }

  public function bemutatkozik() {
    echo "A nevem: {$this->nev}\n";
  }
}

Objektum példányosítása

$zsofi = new Gyerek('Zsófia', 7);
$matyi = new Gyerek('Mátyás', 2);

$zsofi->bemutatkozik();
$matyi->bemutatkozik();

$zsofi->nev = 'Zsozsó';
$zsofi->bemutatkozik();
A nevem: Zsófia
A nevem: Mátyás
A nevem: Zsozsó

Getterek és setterek

class Gyerek {
  private $kor;
  private $nev;
  public function __construct($nev, $kor) {
    $this->nev = $nev;
    $this->kor = $kor;
  }
  public function getNev() {
    return $this->nev;
  }
  public function setNev($value) {
    $this->nev = $value;
  }  
  public function getKor() {
    return $this->kor;
  }
  public function setKor($value) {
    $this->kor = $value;
  }  
  public function bemutatkozik() { /*...*/ }
}
$sari = new Gyerek('Sári', 7);
$sari->bemutatkozik();

$sari->setNev('Sarah');
$sari->bemutatkozik();
A nevem: Sári
A nevem: Sarah

Öröklés

class Ovodas extends Gyerek {
  private $jel;

  public function __construct($nev, $kor, $jel) {
    parent::__construct($nev, $kor);
    $this->jel = $jel;
  }

  public function getJel() {
    return $this->jel;
  }

  public function setJel($value) {
    $this->jel = $value;
  }

  public function miAJeled() {
    echo "A jelem: {$this->jel}\n";
  }
}
$zsofi = new Gyerek('Zsófia',7);
$zsofi->bemutatkozik();

$david = new Ovodas('Dávid',4,'perec');
$david->bemutatkozik();
$david->miAJeled();
A nevem: Zsófia
A nevem: Dávid
A jelem: perec

További OOP tulajdonságok

  • osztályok (class),
  • láthatóság szabályozása (public, protected, private),
  • konstruktorok, destruktorok (__construct, __destruct),
  • statikus adattagok és metódusok (static),
  • absztrakt osztályok (abstract),
  • interfészek (interface),
  • öröklés (extends),
  • mágikus metódusok (__get, __set, stb)
  • stb.

Kimenet generálása

PHP fájl

  • .php kiterjesztésű fájl
  • <?php és ?> tagek közötti rész kerül értelmezésre
  • Több PHP blokk is lehet
  • Ezeken kívüli rész automatikusan kiírásra kerül
  • Kiírás PHP blokkon belül
    • echo
    • var_dump() (debugolás)
<?php
//PHP kód
?>
Szöveg
<?php
//PHP kód
?>
<p>Bekezdés</p>
<?php
$nev = 'Alma';
echo "<p>{$nev}</p>";
?>
<p>Bekezdés</p>

Elvek

  • Cél: HTML előállítása programmal
  • PHP fájl logikai részei
    • beolvasás
    • feldolgozás: adat előkészítése
    • kiírás: HTML előállítása az adatból
  • Adat és nézet szétválasztása
  • Statikus prototípus → Dinamikus sablon
  • Csak a dinamikus részekhez használjunk PHP-t!
  • PHP alternatív szintaxisa (sablonnyelv)

Példa

Adott hibaüzenetek sorozata. Jelenítsük ezt meg felsorolásként!

Adat

$errors = [
  'error1',
  'error2',
  'error3',
];

Statikus prototípus

<ul>
  <li>error1</li>
  <li>error2</li>
  <li>error3</li>
</ul>

Dinamikus sablon

echo "<ul>";
foreach($errors as $error) {
  echo "  <li>${error}</li>";
}
echo "</ul>";
<ul>
<?php foreach($errors as $error) { ?>
    <li><?php echo $error ?></li>
<?php } ?>
</ul>
<ul>
<?php foreach($errors as $error) : ?>
    <li><?= $error ?></li>
<?php endforeach ?>
</ul>

Alternatív szintaxis (sablonnyelv)

<!-- Kiírás -->
<?= $valtozo ?>

<!-- Elágazás -->
<?php if (felt) : ?>
    HTML sablon kód
<?php else : ?>
    HTML sablon kód
<?php endif ?>

<!-- Ciklus -->
<?php foreach($arr as $e) : ?>
    HTML sablon kód
<?php endforeach ?>

Megjegyzendő

  • Cél: olyan programot írni, amely HTML kódot állít elő
  • HTTP, CGI
  • PHP hasonlít a JavaScripthez, csak $ jeleket kell írni
  • Kimenet generálásakor csak a dinamikus tartalomhoz használunk PHP-t