Ohjelmointikielet ja -paradigmat 5op Markus Norrena
Kotitehtävä 10: Framework esitelmä Valmistelkaa viimeiselle kerralle esitelmä Frameworkistanne Tarkoituksena antaa muille kurssilaisille käsitys Frameworkinne toiminnallisuuksista sekä sen hyvistä ja huonoista puolista Esitelkää myös mitä olette saaneet sillä aikaan Esitelmät 10.4. (Nic) ja 17.4. (muut)
Näitä jatketaan tänään Käyttäjien luominen, päivittäminen ja poistaminen (creating, updating and deleting users): User luokkaan Tiedostojen latauksen (File Upload): Photograph -luokka Kuvien näyttäminen ja niiden ylläpito (jos ehditään)
Ko$tehtävä Toteuta public func$on update() ja public func$on delete() User luokkaan seuraavien kalvojen mukaan:
user.php: public func$on update() Luodaan samalla tapaa, muba sql- muoto on: UPDATE table SET key='value', key='value' WHERE condition Toteuta. Voisi toimia esim. näin: $user = User::find_by_id(2); $user->password = "uusisalasana"; $user->update();
user.php: public func$on update() public function update() { global $database; // - UPDATE table SET key='value', key='value' WHERE condition $sql = "UPDATE ".self::$table_name." SET "; $sql.= "username='". $database->escape_value($this->username)."', "; $sql.= "password='". $database->escape_value($this->password)."', "; $sql.= "first_name='". $database->escape_value($this->first_name)."', "; $sql.= "last_name='". $database->escape_value($this->last_name)."' "; $sql.= "WHERE id=". $database->escape_value($this->id); $database->query($sql); return ($database->affected_rows() == 1)? true : false;
user.php: public func$on delete() public func$on delete() SQL- lauseen muoto DELETE FROM table WHERE condition LIMIT 1 Limit - kannabaa $etoturvasyistä käybää delete- lauseissa aina kun mahdollista. Huomatkaa ebä ilmentymä (olio) on yhä olemassa vaikka poistamme käybäjän $etokannasta! Tämä mahdollistaisi esim. Tällaisen: echo $user->first_name. " was deleted";
user.php: public func$on delete() public function delete() { global $database; // - DELETE FROM table WHERE condition LIMIT 1 // - use LIMIT 1 $sql = "DELETE FROM ".self::$table_name; $sql.= " WHERE id=". $database->escape_value($this->id); $sql.= " LIMIT 1"; $database->query($sql); return ($database->affected_rows() == 1)? true : false; // NB: After deleting, the instance of User still // exists, even though the database entry does not.
Seuraavaksi samaa valokuville! Ensin kuvien lataaminen (upload) SiBen create, update and delete photographs (CRUD): photograph.php photograph.php
Luo valokuville $etokanta CREATE TABLE photographs ( id int(11) NOT NULL auto_increment, filename varchar(255) NOT NULL, type varchar(100) NOT NULL, size int(11) NOT NULL, caption varchar(255) NOT NULL, PRIMARY KEY (id) );
Luo palvelimelle kansio ladabaville /public/images kuville Muutetaan webbipalvelin kansion omistajaksi sudo chown www- data images Jos www- data on apache- prosessin käybäjätunnus Ja tarkista ebä oikeudet (chmod) ovat muuten kunnossa Muistakaa e*ä tämä teh.in jo ekalla luennolla.
Perus upload- käskyt: lomake <form action="upload.php" enctype="multipart/form-data" method="post"> <input type="hidden" name="max_file_size" value="1000000" /> <input type="file" name="file_upload" /> <input type="submit" name="submit" value="upload" /> </form> Muistakaa e*ä tämä teh.in jo ekalla luennolla.
Perus upload- käskyt PHP: $_FILES[] if(isset($_post['submit'])) { // process the form data $tmp_file = $_FILES['file_upload']['tmp_name']; $target_file = basename($_files['file_upload']['name']); $upload_dir = "images"; // move_uploaded_file will return false if $tmp_file is // not a valid upload file or if it cannot be moved for // any other reason if(move_uploaded_file($tmp_file, $upload_dir."/".$target_file)){ echo "File uploaded successfully."; else { echo $_FILES['file_upload']['error']; Muistakaa e*ä tämä teh.in jo ekalla luennolla (tallenna.php)
photograph.php photograph ja user - luokkien määribelyissä paljon samankaltaisuuksia. Lisää / poista osien toimintaperiaabeet voi kopioida user- luokasta. Lisää photograph.php ini$alizeen (ini$alize.php) joba se ladataan muiden luokkien kanssa
class Photograph { photograph.php Käytän itse luokassa tällaisia abribuubeja protected static $table_name="photographs"; protected static $db_fields=array('id', 'filename', 'type', 'size', 'caption'); public $id; public $filename; public $type; public $size; public $caption; private $temp_path; protected $upload_dir="images"; public $errors=array();
Lomake jolla testata luokka: photo_upload.php osa 1 require_once('../../includes/initialize.php'); if (!$session->is_logged_in()) { redirect_to("login.php"); $max_file_size = 1048576; // expressed in bytes if(isset($_post['submit'])) { $photo = new Photograph(); $photo->caption = $_POST['caption']; $photo->attach_file($_files['file_upload']); if($photo->save()) { // Success $session->message("photograph uploaded successfully."); // redirect_to('list_photos.php'); // implement later else { // Failure $message = join("<br />", $photo->errors);
<?php include_layout_template('admin_header.php');?> <h2>photo Upload</h2> Lomake jolla testata luokka: photo_upload.php osa 2 <?php echo output_message($message);?> <form action="photo_upload.php" enctype="multipart/form-data" method="post"> <input type="hidden" name="max_file_size" value="<?php echo $max_file_size;?>" /> <p><input type="file" name="file_upload" /></p> <p>caption: <input type="text" name="caption" value="" /></p> <input type="submit" name="submit" value="upload" /> </form> <?php include_layout_template('admin_footer.php');?>
photograph.php // Pass in $_FILE(['uploaded_file']) as an argument public function attach_file($file) { // Define $temp_path, $filename, $type, $size // Also check for errors Metodi joka alustaa olion kun $edot ovat oliossa, ne voi tallebaa $etokantaan (myöhemmin, sitä ei kannata vielä mie_ä) Toteuta
photograph.php // Pass in $_FILE(['uploaded_file']) as an argument public function attach_file($file) { // Perform error checking on the form parameters if(!$file empty($file)!is_array($file)) { // error: nothing uploaded or wrong argument usage $this->errors[] = "No file was uploaded."; return false; elseif($file['error']!= 0) { // error: report what PHP says went wrong $this->errors[] = $file['error']; return false; else { // Set object attributes to the form parameters. $this->temp_path = $file['tmp_name']; $this->filename = basename($file['name']); $this->type = $file['type']; $this->size = $file['size']; return true;
photograph.php public function save() { Save metodi tekee kaksi asiaa Siirtää kuvan sen oikeaan talletuspaikkaan TalleBaa $etokantaan $edon minne kuva tallete_in
photograph.php osa 1 public function save() { // A new record won't have an id yet. if(isset($this->id)) { $this->update(); else { // Can't save if there are pre-existing errors if(!empty($this->errors)) { return false; // Make sure the caption is not too long for the DB if(strlen($this->caption) > 255) { $this->errors[] = "The caption can only be 255 characters long."; return false; // Can't save without filename and temp location if(empty($this->filename) empty($this->temp_path)) { $this->errors[] = "The file location was not available."; return false; // Determine the target_path $target_path = SITE_ROOT.DS. 'public'.ds. $this->upload_dir. DS. $this->filename;
photograph.php osa 2 // Make sure a file doesn't already exist in the target location if(file_exists($target_path)) { $this->errors[] = "The file {$this->filename already exists."; return false; // Attempt to move the file if(move_uploaded_file($this->temp_path, $target_path)) { // Success // Save a corresponding entry to the database if($this->create()) { // We are done with temp_path, the file isn't there anymore unset($this->temp_path); return true; else { // File was not moved. $this->errors[] = "The file upload failed."; return false;
photograph.php public function create() { global $database; // - INSERT INTO table (key, key) VALUES ('value', 'value') // OSAATKO ITSE TEHDÄ TÄMÄN?
photograph.php public function create() { global $database; // - INSERT INTO table (key, key) VALUES ('value', 'value') // - single-quotes around all values // - escape all values to prevent SQL injection $attributes = $this->sanitized_attributes(); $sql = "INSERT INTO ".self::$table_name." ("; $sql.= join(", ", array_keys($attributes)); $sql.= ") VALUES ('"; $sql.= join("', '", array_values($attributes)); $sql.= "')"; if($database->query($sql)) { $this->id = $database->insert_id(); return true; else { return false;
photograph.php protected function sanitized_attributes() { global $database; $clean_attributes = array(); // sanitize the values before submitting // Note: does not alter the actual value of each attribute foreach($this->attributes() as $key => $value){ $clean_attributes[$key] = $database->escape_value($value); return $clean_attributes;
photograph.php protected function attributes() { // return an array of attribute names and their values $attributes = array(); foreach(self::$db_fields as $field) { if(property_exists($this, $field)) { $attributes[$field] = $this->$field; return $attributes;
Kokeile toimiiko? photograph.php
list_photos.php NäyBää kuvat admin puolella - > yritä ensin kirjoibaa se itse! Saatat tarvita user luokasta tubuja apumetodeja, kuten Photograph::find_all();
list_photos.php osa 1 <?php require_once("../../includes/initialize.php"); if (!$session->is_logged_in()) { redirect_to("login.php"); // Find all the photos $photos = Photograph::find_all(); include_layout_template('admin_header.php');?> <h2>photographs</h2> <?php echo output_message($message);?> <table class="bordered"> <tr> <th>image</th> <th>filename</th> <th>caption</th> <th>size</th> <th>type</th> <th> </th> </tr>
list_photos.php osa 2 <?php foreach($photos as $photo):?> <tr> <td><img src="../<?php echo $photo->image_path();?>" width="100" /></td> <td><?php echo $photo->filename;?></td> <td><?php echo $photo->caption;?></td> <td><?php echo $photo->size_as_text();?></td> <td><?php echo $photo->type;?></td> <td><a href="delete_photo.php?id=<?php echo $photo->id;?> ">Delete</a></td> </tr> <?php endforeach;?> </table> <br /> <a href="photo_upload.php">upload a new photograph</a> <?php include_layout_template('admin_footer.php');?>
photograph.php public function image_path() { return $this->upload_dir.ds.$this->filename; public function size_as_text() { if($this->size < 1024) { return "{$this->size bytes"; elseif($this->size < 1048576) { $size_kb = round($this->size/1024); return "{$size_kb KB"; else { $size_mb = round($this->size/1048576, 1); return "{$size_mb MB";
public static function find_by_sql($sql="") { global $database; $result_set = $database->query($sql); $object_array = array(); while ($row = $database->fetch_array($result_set)) { $object_array[] = self::instantiate($row); return $object_array; photograph.php // Common Database Methods public static function find_all() { return self::find_by_sql("select * FROM ".self::$table_name); public static function find_by_id($id=0) { global $database; $result_array = self::find_by_sql( "SELECT * FROM ".self::$table_name." WHERE id=".$database->escape_value($id)." LIMIT 1"); return!empty($result_array)? array_shift($result_array) : false;
photograph.php private static function instantiate($record) { $object = new self; // Simple, long-form approach: $object->id = $record['id']; $object->filename = $record['filename']; $object->type = $record['type']; $object->size = $record['size']; $object->caption = $record['caption']; return $object;
delete_photo.php Koodissa mainibu delete_photo.php pitäisi myös toteubaa
delete_photo.php <?php require_once("../../includes/initialize.php"); php if (!$session->is_logged_in()) { redirect_to("login.php"); // must have an ID if(empty($_get['id'])) { $session->message("no photograph ID was provided."); redirect_to('index.php'); $photo = Photograph::find_by_id($_GET['id']); if($photo && $photo->destroy()) { $session->message("the photo {$photo->filename was deleted."); redirect_to('list_photos.php'); else { $session->message("the photo could not be deleted."); redirect_to('list_photos.php'); if(isset($database)) { $database->close_connection();?>
photograph.php public function destroy() { // First remove the database entry if($this->delete()) { // then remove the file // Even though the database entry is gone, this object // is still around $target_path = SITE_ROOT.DS.'public'.DS.$this->image_path(); return unlink($target_path)? true : false; else { // database delete failed return false;
photograph.php public function delete() { global $database; // - DELETE FROM table WHERE condition LIMIT 1 $sql = "DELETE FROM ".self::$table_name; $sql.= " WHERE id=". $database->escape_value($this->id); $sql.= " LIMIT 1"; $database->query($sql); return ($database->affected_rows() == 1)? true : false;
public $message; function construct() { $this->check_message(); public function message($msg="") { if(!empty($msg)) {// set message $_SESSION['message'] = $msg; else { // get message return $this->message; session.php lisätään $message, joba saadaan viestejä välitebyä redirect käskyn yli private function check_message() { if(isset($_session['message'])) { $this->message = $_SESSION['message']; unset($_session['message']); else { $this->message = ""; $message = $session->message();
photograph.php public function update() { global $database; // - UPDATE table SET key='value', key='value' WHERE condition $attributes = $this->sanitized_attributes(); $attribute_pairs = array(); foreach($attributes as $key => $value) { $attribute_pairs[] = "{$key='{$value'"; $sql = "UPDATE ".self::$table_name." SET "; $sql.= join(", ", $attribute_pairs); $sql.= " WHERE id=". $database->escape_value($this->id); $database->query($sql); return ($database->affected_rows() == 1)? true : false;
Julkiselle puolelle Sivun vierailijoille näytetään kuvat: index.php pienemmille kuvakkeille photo.php täysikokoisille kuville Kokeile toteubaa.
Julkiselle puolelle: index.php <?php require_once("../includes/initialize.php");?> <?php // Find all photos $photos = Photograph::find_all();?> <?php include_layout_template('header.php');?> <?php foreach($photos as $photo):?> <div style="float: left; margin-left: 20px;"> <a href="photo.php?id=<?php echo $photo->id;?>"> <img src="<?php echo $photo->image_path();?>" width="200"> </a> <p><?php echo $photo->caption;?></p> </div> <?php endforeach;?> <?php include_layout_template('footer.php');?>
Julkiselle puolelle: photo.php <?php require_once("../includes/initialize.php"); if(empty($_get['id'])) { $session->message("no photograph ID was provided."); redirect_to('index.php'); $photo = Photograph::find_by_id($_GET['id']); if(!$photo) { $session->message("the photo could not be located."); redirect_to('index.php'); include_layout_template('header.php');?> <a href="index.php">«back</a><br /><br /> <div style="margin-left: 20px;"> <img src="<?php echo $photo->image_path();?>" /> <p><?php echo $photo->caption;?></p> </div> <?php include_layout_template('footer.php');?>
(Kotitehtävä) Toteuta kommentointi (Comments -class) Pitkälti samalla tapaa kuin käyttäjien ja kuvien ylläpito Erona että kommentti liittyy aina tiettyyn kuvaan
(Kotitehtävä) Toteuta admin-puolelle lomake joka mahdollistaa käyttäjien ylläpidon uuden luomisen, delete & update työkalut?
Photo Gallery Project Alkuperäisen suunnitelmani $lanne: User Photograph Comments - > (ko$tehtävä) Database Session Pagina$on - >jää puubumaan
Kurssin status KäsiBelemäBä jäi Func$onal Programming (Funk$onaalinen ohjelmoin$) hbp://phpmaster.com/func$onal- programming- and- php/ Haskell is an advanced purely- func$onal programming language. hbp://www.haskell.org/haskellwiki/haskell
Kurssin status Muuta jos kiinnostaa JavaScript JavaScript does not have classical OOP. It has prototyping OOP. This means you have only objects. h*p://www.codecademy.com/tracks/javascript The MVC PaBern and PHP hbp://phpmaster.com/the- mvc- pabern- and- php- 1/ hbp://phpmaster.com/the- mvc- pabern- and- php- 2/
KurssipalauteBa Tuubissa nyt jo! Ensi kerralla "framework" esitelmät.