440 likes | 610 Views
Server side scripting. Webtechnologie. Lennart Herlaar. Inhoud. PHP Meer PHP En nog meer PHP. Server side scripting. En n og meer PHP. Webtechnologie. Lennart Herlaar. Class based. Object model herschreven voor PHP5, deels 5.3 Breuk met PHP4; incompatible legacy code
E N D
Server side scripting Webtechnologie Lennart Herlaar
Inhoud • PHP • Meer PHP • En nog meer PHP
Server side scripting En nog meer PHP Webtechnologie Lennart Herlaar
Class based • Object model herschreven voor PHP5, deels 5.3 • Breuk met PHP4; incompatible legacy code • Objects en classes • Een object heeft functies en variabelen • Methods en properties • Methods en properties kunnendynamischaanobjectentoegevoegdworden • Een object is een instantiatie van een class • Een class is een blauwdruk voor een object • De classes vormen een hiërarchie Vergelijk dit met JavaScript...
Objecten class Cart { private $items; // Pas op! public function add_item ($artnr, $num) { $this->items[$artnr] += $num; } public function remove_item ($artnr, $num) { if ($this->items[$artnr] >= $num) { $this->items[$artnr] -= $num; return true; } else { return false; } } } Public, private, protected $cart = new Cart; $cart->add_item("10", 1); $cart->add_item("42", 42); $another_cart = new Cart; $another_cart->add_item("0815", 3);
Object dynamics • Naast object dynamics ook class dynamics • Lastiger dan prototype dynamics in JavaScript • Probeer dit allemaal niet nodig te hebben... $cart1 = new Cart; $cart2 = new Cart; $cart2->add_item("a",10); $cart2->add_item("b",5); $cart1->val = "cart1"; echo ($cart1->val); // cart1 echo ($cart2->val); // Niets echo implode(";",$cart2->items); // 10;5 unset ($cart2->items); echo ($cart2->items); // Niets
Class inheritance • Geen multiple inheritance • Wel multiple interfaces class Named_Cart extends Cart { private $owner; function set_owner($name) { $this->owner = $name; } function get_owner() { return($this->owner); } }
Constructors • Magic Method met de naam __construct • Constructor van super class moet expliciet aangeroepen worden • Eveneens een destructor beschikbaar class Constructor_Cart extends Cart { function __construct($item = "10", $num = 1) { $parent::__construct(); $this->add_item ($item, $num); } } $default_cart = new Constructor_Cart; $different_cart = new Constructor_Cart("20", 17);
Paamayim Nekudotayim • Dubbele dubbele punt • Scope resolution operator • Static properties en methods • Geen instantiatie nodig • Overridden methods • Methods van super classes • Class constants class Foo { public static function myStaticFunc() { [...] }}Foo::myStaticFunc(); class OtherClass extends MyClass { public function myFunc() { [...] parent::myFunc(); } }
Functies op objecten function print_vars($obj) { $vars = get_object_vars($obj); foreach ($vars as $prop => $val) { echo "$prop = $val\n"; } } function print_methods($obj) { $methods = get_class_methods(get_class($obj)); foreach ($methods as $method) { echo "function $method()\n"; } }
Zwakgetypeerd, dynamisch • Nietnodigvariabelen of properties tedeclareren • Type wordt "at runtime" bepaald, duck typing • Automatische type conversion • Functieszijn in de regel geen 1st class citizens • Functies en properties kunnendynamischaanobjectentoegevoegdworden (maar…) • Functies met mogelijkvariabelaantal parameters • Polymorfie • Nesting van functiedefinities, closures (PHP5.3) Vergelijk dit met JavaScript...
Centraalarchitectuur diagram Form, parameters Parameters, code Interpreter of compiler Web browser Webserver HTML HTML File access HTML+code SQL Result set Statische files RDBMS
Superglobals • PHP kent een aantal bijzondere variabelen • Superglobals: automatisch beschikbaar in elke scope • Arrays met (veelal) informatie over de buitenwereld • $_SERVER: server en execution environment • $_GET: key / value paren uit de GET query string • $_POST: key / value paren uit de POST body • Ook: $_FILES, $_COOKIE, $_SESSION, $_ENV • $_REQUEST = $_GET + $_POST + $_COOKIE
Superglobals <?php echo $_SERVER["SERVER_NAME"] . "<br/>"; echo $_SERVER["SERVER_ADDR"] . "<br/>"; echo $_SERVER["SERVER_PORT"] . "<br/>"; echo $_SERVER["REQUEST_TIME"] . "<br/>"; echo $_SERVER["REQUEST_METHOD"] . "<br/>"; echo $_SERVER["REQUEST_URI"] . "<br/>"; echo $_SERVER["HTTPS"] . "<br/>"; echo $_SERVER["HTTP_USER_AGENT"] . "<br/>"; echo $_SERVER["REMOTE_ADDR"] . "<br/>"; echo $_SERVER["REMOTE_PORT"] . "<br/>"; ?>
Form processing <form name="input" action="welcome.php" method="get"> First name: <input type="text" name="first"/><br/> Last name: <input type="text" name="last"/><br/> <input type="submit" value="Send"/> </form> http://…/welcome.php?first=Willie&last=Wartaal <?php echo $_GET["first"]; // Geen URL decoding nodig echo $_REQUEST["first"]; extract($_GET, EXTR_PREFIX_ALL, "imported") // Pas op! echo $imported_first; // Old-skool echo $HTTP_GET_VARS["first"]; // Met PHP directive register_globals = on echo $first; // Pas op! (Old skool; < PHP 5.4) ?>
Odds & ends • Includen van PHP code • include() en require() • Local / remote, scoping • Let op: HTML-context! Gebruik <?php ?> • Aanpassen PHP settings • Vele tientallen setting • In de config file, maar soms ook "at runtime" • ini_set('display_errors', 1), ini_get('post_max_size') • Genereren van HTTP headers • header(), maar pas op met whitespace... <?php // We serveren een PDF uit... header('Content-type: application/pdf'); // ...en we noemen 'm doc.pdf header('Content-Disposition: attachment; filename="doc.pdf"'); [...] ?>
Odds & ends • Heel veel functies in de core... • ...en heel veel functies in extensions • Compressie, cryptografie, cookies, beeldverwerking, e-mail, XML, file system, datum/tijd, sessions, URIs, FTP, databases, mathematische bewerkingen, TCP, sockets, HTTP, SOAP, JSON, LDAP, PDF, MIME, ... • We komen er nog een aantal van tegen • State, sessions, databases, security, stateful web • Belang van frameworks PEAR PECL
PHP configuratie • phpinfo()
State, sessions, databases Webtechnologie Lennart Herlaar
Inhoud • State • Cookies en sessions • Webdatabases • Databases en PHP • (Transactions)
State • HTTP revisited • HTTP is stateless • HTTP kent page based requests • In de regel geen continu draaiende applicatie • Niet op de server, niet in de client • Maar we willen wel persistency • State moet ergens opgeslagen worden • In de client, maar dan wel telkens meesturen • In de server, maar dan wel een identificatieprobleem • Verschillende opties
Hidden input fields • State wordt "verborgen" in het formulier • Hidden input fields, state opgeslagen in de client • Bij submit worden deze waarden meegestuurd • Onderdeel van de GET query string / POST body • En opnieuw verwerkt door het server side script • Problemen met hidden input fields • Verwarrend: gebruik back button geeft verlies state • Inefficiënt: alle state ping-pongt heen en weer • Onveilig: de gebruiker kan eenvoudig bij de state • Complex: scripten ping-pongen en input validation
Hidden input fields <form name="product" action="shop.php" method="get"> Product: <select name="product"> <option value="62629">Volvo</option> <option value="89124">Saab</option> <option value="64625">Fiat</option> <option value="31763">Audi</option> </select><br/> <input type="submit" value="Send"/> <input type="hidden" name="step" value="productinfo"/> </form> <form name="input" action="shop.php" method="get"> Full name: <input type="text" name="name"/><br/> Address: <input type="text" name="address"/><br/> <input type="submit" value="Send"/> <input type="hidden" name="step" value="buyerinfo"/> <input type="hidden" name="product" value="64625"/> <input type="hidden" name="price" value="8995"/> </form> <form name="input" action="shop.php" method="get"> card number: <input type="text" name="cardno"/><br/> card name: <input type="text" name="cardname"/><br/> <input type="submit" value="Send"/> <input type="hidden" name="step" value="paymentinfo"/> <input type="hidden" name="product" value="64625"/> <input type="hidden" name="price" value="8995"/> <input type="hidden" name="name" value="Willie Wartaal"/> <input type="hidden" name="address" value="..."/> </form>
Hidden input fields <form name="input" action="shop.php" method="get"> Full name: <input type="text" name="name"/><br/> Address: <input type="text" name="address"/><br/> <input type="submit" value="Send"/> <input type="hidden" name="step" value="buyerinfo"/> <input type="hidden" name="product" value="64625"/> <input type="hidden" name="price" value="8995"/> </form> shop.php?[...]step=buyerinfo&product=64625&price=8995 shop.php?[...]step=buyerinfo&product=64625&price=89 <form name="input" action="shop.php" method="get"> card number: <input type="text" name="cardno"/><br/> card name: <input type="text" name="cardname"/><br/> <input type="submit" value="Send"/> <input type="hidden" name="step" value="paymentinfo"/> <input type="hidden" name="product" value="64625"/> <input type="hidden" name="price" value="89"/> <input type="hidden" name="name" value="Willie Wartaal"/> <input type="hidden" name="address" value="..."/> </form>
Hidden input fields <input type="hidden" name="step" value="buyerinfo"/> <input type="hidden" name="product" value="64625"/> <input type="hidden" name="price" value="8995"/> <input type="hidden" name="checksum" value="7ce9e97f43808be0d23f0493c3e1345b"/> <input type="hidden" name="step" value="buyerinfo"/> <input type="hidden" name="product" value="64625"/> <input type="hidden" name="price" value="8995"/> <input type="hidden" name="ts" value="timestamp"/> <input type="hidden" name="checksum" value="b368395508548682751710ccd2548d24"/> <input type="hidden" name="step" value="buyerinfo"/> <input type="hidden" name="product" value="64625"/> <input type="hidden" name="price" value="89"/> <input type="hidden" name="checksum" value="6ae40396005969e2c301b5eafa463285"/> <input type="hidden" name="step" value="buyerinfo"/> <input type="hidden" name="product" value="64625"/> <input type="hidden" name="price" value="89"/> <input type="hidden" name="checksum" value="9eece848a4c43a0b1144f863d770c66b"/> REPLAY! md5("step=buyerinfo&product=64625&price=8995") md5("step=buyerinfo&product=64625&price=89") 6ae40396005969e2c301b5eafa463285 md5("step=buyerinfo&product=64625&price=8995MyLittleSecret") 9eece848a4c43a0b1144f863d770c66b md5("step=buyerinfo&product=64625&price=8995MyLittleSecretTimestamp")
State opbouwen in URL • Feitelijk het opbouwen van state in de URL • Bij gebruik van GET • Generiek principe • Alle state aan elke link toevoegen als query string • Form action wordt het script met de state tot nu toe • Maar pas op... • Dan wel gebruik maken van POST • Beter: met hidden input fields en GET of POST <a href="specials.html?[...]&step=buyerinfo&product=64625"> See special deals</a> <form name="input" action="shop.php?step=paymentinfo&[...]&product=64625" method="post"> Full name: <input type="text" name="name"/><br/> Address: <input type="text" name="address"/><br/> <input type="submit" value="Send"/> </form> 't Heeft allemaal dezelfde problematiek!
State, sessions, databases Cookies en sessions Webtechnologie Lennart Herlaar
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 • Cookies zijn key-value paren; associative array Set-Cookie: product=64625; Max-Age=3600 Cookie: product=64625
Cookies • Cookies hebben aanvullende attributen • Expires: wanneer het cookie verloopt (ook: Max-Age) • Domain: voor welke domeinen het cookie geldig is • Path: ...en voor welke URLs binnen het domein • Secure: of het via HTTPS verzonden moet worden • HttpOnly: of het alleen bedoeld is voor HTTP requests Set-Cookie: userid=willie; Domain=shop.foo.com; Path=/accounts; Expires=Wed, 13-Jan-2021 22:23:01 GMT; Secure; HttpOnly Set-Cookie: product=64625; Domain=.foo.com; Path=/; Expires=Wed, 05-Mar-2014 14:30:01 GMT;
Cookies in PHP en JavaScript • PHP ondersteunt op transparante wijze cookies • Header output eerst, dus cookies ook eerst! • Cookies zijn vanuit JavaScript bereikbaar • Zowel lezen als schrijven is mogelijk • Alleen indien matchend en geen HttpOnly <?php $count = $_COOKIE["count"] + 1; setcookie("count", $count, time()+3600); echo $count; ?> document.cookie = 'koekje=hello;expires=Wed, 05 Mar 2014 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 • Biedt persistent storage in de client • 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 var nrOfClicks = localStorage.getItem('clickcount'); nrOfClicks++; localStorage.setItem('clickcount', nrOfClicks); alert(nrOfClicks);
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 session_start(); unset($_SESSION['count']);?> <?php session_start(); session_unset(); session_destroy(); ?> <?php session_start(); session_regenerate_id(); ?>
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 Webtechnologie Lennart Herlaar
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
Centraalarchitectuur diagram Form, parameters, … Web Browser + Applicatie Parameters, code Interpreter of compiler Webserver HTML, CSS, JavaScript, JSON, … HTML, JavaScript, JSON, … File access File SQL Result set SQL Result set X Files RDBMS RDBMS