Webfejlesztés 2.

Adattárolás, fájlkezelés

Horváth Győző
Egyetemi adjunktus
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

Ismétlés

Ismétlés

Dinamikus szerveroldali webprogramozás: program (PHP) állítja elő a tartalmat (HTML)

  • Output
    • statikus prototípus
    • dinamikus sablon
  • Input
    • kliens: link, űrlap
    • PHP: $_GET, $_POST
  • Űrlapfeldolgozás
    • Beolvasás, ellenőrzés ($_POST, $_GET)
    • Adatok (nincsen: $_POST, $_GET, HTML)
    • Kimenet (HTML)

Adatok a klienstől PHP-ig

Szerverprogram bemeneti adatai

Adattárolás

Közös adat mint erőforrás megosztása

Szkriptbeli változók

  • Élettartamuk a szkript futása
  • Utána megszűnnek
if (isset($szamlalo)) {
  $szamlalo += 1;
} else {
  $szamlalo = 0;
}
var_dump($szamlalo);

Külső adattárolás

Fájl

  • bármikor elérhető, nincs szükség plusz szoftverekre
  • könnyen értelmezhető (ember, program)
  • könnyen használható
  • viszonylag kis méretű

Adatbázis

  • biztonságos
  • típusos adatok
  • bonyolult adatszerkezetek
  • összetett kereshetőség
  • fejlett konkurenciakezelés

Fájlkezelés PHP-ban

Fájlműveletek PHP-ban

  • PHP-ban van lehetőség fájlok használatára (írás, olvasás, stb)
  • Mint a legtöbb programozási nyelvben
  • Csak a szerver helyi fájljai érhetők el
  • Sokféle nyelvi lehetőség
  • Tipikus folyamat
    • megnyitás
    • feldolgozás
    • bezárás

Alacsony szintű általános fájlműveletek

  • $f = fopen($fájlnév, $mód)
    • fájl vagy URL megnyitása
    • $f: logikai fájlkezelő
    • $mód: megnyitás módját
  • feof($f)
    • fájl vége?
  • fclose($f)
    • fájl bezárása
// $mód
r (csak olvasás)
r+ (olvasás, írás)
w (csak írás, üres fájl)
w+ (olvasás, írás, üres fájl)
a (hozzáfűzés)
a+ (hozzáfűzés, olvasás)
x (csak írás, üres fájl, ha létezik a fájl, akkor hiba)
x+ (olvasás, írás, üres fájl, ha létezik, akkor hiba)
c (csak írás, ha létezik, akkor elejére áll)
c+ (írás, olvasás, ha létezik, elejére áll)

Alacsony szintű beolvasás/kiírás

  • Beolvasás
    • fread($f, $hossz)
      • $hossz byte beolvasása
    • fscanf($f, $formátum)
      • formátum szerinti beolv.
    • fgets($f[, $hossz])
      • sor beolvasása
    • fgetcsv($f, $hossz[, $elv])
      • CSV sor beolvasása
  • Kiírás
    • fwrite($f, $s)
      • $s kiírása
    • fputs($f, $s)
      • ld. fwrite()
    • fprintf($f, $formátum, $változók)
      • formázott kiírás
    • fputcsv($f, $tömb[, $elv])
      • CSV sor kiírása

Magas szintű beolvasás/kiírás

  • Beolvasás
    • $tömb = file($fájlnév[, módosítók])
      • fájl soronként a tömbbe
    • $s = file_get_contents($fájlnév)
      • egész fájl szövegként
    • readfile($fájlnév)
      • fájl kimenetre írása (pl. képek kiírása)
    • fpassthru($f)
      • megnyitott fájl maradék részének kimenetre írása (pl. képek)
  • Kiírás
    • file_put_contents($fájlnév, $s)
      • szöveg fájlba írása

További fájlműveletek

  • mkdir($útvonal)
    • könyvtár létrehozása
  • rmdir($könyvtárnév)
    • könyvtár törlése
  • copy($forrás, $cél)
    • másolás
  • rename($mit, $mire)
    • átnevezés, mozgatás
  • unlink($fájlnév)
    • törlés
  • is_dir($fájlnév)
  • is_file($fájlnév)
  • is_readable($fájlnév)
  • is_writable($fájlnév)
  • is_link($fájlnév)
  • is_executable($fájlnév)

További fájlműveletek

  • basename($útvonal)
    • fájlnevet adja vissza
  • chown($fájl, $user)
  • chmod($fájl, $mód)
  • chgrp($fájl, $group)
  • stat($fájl)
    • fájl adatai tömbben
  • fseek($f, $offset)
    • fájlmutató mozgatása

Hibakezelés

  • Hiba esetén → hamis visszatérési érték
  • @ operátor: hibaüzenet kiírásának elnyomása
$f = @fopen('nem_letezik.txt', 'r');
if ($f) {
  /* ... */
  fclose($f);
}

Fájlszerkezet-vezérelt tárolás

Használati esetek

  • Fájl szerkezete kötött
    • mikroformátum
    • áttekinthetőség
    • interoperabilitás
  • → Magas és alacsony szintű fájlműveletek

1. példa

Adott filmcímek listája egy fájlban, soronként egy filmmel. Olvassuk ezt be egy tömbbe!

$filmek = file('lista.txt', 
               FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
/*
Array
(
  [0] => A hobbit
  [1] => A Gyűrűk Ura
  [2] => Út a vadonba
  [3] => Passió
)
*/
A hobbit
A Gyűrűk Ura
Út a vadonba
Passió
    

1. példa – hibaellenőrzés

// Required
$filmek = @file('lista_.txt', 
                FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) 
          or die('Nincs meg a fájl');

vagy

// Default data
$filmek = @file('lista_.txt', 
                FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
if (!$filmek) {
  $filmek = [];
}

2. példa

Egy filmcímeket tartalmazó tömb fájlba mentése (egy cím egy sor)

// A tömb filmcímekkel
$filmek = [
  'Vuk',
  'Lolka és Bolka',
  'Macskafogó',
  'Kisvakond és barátai',
];

// Kiírás alacsony szintű műveletekkel
define('SORVEG', "\n");
$f = @fopen('mesek.txt', 'w') 
     or die('Hiba!');
if ($f) {
  foreach ($filmek as $film) {
    fputs($f, $film . SORVEG);
  }
  fclose($f);
}
// VAGY
define('SORVEG', "\n");
// Elemek összefűzése
$s = implode(SORVEG, $filmek) 
       . SORVEG;
// Kiírás magas szintű művelettel
$siker = @file_put_contents(
  'mesek.txt', $s);

3. példa

Adott egy rekordokból álló tömb. Végezzük el a kiírását úgy, hogy egy sorban egy rekordnyi információ legyen, az egyes értékeket soron belül tabulátorral válasszuk el!

$filmek = [
  [
    'cim'     => 'Passió',
    'rendezo' => 'Mel Gibson',
    'ev'      => '2004',
  ],
  [
    'cim'     => 'Pio atya - A csodák embere',
    'rendezo' => 'Carlo Carlei',
    'ev'      => '2000',
  ],
];

3. példa

define('SORVEG', "\n");
$f = @fopen('filmek.txt', 'w')
     or die('Hiba!');
if ($f) {
  foreach ($filmek as $film) {
    fputcsv($f, $film, "\t");
  }
  fclose($f);
}
$filmek = [
  [
    'cim'     => 'Passió',
    'rendezo' => 'Mel Gibson',
    'ev'      => '2004',
  ],
  [
    'cim'     => 'Pio atya - A csodák embere',
    'rendezo' => 'Carlo Carlei',
    'ev'      => '2000',
  ],
];
Passió  Mel Gibson  2004
Pio atya - A csodák embere  Carlo Carlei    2000
    

4. példa

Az előző példában kapott fájlt olvassuk be rekordok tömbjeként!

Passió  Mel Gibson  2004
Pio atya - A csodák embere  Carlo Carlei    2000
    
//Beolvasás a file paranccsal, és az utólagos soronkénti bontás
$filmek = file('filmek.txt', 
               FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
foreach($filmek as &$film) {
  list($c, $r, $e) = explode("\t", $film);
  $film = [
    'cim'     => $c,
    'rendezo' => $r,
    'ev'      => $e,
  ];
} 

4. példa

Az előző példában kapott fájlt olvassuk be rekordok tömbjeként!

Passió  Mel Gibson  2004
Pio atya - A csodák embere  Carlo Carlei    2000
    
//Beolvasás soronként az fgetcsv-vel 
$filmek = [];
$f = @fopen('filmek.txt', 'r');
if ($f) {
  while ($sor = fgetcsv($f, 0, "\t")) {
    $filmek[] = [
      'cim'     => $sor[0],
      'rendezo' => $sor[1],
      'ev'      => $sor[2],
    ];
  }
  fclose($f);
}

5. példa

  • Az előző feladatbeli rekordok tömbjét tároljuk úgy a fájlban, hogy a rekord minden egyes mezeje külön sorba kerüljön, és az egyes rekordokat üres sor válassza el egymástól.
  • Oldjuk meg a tömb beolvasását is!
  • Alacsony szintű fájlműveletek

5. példa – kiírás

//Mentés fájlba
define('SORVEG', "\n");
$f = @fopen('filmek_tobbsor.txt', 'w')
     or die('Hiba!');
if ($f) {
  foreach ($filmek as $film) {
    fputs($f, $film['cim'] . SORVEG);
    fputs($f, $film['rendezo'] . SORVEG);
    fputs($f, $film['ev'] . SORVEG);
    fputs($f, SORVEG);
  }
  fclose($f);
}
$filmek = [
  [
    'cim'     => 'Passió',
    'rendezo' => 'Mel Gibson',
    'ev'      => '2004',
  ],
  // ...
];
Passió
Mel Gibson
2004

Pio atya - A csodák embere
Carlo Carlei
2000
    

5. példa – beolvasás

Passió
Mel Gibson
2004

Pio atya - A csodák embere
Carlo Carlei
2000
    
//Beolvasás fájlból
$filmek = [];
$f = @fopen('filmek_tobbsor.txt', 'r');
if ($f) {
  while (!feof($f)) {
    $cim = trim(fgets($f));
    $rendezo = trim(fgets($f));
    $ev = trim(fgets($f));
    $ures = fgets($f);
    if ($cim != '') {
      $filmek[] = [
        'cim'       => $cim,
        'rendezo'   => $rendezo,
        'ev'        => $ev,
      ];
    }
  }
  fclose($f);
}

Konkurens fájlhasználat

  • Ha egyszerre többen hívják meg a szkriptet → konkurens használat
  • flock($f, $op)
    • $op
      • LOCK_SH (olvasáshoz)
      • LOCK_EX (íráshoz)
      • LOCK_UN (kioldáshoz)
  • fflush($f)
    • fájlpuffer ürítése
define('SORVEG', "\n");
$f = @fopen('mesek.txt', 'w')
     or die('Hiba!');
if ($f) {
  if (flock($f, LOCK_EX)) {
    foreach ($filmek as $film) {
      fputs($f, $film . SORVEG);
    }
    flock($f, LOCK_UN);
  }
  fclose($f);
}

Konkurens fájlhasználat

  • Olvasáshoz is érdemes lockolni a fájlt, hogy közben ne kezdődhessen el egy írási folyamat.
$filmek = [];
$f = @fopen('lista.txt', 'r');
if ($f) {
  if (flock($f, LOCK_SH)) {
    while (!feof($f)) {
      $sor = trim(fgets($f));
      if ($sor != '') {
        $filmek[] = $sor;
      }
    }
    flock($f, LOCK_UN);
  }
  fclose($f);
}

Adatszerkezet-vezérelt tárolás

Adatszerkezet

  • Adatszerkezet mentése és betöltése
  • Fájl tartalma nem érdekes
  • Az adat rendelkezésre állása az érdekes
  • Adatszerkezet → szöveges formátum
  • → Sorosítás

Sorosítás

  • Egy adatszerkezet visszaalakítható szöveges megfelelője.
  • Használata
    • tárolás
    • átküldés
  • Sorosító függvények
    • serialize($érték) → szöveg
    • unserialize($szöveg) → érték
    • json_encode($érték) → szöveg
    • json_decode($szöveg) → érték

Példa

$filmek = [
  [
    'cim'      => 'Passió',
    'rendezo'  => 'Mel Gibson',
    'ev'       => '2004',
    'szereplok'=> [
      'Jim Caviezel',
      'Maia Morgenstern',
      'Christo Jivkov',
    ],
  ],
  [
    'cim'      => 'Feltámadás',
    'rendezo'  => 'Kevin Reynolds',
    'ev'       => '2016',
    'szereplok'=> [
      'Joseph Fiennes',
      'Tom Felton',
      'Cliff Curtis',
    ],
  ],
];

Serialize, unserialize

$s = serialize($filmek);
//a:2:{i:0;a:4:{s:3:"cim";s:7:"Passió";s:7:"rendezo";s:10:"Mel Gibson";s:2:"ev";s:4:"2004";s:9:"szereplok";a:3:{i:0;s:12:"Jim Caviezel";i:1;s:16:"Maia Morgenstern";i:2;s:14:"Christo Jivkov";}}i:1;a:4:{s:3:"cim";s:12:"Feltámadás";s:7:"rendezo";s:14:"Kevin Reynolds";s:2:"ev";s:4:"2016";s:9:"szereplok";a:3:{i:0;s:14:"Joseph Fiennes";i:1;s:10:"Tom Felton";i:2;s:12:"Cliff Curtis";}}}
$filmek2 = unserialize($s);
/*
Array
(
  [0] => Array
    (
      [cim] => Passió
      [rendezo] => Mel Gibson
      [ev] => 2004
      [szereplok] => Array
        (
          [0] => Jim Caviezel
          [1] => Maia Morgenstern
          [2] => Christo Jivkov
        )
    )
  [1] => Array
    (
      [cim] => Feltámadás
      [rendezo] => Kevin Reynolds
      [ev] => 2016
      [szereplok] => Array
        (
          [0] => Joseph Fiennes
          [1] => Tom Felton
          [2] => Cliff Curtis
        )
    )
)*/

json_encode

$s = json_encode($filmek);
//[{"cim":"Passi\u00f3","rendezo":"Mel Gibson","ev":"2004","szereplok":["Jim Caviezel","Maia Morgenstern","Christo Jivkov"]},{"cim":"Felt\u00e1mad\u00e1s","rendezo":"Kevin Reynolds","ev":"2016","szereplok":["Joseph Fiennes","Tom Felton","Cliff Curtis"]}]
[
  {
    "cim": "Passi\u00f3",
    "rendezo": "Mel Gibson",
    "ev": "2004",
    "szereplok": [
      "Jim Caviezel",
      "Maia Morgenstern",
      "Christo Jivkov"
    ]
  },
  {
    "cim": "Felt\u00e1mad\u00e1s",
    "rendezo": "Kevin Reynolds",
    "ev": "2016",
    "szereplok": [
      "Joseph Fiennes",
      "Tom Felton",
      "Cliff Curtis"
    ]
  }
]

json_decode

$filmek3 = json_decode($s, true);
/*
Array
(
  [0] => stdClass Object
    (
      [cim] => Passió
      [rendezo] => Mel Gibson
      [ev] => 2004
      [szereplok] => Array
        (
          [0] => Jim Caviezel
          [1] => Maia Morgenstern
          [2] => Christo Jivkov
        )
    )
  [1] => stdClass Object
    (
      [cim] => Feltámadás
      [rendezo] => Kevin Reynolds
      [ev] => 2016
      [szereplok] => Array
        (
          [0] => Joseph Fiennes
          [1] => Tom Felton
          [2] => Cliff Curtis
        )
    )
)*/

Segédfüggvények

function load_from_file(string $filename, bool $array_result = false, $default_data = []) {
  $s = @file_get_contents($filename);
  return ($s === false 
    ? $alap 
    : json_decode($s, $array_result));
}

function save_to_file(string $filename, $data) {
  $s = json_encode($data);
  return file_put_contents($filename, $s, LOCK_EX);
}

Akármilyen adatszerkezetre működik

Példa – új szereplő hozzáadása

$filmek = load_from_file('filmek.json');

$filmek[0]['szereplok'][] = 'Monica Bellucci';

save_to_file('filmek.json', $filmek);
[
  {"cim":"Passi\u00f3","rendezo":"Mel Gibson","ev":"2004",
   "szereplok":["Jim Caviezel","Maia Morgenstern","Christo Jivkov","Monica Bellucci"]},
  {"cim":"Pio atya - A csod\u00e1k embere","rendezo":"Carlo Carlei","ev":"2000",
   "szereplok":["Sergio Castellitto","Sergio Albelli"]}
]

Hátrányok

  • Sok adat mozgatása
  • Rossz konkurrencia-kezelés
  • Manuális szűrés

Adatbázis-kezelés általában

Adatbázis-típusok

  • Adatok szerkezete szerint
    • relációs adatbázisok
    • dokumentum alapú adatbázisok (NoSQL)
  • Tárolás módja szerint
    • adatbázisszerver
    • fájl-alapú adatbázis

Adatbázis-kezelő rendszerek

  • Adatbázis-kezelők
    • MySQL
    • PostgreSQL
    • MSSQL
    • Oracle
    • SQLite
    • stb.
  • Adatbáziskezelő-specifikus függvények
  • SQL utasítások

SQL utasítások

-- Tábla létrehozása
create table filmek (
  id integer primary key,
  cim varchar(40),
  rendezo varchar(20),
  ev integer);

-- Lekérdezés
select id, cim from filmek;
select id, cim from filmek where id > 10;

-- Beszúrás
insert into filmek (cim, rendezo, ev) 
  values ('A hobbit 2', 'Michael Jackson', 2013);

-- Módosítás
update filmek 
  set cim = 'A hobbit: Smaug Pusztasága', 
      rendezo = 'Peter Jackson' 
  where id = 11;

-- Törlés
delete from filmek where id = 12;

Feldolgozás lépései

  • kapcsolódás az adatbázis-kezelő rendszerhez
  • az adatbázis kiválasztása
  • SQL utasítások futtatása az adatbázis-kezelő rendszerben
  • az SQL utasítás eredményének lekérdezése (ha van)
  • a kapcsolat bontása

Adatbázis-kezelés PHP-ban

Adatbázis-kezelő függvények

  • Vendorspecifikus
    • MySQL
    • PostgreSQL
    • MSSQL
    • SQLite
  • Absztrakt interfész

PDO osztályai

  • PDO: az adatbázishoz való kapcsolódásért, és az SQL utasítások futtatásáért (query, exec, prepare) felel.
  • PDOStatement: az adatok lekérdezéséért, illetve előkészített lekérdezések futtatásáért felel.

PDO főbb utasításai

  • $pdo = new PDO("adatbázis_kapcsolat"): kapcsolódás az adatbázishoz
  • $pdo = null: kapcsolat bontása
  • $stmt = $pdo->query("sql"): lekérdezések (SELECT) futtatása
  • $db = $pdo->exec("sql"): nem lekérdezések esetén
  • $stmt = $pdo->prepare("sql"): paraméteres SQL utasítások előkészítése
  • $siker = $stmt->execute(paraméter_tömb): az előkészített SQL utasítás futtatása a paraméterek behelyettesítésével.
  • $adattomb = $stmt->fetchAll(): lekérdezés eredményének eltárolása tömbben

PDO: hibakezelés

  • a hibás utasítások hamis értékkel térnek vissza –> PDO és PDOStatement osztályok műveletei:
    • errorCode(): szabványos (ANSI SQL-92) hibakód
    • errorInfo(): részletes hibaüzenet
  • PDOException típusú hiba dobása : a hibás utasítások kivételt dobnak (try-catch)
    • expliciten beállítandó:
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

Adatbázis előkészítése

Adatbázis előkészítése – példa

CREATE TABLE `albumok` (
  `id`    INTEGER PRIMARY KEY AUTOINCREMENT,
  `egyuttes`  TEXT,
  `cim`   TEXT NOT NULL,
  `ev`    INTEGER NOT NULL
);
INSERT INTO `albumok` (`id`, `egyuttes`, `cim`, `ev`) VALUES (1,'Guns n'' Roses','Appetite for destruction',1986);
INSERT INTO `albumok` (`id`, `egyuttes`, `cim`, `ev`) VALUES (2,'Aerosmith','Get a grip',1993);

CREATE TABLE `zeneszamok` (
  `id`    INTEGER PRIMARY KEY AUTOINCREMENT,
  `szerzo`    TEXT,
  `cim`   TEXT NOT NULL,
  `hossz` INTEGER,
  `album_id`  INTEGER NOT NULL,
  FOREIGN KEY(`album_id`) REFERENCES `albumok`(`id`) ON UPDATE RESTRICT ON DELETE RESTRICT
);
INSERT INTO `zeneszamok` (`id`, `szerzo`, `cim`, `hossz`, `album_id`) VALUES (1, NULL, 'Cryin', 309, 2);
INSERT INTO `zeneszamok` (`id`, `szerzo`, `cim`, `hossz`, `album_id`) VALUES (2, NULL, 'Crazy', 314, 2);
INSERT INTO `zeneszamok` (`id`, `szerzo`, `cim`, `hossz`, `album_id`) VALUES (6, NULL, 'Paradise City', 406, 1);
INSERT INTO `zeneszamok` (`id`, `szerzo`, `cim`, `hossz`, `album_id`) VALUES (7, NULL, 'Sweet Child o'' Mine', 355, 1);

Kapcsolódás

$pdo = new PDO("sqlite:./zene.sqlite");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

// segédfüggvényben:

function kapcsolodas($kapcsolati_szoveg, $felhasznalonev = '', $jelszo = '') {
  $pdo = new PDO($kapcsolati_szoveg, $felhasznalonev, $jelszo);
  $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  return $pdo;
}

// használata
$kapcsolat = kapcsolodas("sqlite:./zene.sqlite");

Egyszerű lekérdezések

Paraméter nélküli lekérdezések

$stmt = $kapcsolat->query("SELECT * FROM `albumok`");
$albumok = $stmt->fetchAll();
var_dump($albumok);

Paraméteres lekérdezések

$stmt = $kapcsolat->prepare("SELECT * FROM `zeneszamok` WHERE `album_id` = :album_id");
$stmt->execute([
  "album_id" => 1
]);
$zeneszamok = $stmt->fetchAll();
var_dump($zeneszamok);

Paraméteres lekérdezések

// segédfüggvényben:
function lekerdezes($kapcsolat, $sql, $parameterek = []) {
  $stmt = $kapcsolat->prepare($sql);
  $stmt->execute($parameterek);
  return $stmt->fetchAll();
}

// használata
$zeneszamok = lekerdezes($kapcsolat, 
  "SELECT * from zeneszamok where album_id = :album_id", 
  [ "album_id" => 1 ]
);

var_dump($zeneszamok);

SQL injection

Szövegösszefűzés:

$query = "SELECT `id`, `name`, `inserted`, `size` FROM `products`
          WHERE `size` = '${size}'";

Ha a $size értékeke a következő:

'
union select '1', concat(uname||'-'||passwd) as name, '1971-01-01', '0' from usertable;
--

akkor a végső SQL utasítás ez lesz:

SELECT `id`, `name`, `inserted`, `size` FROM `products`
      WHERE `size` = ''
union select '1', concat(uname||'-'||passwd) as name, '1971-01-01', '0' from usertable;
--'

Módosító utasítások

$kapcsolat
  ->prepare("
    INSERT INTO `albumok` (`egyuttes`, `cim`, `ev`) VALUES (:egyuttes, :cim, :ev)
  ")
  ->execute([
    "egyuttes"  => "Roxette",
    "cim"       => "Joyride",
    "ev"        => 1991
  ]);

$id = $kapcsolat->lastInsertId();
var_dump($id);

Módosító utasítások

// segédfüggvényben:
function vegrehajtas($kapcsolat, $sql, $parameterek = []) {
  return $kapcsolat
    ->prepare($sql)
    ->execute($parameterek);
}

// használata
vegrehajtas($kapcsolat,
  "INSERT INTO albumok (egyuttes, cim, ev) values (:egyuttes, :cim, :ev)",
  [
    "egyuttes"  => "Roxette",
    "cim"       => "Joyride",
    "ev"        => 1991
  ]
);

$id = $kapcsolat->lastInsertId();
var_dump($id);

Hibakezelés

try {
  $kapcsolat = kapcsolodas("sqlite:./zene.sqlite");

  vegrehajtas($kapcsolat, 
    "INSERT INTO `zeneszamok` (`cim`) VALUES (:cim)",
    [ "cim" => "Joyride" ]
  );
}
catch (PDOException $e) {
  var_dump($e->errorInfo);
}

Segédfüggvények

function kapcsolodas($kapcsolati_szoveg, $felhasznalonev = '', $jelszo = '') {
  $pdo = new PDO($kapcsolati_szoveg, $felhasznalonev, $jelszo);
  $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  return $pdo;
}

function lekerdezes($kapcsolat, $sql, $parameterek = []) {
  $stmt = $kapcsolat->prepare($sql);
  $stmt->execute($parameterek);
  return $stmt->fetchAll();
}

function vegrehajtas($kapcsolat, $sql, $parameterek = []) {
  return $kapcsolat
    ->prepare($sql)
    ->execute($parameterek);
}

Példa

Jelenítsük meg az albumokat felsorolásban! A lista fölött szűrőmező.

<?php
$szuro = $_GET["szuro"] ?? "";

$kapcsolat = kapcsolodas("sqlite:./zene.sqlite");

$albumok = lekerdezes($kapcsolat, 
  "SELECT * FROM `albumok` WHERE `egyuttes` LIKE :egyuttes",
  [ ":egyuttes" => "%${szuro}%" ]
);
?>
<h1>Albumok</h1>
<form action="">
  <input name="szuro">
  <button type="submit">Szűr</button>
</form>
<ul>
  <?php foreach ($albumok as $album) : ?>
    <li>
      <?= $album["egyuttes"] ?>: 
      <?= $album["cim"] ?>
      (<?= $album["ev"] ?>)
    </li> 
  <?php endforeach ?>
</ul>

Feladat

  • Adott filmek listája. Minden filmről tároljuk a címét, rendezőjét és megjelenési évét.
  • Listázzuk ki a nyilvántartásunkban lévő filmeket!
  • Adjunk lehetőséget új film felvételére!

Tábla létrehozása

-- SQLite
CREATE TABLE `filmek` (
  `id`  INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
  `cim` TEXT NOT NULL,
  `rendezo` TEXT,
  `ev`  INTEGER
)

-- MySQL
CREATE TABLE `filmek` (
  `id` int(10) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
  `cim` varchar(50) NOT NULL,
  `rendezo` varchar(50),
  `ev` year(4)
)

Lista oldal

<?php
//Feldolgozó függvények
function osszes_film() {
  //???
}

//A "fõprogram"
$filmek = osszes_film();

//Kiírás
?>
<!doctype html>
<html>
  <meta charset="utf-8">
  <head>
    <title></title>
  </head>
  <body>
    <h1>Filmlista</h1>
    <a href="ujfilm.php">Új film...</a>
    <table>
      <tr>
        <th>Cím</th>
        <th>Rendezo</th>
        <th>Év</th>
      </tr>
      <?php foreach ($filmek as $f) : ?>
      <tr>
        <td><?php echo $f['cim']; ?></td>
        <td><?php echo $f['rendezo']; ?></td>
        <td><?php echo $f['ev']; ?></td>
      </tr>
      <?php endforeach; ?>
    </table>
  </body>
</html>

Lista oldal – lényegi rész

Adatbázis

create table filmek (
    id integer primary key,
    cim,
    rendezo,
    ev);
//Feldolgozó függvények
function osszes_film() {
  $kapcsolat = kapcsolodas("sqlite:./filmek.sqlite");
  return lekerdezes($kapcsolat, 'select * from filmek');
}

Fájl

//Feldolgozó függvény
function osszes_film() {
  return load_from_file('filmek.json');
}

Új film oldal

<!doctype html>
<html>
  <meta charset="utf-8">
  <head>
    <title></title>
  </head>
  <body>
    <h1>Új film</h1>
    <?php if ($hibak) : ?>
    <ul>
      <?php foreach ($hibak as $hiba) : ?>
      <li><?php echo $hiba; ?></li>
      <?php endforeach; ?>
    </ul>
    <?php endif; ?>
    <form action="" method="post">
      Cím: <br>
      <input type="text" name="cim" value="<?php echo $cim; ?>"> <br>
      Rendező: <br>
      <input type="text" name="rendezo" value="<?php echo $rendezo; ?>"> <br>
      Év: <br>
      <input type="text" name="ev" value="<?php echo $ev; ?>"> <br>
      <input type="submit">
    </form>
  </body>
</html> 

Új film oldal

<?php
//Feldolgozó függvények
function film_beszur($cim, $rendezo, $ev) {
  //???
}
//--------
//A "főprogram"
$hibak = array();
$cim = '';
$rendezo = '';
$ev = '';
if ($_POST) {
  $cim = $_POST['cim'];
  $rendezo = $_POST['rendezo'];
  $ev = $_POST['ev'];
  if ($cim == '') {
    $hibak[] = 'Cím kötelező!';
  }
  if ($rendezo == '') {
    $hibak[] = 'Rendező kötelező!';
  }
  if (!is_numeric($ev) || strlen($ev) != 4) {
    $hibak[] = 'Rossz évszám!';
  }
  if (!$hibak) {
    if (film_beszur($cim, $rendezo, $ev)) {
      header('Location: lista_fajl.php');
    };
  }
}
?>

Új film oldal – lényegi rész

Adatbázis

//Feldolgozó függvények
function film_beszur($cim, $rendezo, $ev) {
  $kapcsolat = kapcsolodas("sqlite:./filmek.sqlite");
  return vegrehajtas($kapcsolat, 
    "insert into filmek (cim, rendezo, ev) values (:cim, :rendezo, :ev)",
    [
      "cim"       => $cim,
      "rendezo"        => $rendezo,
      "ev"        => $ev,
    ]
  );
}

Új film oldal – lényegi rész

Fájl

function film_beszur($cim, $rendezo, $ev) {
  $filmek = load_from_file('filmek.json');
  $filmek[] = array(
    'cim'    =>  $cim,
    'rendezo'  =>  $rendezo,
    'ev'    =>  $ev,
  );
  return save_to_file('filmek.json', $filmek);
}

Összefoglalás

  • Adattárolás a kérés-válaszon kívül
  • Fájlkezelés
    • Adatszerkezet-vezérelt
      • sorosítás + magas szintű fájlműveletek
    • Fájlszerkezet-vezérelt
      • alacsony vagy magas szintű fájlműveletek
  • Adatbázis-kezelés
    • PDO