State, sessions, databases Lennart Herlaar Webtechnologie 1 Inhoud • State • Cookies en sessions • Webdatabases • Databases en PHP • (Transactions) State, sessions, databases Cookies en sessions Lennart Herlaar Webtechnologie 3 Cookies • State wordt als "brokje" data opgeslagen • In de client • Server geeft client opdracht cookie te zetten • Client stuurt het cookie mee met elk request • Indien cookie en request matchen • Uitwisseling op basis van HTTP headers • Server zet het cookie met Set-Cookie Set-Cookie: product=64625; Max-Age=3600 Cookie: product=64625 • Cookies zijn key-value paren; associative array Cookies in PHP en JavaScript • PHP ondersteunt op transparante wijze cookies <?php $count = $_COOKIE["count"] + 1; setcookie("count", $count, time()+3600); echo $count; ?> • Header output eerst, dus cookies ook eerst! • Cookies zijn vanuit JavaScript bereikbaar • Zowel lezen als schrijven is mogelijk • Alleen indien matchend en geen HttpOnly document.cookie = 'koekje=hello;expires=Fri, 09 Mar 2016 14:35:01 GMT'; var koekje = document.cookie; // let op: string met key-value paren! Cookies? • Soorten cookies • Persistent, Session, Supercookie, Trackingcookie, ... • Cookies lossen niet alle eerdere problemen op • Inefficiënt, onveilig • Daarnaast nieuwe specifieke problemen • • • • • Cookies kunnen in de browser geweigerd worden Beperkingen m.b.t. aantal en omvang van cookies Cookies hebben een matige reputatie Wettelijke beperkingen aan het gebruik van cookies Cookies soms ten onrechte geweigerd Web Storage • Onderdeel van HTML5 var nrOfClicks = localStorage.getItem('clickcount'); • Biedt persistent storage in de client nrOfClicks++; localStorage.setItem('clickcount', nrOfClicks); alert(nrOfClicks); • Vergelijkbaar met cookies, maar... • Meer opslagruimte (5MB per domein versus 50 x 4kB) • Local storage per domein (≈ persistent cookie) • Session storage per window (≈ session cookie) • Associative array • Uitsluitend een client side interface... • ...en dus alleen te benaderen vanuit JavaScript Sessions • State in de gedaante van generieke session data • De session data is opgeslagen op de server • In een file of in een database • Minimale identifier ping-pongt heen en weer • Als cookie; desnoods in een query string • Script uitgevoerd in context van de session data • PHP ondersteunt op transparante wijze sessions • PHPSESSID cookie bevat meestal de session identifier • Bijvoorbeeld: vgdo5afs4o220s6d991cr1nhg042ax17 • De session identifier is een voucher Sessions in PHP <?php session_start(); //Pas op, voor eerste output if (!isset($_SESSION['count'])) { $_SESSION['count'] = 1; } else { $_SESSION['count']++; } [...] echo "Hello visitor, you have seen this page " . $_SESSION['count'] . " times."; ?> <?php <?php session_start(); session_start(); unset($_SESSION['count']); session_regenerate_id(); ?> ?> <?php session_start(); session_unset(); session_destroy(); ?> Session bijzonderheden • Uniciteit session identifier niet gegarandeerd • Kans op conflict buitengewoon klein • Diverse mogelijkheden om dit te verbeteren • Defaults voor PHPSESSID cookie • Expires: "0" (maar…), Path: "/" • Fall-back naar session identifier in query string... • Afhankelijk van settings en aanpasbaar • Opslag van session data • File system, in een bestand sess_PHPSESSID • Eigen session handlers kunnen gedefinieerd worden Zijn sessions veilig? • Min of meer, maar het vergt wel aandacht... • Use only cookies setting: voorkomt session hijacking t.g.v. shoulder surfing, bookmarking, referer URL, ... • Secure cookie attribuut: HTTPS vereist • Goede keuze van Expires, Path, Domain, HttpOnly • Aanvullende controles: IP-adres, etc. (maar...) • Regelmatig wisselen van session identifier • Betere generator voor de session identifier • ... • Sessions werken in de praktijk goed (maar...) State, sessions, databases Webdatabases Lennart Herlaar Webtechnologie 12 Web SQL • Web Storage soms met een client side database • SQLite in Firefox: webappsstore.sqlite • Is dit idee niet generieker te maken? • Client side database • Toegang met behulp van SQL, vanuit JavaScript • Web SQL • Onderdeel van HTML5 • Inmiddels alweer deprecated... • Gebrek aan "onafhankelijke implementaties" die geen SQLite gebruiken Centraal architectuur diagram RDBMS HTML, CSS, JavaScript, JSON, … File HTML, JavaScript, JSON, … Files Interpreter of compiler Result set Webserver SQL Parameters, code File access Result set SQL Web Browser + Applicatie Form, parameters, … RDBMS Webdatabases? • Wenselijke eigenschappen van RDBMSen • • • • • Stabiele structuur van data Grote hoeveelheden data Goede performance Meerdere gebruikers tegelijkertijd (transactions) Betrouwbaarheid en integriteit van data • Uitbreiding van webapplicatie met een RDBMS voor storage ligt voor de hand • B.v. producten en bestellingen binnen een webshop • Databases op het web is een betere benaming Computing models revisited • Three-tier C/S model past goed bij het web 1. Webbrowser functioneert als thin client 2. Webserver functioneert als application server 3. Database server voor database en transaction logic • Eventueel loskoppeling webserver en applicatie • Diverse technieken voor integratie • • • • Leverancier-specifieke technieken, eigen webservers Gebruikelijke ondersteuning in programmeertalen Java: Java DataBase Connectivity (JDBC) Server side scripting talen Server side scripting & RDBMSen • Server side scripting talen hebben in de regel faciliteiten voor interactie met een RDBMS • • • • Vaak in de vorm van extensions, modules, libraries Perl DBI-modules PHP extensions Maar ook: RDBMS support in de core • Leverancier-specifiek versus abstractielagen • Vaak een platform-specifieke driver nodig • Interactie vaak op basis van SQL en result set • Client/server request en response Database smaken • Er zijn vele tientallen RDBMSen beschikbaar • Oracle, MS SQL Server, MySQL, PostgreSQL, SQLite • MS Access, Excel (!) • "Wat is het beste RDBMS?" • Holy Wars! Vergelijk: taal, OS, telefoon, ... • Betere vraag: "gegeven mijn specifieke situatie?" • "Use the tool that does the job best" • Requirements, license, features, stabiliteit, eenvoud, schaalbaarheid, performance, kennis, support, kosten Databases op het web • HTTP revisited • HTTP is stateless • HTTP kent page based requests • Gevolgen voor database interactie • 1 tot vele tientallen queries per pagina • Queries vaak relatief eenvoudig; binnen een context • Transactions over meerdere requests problematisch • Snelheid versus features? • Snelheid versus betrouwbaarheid en integriteit? De populairste opties • MySQL en SQLite zijn populaire keuzes • Gratis (maar...), snel, relatief eenvoudig • Inmiddels ook een behoorlijke featureset • ACID-compliant database platformen • MySQL is een client/server RDBMS • SQLite is een file database • Geen eigen server proces • Access mechanisme (library) gelinkt in de client(s) • "Concurrent" writes op basis van file locking! SQLite overwegingen • • • • SQLite SQLite SQLite SQLite files zijn portable werkt zonder users / passwords is "weakly typed" wordt vaak client side gebruikt • Browsers, mobile devices • SQLite is niet zo heel serieus... • ...als server side database platform voor grote sites • ...maar voldoet prima bij een practicumopdracht • Zero-install footprint! • De trend is overigens weer naar client side state! State, sessions, databases Databases en PHP Lennart Herlaar Webtechnologie 22 Databases en PHP • Database ondersteuning in PHP is uitgebreid • Specifieke extensions voor > 20 platformen • Daarnaast abstraction layers • Portability is een aandachtspunt • • • • Platform-specifieke functienamen en parameters mysqli_query, pg_query, ... Maar wel platform-specifieke features benaderbaar Eigen database abstraction library schrijven? • MySQL en SQLite support native in PHP aanwezig • Afhankelijk van versie en compilatie-opties Databases en PHP <?php if (!($cnx = @pg_connect("host=somehost dbname=somedatabase user=someuser password=somepassword"))) { showerror(); } if (!($result = pg_query($cnx, "SELECT * FROM products"))) { showerror(); } echo "<ul>\n"; while ($row = pg_fetch_array($result)) { echo "<li>" . $row["description"] . " : " . $row["price"] . "</li>\n"; } echo "</ul>\n"; pg_close($cnx); ?> Database abstraction library? function db_connect ($type, $host, $database, $user, $password) { if ($type == 'pgsql') { if (!($cnx = @pg_connect("host=$host dbname=$database user=$user password=$password"))) { showerror(); } } elseif ($type == 'mysql') { if (!($cnx = @mysql_connect($host, $user, $password))) { showerror(); } mysql_select_db($database, $cnx) or showerror(); } return $cnx; } PHP database abstraction layers • Diverse database abstraction layers beschikbaar • Deels in de core, deels in PEAR/PECL, deels extern • PDO, dbx, ODBC, ... • PHP Data Objects (PDO) • Standaard in PHP aanwezig • Data-access abstraction, niet database abstraction • Dezelfde functies voor queries en result sets • Geen herschrijving van SQL statements • Geen bijzondere functionaliteit (wel via PDO drivers) PDO <?php try { $dbh = new PDO('sqlite:mydbfile.sqlite'); $sth = $dbh->query("SELECT * FROM products"); echo "<ul>\n"; foreach ($sth as $row) { echo "<li>" . $row["description"] . " : " . $row["price"] . "</li>\n"; } echo "</ul>\n"; $dbh = NULL; } catch(PDOException $e) { echo "Exception: " . $e->getMessage(); } ?> PDO prepare & execute <?php <?php $sth = $dbh->prepare('SELECT name, colour, calories $sth = $dbh->prepare('SELECT name, colour, calories FROM fruit FROM WHEREfruit calories < :calories WHERE calories < :calories AND colour = :colour'); <?php AND colour = :colour'); $calories = 150; $sth = $dbh->prepare('SELECT name, colour, calories $sth->bindParam(':calories', $calories, PDO::PARAM_INT); $colour = 'red'; FROM fruit $sth->bindParam(':colour', $colour, PDO::PARAM_STR, 12); $sth->execute(array(':calories' => $calories, WHERE calories < ? AND colour = ?'); $calories = 150; ':colour' => $colour)); $sth->bindParam(1, $calories, PDO::PARAM_INT); $colour = 'red'; [...] $sth->bindParam(2, $colour, PDO::PARAM_STR, 12); $sth->execute(); ?> <?php $calories = 150; [...] $sth = $dbh->prepare('SELECT name, colour, calories $colour = 'red'; FROM fruit $sth->execute(); $calories = 90; WHERE calories < ? AND colour = ?'); [...] $colour = 'green'; = 150; ?>$calories $sth->execute(); $colour = 'red'; [...] $sth->execute(array($calories, $colour)); ?>[...] ?> PDO observaties • Class based • Exception handling • try – catch; informatief, maar niet te informatief • PDO versus PDOStatement • Database handle versus query en result set • Query versus prepare & execute: templates! • Efficiëntie en security; voorkomen SQL injection • Let op data type • Ook data manipulatie en data definitie • INSERT, DELETE, CREATE TABLE, DROP TABLE Frameworks en databases • Sommige PHP frameworks werken met ORM • Object Relational Mapping; vaak onderdeel MVC • Virtuele object database; persistent objects • Conversie van objecten naar RDBMS records • Een tabel is een class, een record is een object • OR impedance mismatch; lastig That probleem hurts! • Soms alleen: SQL samenstellen; result in arrays • ORM abstractie bovenop een PDO abstractie waar een ODBC abstractie gebruikt wordt om een SQLite abstractie van een file te benaderen? Session data en databases • Is session data ook data? Ja! • Producten, bestellingen en winkelmandjes • PHP gebruikt files voor opslag session data • Een database is vaak handiger • Grote verzameling sessions verstopt het file system • Niet erg toegankelijk voor externe toepassingen • Schaalt moeizaam: multi-server omgeving • Twee mogelijkheden • Expliciet afhandelen van sessions • Herdefiniëren van default session handlers State tables • Session data komt terecht in state tables • Basis: session identifier, key, value • Maar ook maatwerk mogelijk; inpassen in database • Reguliere database tabellen met enkele extra velden • Functies nodig voor create, read, update, delete • En een garbage collection mechanisme • Session data is immers veelal tijdelijk van aard State tables session_start(); $dbh = new PDO('sqlite:statedb.sqlite'); $sth = $dbh->prepare("SELECT count(*) AS count FROM visitors WHERE sessionid = ?"); $sth->bindValue(1, session_id(), PDO::PARAM_STR); $sth->execute(); $row = $sth->fetch(); $count = $row['count']; if ($count == 0) { $sth = $dbh->prepare("INSERT INTO visitors (sessionid, lastvisit) VALUES (:sessionid, :time)"); } else { $sth = $dbh->prepare("UPDATE visitors SET lastvisit = :time WHERE sessionid = :sessionid"); } $sth->bindValue(':sessionid', session_id(), PDO::PARAM_STR); $sth->bindValue(':time', time(), PDO::PARAM_INT); $sth->execute(); State tables class MySessionHandler extends SessionHandler { • Herdefiniëren van default session handlers • public function read($sessionid) { session_set_save_handler("open", "close", "read", global $sess_save_path; session.save_handler op "user" in plaats van "write", "destroy", "gc"); "file" $sess_file = "$sess_save_path/sess_$sessionid"; • Definiëren van functies voor afhandelen sessions session_set_save_handler($handler); return (string) @file_get_contents($sess_file); } // Vervang dit door een state table query • Toegang state tables onderbrengen in deze functies [...] • Sessions kunnen normaal gebruikt worden } $handler = new MySessionHandler(); • session_start, $_SESSION session_set_save_handler($handler); session_start(); • Transparant, maar wel lastiger om op te zetten