Webbserverprogrammering01 [wesweb01]

Lösningsförslag - userapplikationen

Introduktion

Under moment04-06 så jobbar vi vidare med samma applikation. Denna kan göras på många olika sätt och med olika svårighetsgrad men här kommer ett exempel på en relativt enkel lösning som skulle kunna leda dig mot betyget E på kursen och detta är också grunden till det som senare blir slutprojektet som du då behöver arbeta vidare med.

Moment04

Här finns en lösning till applikationen på Moment04.
Lösningen är enklast möjliga, utan krypterade lösenord och med endast en användare "admin" med lösenord "admin". Sidornas namn och hur de används kommer från den mockup som presenteras i Moment04/Projekt01.

index.php

<!DOCTYPE html>
<html lang="sv">
<head>
	<meta charset="UTF-8">
	<link rel=stylesheet href="style.css" type="text/css">
	<title>User application</title>
</head>
<body>
<article>
	<h1>Logga in</h1>
	<?php
		if(isset($_GET['mess'])){
			echo "<p class='mess'>{$_GET['mess']}</p>";
		}
	?>
	<form method="POST" action="login.php">
		<p>Användarnamn<br /><input type="text" name="username"></p>
		<p>Lösenord <br /><input type="password" name="password"></p>
			<p><input type="submit" value="Logga in"> <input type="reset" value="Rensa"></p>
	</form>
</article>
</body>
</html>

admin.php

<?php
// kollar om användaren är inloggad
include('check_login.php');
?>

<!DOCTYPE html>
<html lang="sv">
<head>
	<meta charset="UTF-8">
	<link rel=stylesheet href="style.css" type="text/css">
	<title>User application</title>
</head>
<body>
<article>
	<?php
		echo "<h1>Du är inloggad som {$_SESSION['username']}</h1>";
		if(isset($_GET['mess'])){
			echo "<p class='mess'>{$_GET['mess']}</p>";
		}
	?>
<p><a href="logout.php">Logga ut</a></p>
</article>
</body>
</html>

login.php

<?php
session_start();

// Kollar om användaren är admin eller user, samt kollar lösenord
if($_POST['username'] == "admin" && $_POST['password'] == "admin"){
  $_SESSION['username'] = $_POST['username'];
  header('location: admin.php');
} else if($_POST['username'] == "user" && $_POST['password'] == "user"){
    $_SESSION['username'] = $_POST['username'];
    header('location: admin.php');
} else {
  header('location: index.php?mess=Felaktig inloggning!');
}
?>

logout.php

<?php
session_start();        // öppnar sessionen
session_unset();        // tömmer sessionen
session_destroy();      // förstör sessionen

// Skicka vidare till index.php med meddelande
header('location: index.php?mess=Du är utloggad!');
?>

check_login.php

<?php
// Öppnar sessionen
session_start();

// Kollar om SESSION['username'] har ett värde, annars kasta ut
if(!isset($_SESSION['username'])){
    header('location: index.php?mess=Du har inte rätt att vara här');
}
?>

style.css

*{
	margin: 0px;
}

body {
	background-color: #93B1C6;
	color: black;
	font-size: 12px;
	font-family: "Lucida Grande", Arial, sans-serif;
	font-weight: normal;
	padding: 0;
	width: 990px;
	margin: 0 auto;
}

article {
	display: block;
	background-color: #F5F5F5;
	padding: 20px;
	min-height: 600px;
	margin: 20px;
	box-shadow: 0px 0px 5px 5px #C7D0D5;
}

h1 {
	color: #EC583A;
	font-size: 20px;
	font-family: "Lucida Grande", Arial, sans-serif;
	font-weight: 500;
	line-height: 20px;
	margin-top: 12px;
}

a {
	color: #FF7148;
	text-decoration: underline;
}

p{
		margin-top: 12px;
}

.mess{
	font-weight:bold;
	color: #EC583A;
}

Moment05

Här följer enklast möjliga ER-modell, datamodell och det databasscript som skapas från Vertabelo. Här finns också en samling av frågor som vi kan komma att använda för att ställa frågor och göra förändringar av databasens innehåll.

Er-modell

Datamodell

Databasscriptet

-- Created by Vertabelo (http://vertabelo.com)
-- Last modification date: 2016-03-14 10:41:44.584

-- Om inte databasen är skapad så gör det först
-- create database user;

-- välj då att jobba mot denna databas
-- use user;

-- tables
-- Table user
CREATE TABLE user (
    id int  NOT NULL  AUTO_INCREMENT,
    username varchar(30)  NOT NULL,
    password varchar(60)  NOT NULL,
    email varchar(60)  NOT NULL,
    CONSTRAINT user_pk PRIMARY KEY (id)
);

-- End of file.

SQL-frågor

-- Allt som skrivs efter "--" på en rad är en kommentar som inte kommer köras.
-- Efter att tabellen user är skapad (kod ovanför) kan vi nu populera och modifiera
-- tabellens data

-- INSERT
INSERT INTO `user`.`user` (`id`, `username`, `password`, `email`)
VALUES (NULL, 'admin', 'admin', 'admin@systemet.se');

-- Det går också att lägga in på följande sätt
-- Vi har tagit bor de kolumner som har defultvärden i tabellen
INSERT INTO user (`username`, `password`, `email`)
VALUES ('user', 'user', 'user@systemet.se');

-- Vi kan också välja att mata in kolumner i den ordning de står i databasen,
-- här måste vi dock sätta tillbaka alla kolumner för att koppla rätt data till
-- rätt kolumn.
INSERT INTO user VALUES (NULL, 'test', 'test', 'test@systemet.se')

-- Vi kan också lägga till flera poster samtidigt
INSERT INTO user (`username`, `password`, `email`)
VALUES ('test01', 'test01', 'test01@systemet.se'),
('test02', 'test02', 'test02@systemet.se'),
('test03', 'test03', 'test03@systemet.se');

-- Dags att söka efter vilka poster som finns i tabellen
SELECT * FROM user;

-- Vi kan välja att visa enstaka kolumner...
SELECT username, email FROM user;

-- ... på en eller flera rader...
SELECT username, email
FROM user;

-- ... med villkor
SELECT username, email
FROM user
WHERE id < 4;

-- På detta sättet kan vi kolla om det går att logga in, vi behöver bara kolla om
-- det går att koppla både användarnamn och lösenord till samma post.
SELECT id
FROM user
WHERE username = 'admin' AND password = 'admin';
-- Funkar det får vi ett resultset med en post och ett korrekt id
-- Funkar det inte så får vi ett tomt resultset tillbaka.

-- Dags att uppdatera poster kopplat till id ...
UPDATE user SET password = 'test001' WHERE id = 4;

-- ... eller med annat villkor
UPDATE user
SET password = 'test'
WHERE username LIKE 'test%';
-- % är ett wildcard som ihop med LIKE innebär att den ersätter 0 till många tecken,
-- oberoende av vilka. _ är ett annat wildcard som ersätter exakt 1 tecken.
UPDATE user WHERE username LIKE 'test_1';

-- Farligt att uppdatera felaktigt
UPDATE user SET password = 'Nytt lösenord';
-- Då ändras alla lösenord i hela systemet

-- Sista modifieringen vi kan göra är att ta bort poster med id ...
DELETE FROM user WHERE id = 6;

-- ... med ett vidare villkor ....
DELETE FROM user WHERE username LIKE 'test%';

-- ... eller den farligaste ...
DELETE FROM user;

-- Nu har vi en helt tom tabell. Om vi skapar en ny post
INSERT INTO user (`username`, `password`, `email`)
VALUES ('user', 'user', 'user@systemet.se');
-- så ser vi att denna användare får ett id som inte är 1.
-- Alla gamla id:n är nu upptagna men det går att rensa allt
-- innehåll i en tabell och återställa räknaren till 1
TRUNCATE user;

-- Tröttnar vi på en tabell och vill ta bort den så skriver vi
DROP table user;

Moment06

Här kommer ett exempel på en applikation med ett enkelt admingränssnitt där det går att logga in och sedan skapa, ta bort och ändra admins. Det finns ingen mockup för denna lösning men förhoppningsvis är filnamnen tillräckligt tydliga för att förstå vad varje sida har för uppgift.

addAdmin.php

<?php
// koppla upp mot databasen
include('dbConnection.php');

// hämta värden från formuläret
// trim tar bort blanka tecken före och efter, strtolower gör om strängen till gemener
$username = trim(strtolower($_POST['username']));
$password = $_POST['password'];
$email = $_POST['email'];

// Bygg upp sql-satsen och kör den sedan mot databasen.
$sql = "INSERT INTO user (username, password, email) VALUES (:username, :password, :email)";
$stm = $pdo->prepare($sql);
$stm->execute( array('username' => $username, 'password' => $password, 'email' => $email));

// Hämta id för den senast skapade posten
$lastId = $pdo->lastInsertId();

// skicka vidare
header("location: admin.php?mess=Admin med id {$lastId} skapades.");
?>

admin.php

<?php
// kollar om användaren är inloggad
include('check_login.php');
require('dbConnection.php');
?>

<!DOCTYPE html>
<html lang="sv">
<head>
	<meta charset="UTF-8">
	<link rel=stylesheet href="style.css" type="text/css">
	<title>User application</title>
</head>
<body>
<article>
	<?php
		echo "<h1>Du är inloggad som {$_SESSION['username']} (id: {$_SESSION['id']}) [<a href='logout.php'>Logga ut</a>]</h1>";
		// Skriv ut meddelandet om det har skickats något sådant.
		if(isset($_GET['mess'])){
			echo "<p class='mess'>{$_GET['mess']}</p>";
		}
	?>

	<fieldset><legend>Skapa ny admin</legend>
		<form method="post" action="addAdmin.php">
			<p>Username:<br />
			<input type="text" name="username" required></p>
			<p>Password:<br />
			<input type="text" name="password" required></p>
			<p>Email:<br />
			<input type="text" name="email" required></p>
			<p><input type="submit" name="submit"></p>
		</form>
	</fieldset>

<?php
// Bygg upp sql-satsen och kör den sedan mot databasen.
$sql = "SELECT * FROM user ORDER BY id ASC;";
$stm = $pdo->prepare($sql);
$stm->execute();
$res = $stm->fetchAll(PDO::FETCH_ASSOC);

$print = "<fieldset><legend>Lista på admins</legend>";
$print .= "<table><tr><th>id</th><th>username</th><th>password</th><th>email</th><th>modify</th></tr>";

// Loopa igenom hela resultatet och skriv ut all info om admins
foreach($res as $row){
	$print .= "<tr>";
	$print .= "<td>{$row['id']}</td>";
	$print .= "<td>{$row['username']}</td>";
	$print .= "<td>{$row['password']}</td>";
	$print .= "<td>{$row['email']}</td>";
	// Lägger in så att det inte går att klicka på delete på sitt eget konto
	$print .= "<td>";
		if($_SESSION['id'] != $row['id']){
			$print .= "<a href='deleteAdmin.php?id={$row['id']}'>delete</a>";
		}
		$print .= "</td>\n <td><a href='editAdmin.php?id={$row['id']}'>ändra</a></td>";
	$print .= "</tr>";
}
$print .= "</table></fieldset>";
// Skriver ut all admininfo
echo $print;
?>

</article>
</body>
</html>

check_login.php

<?php
// Öppnar sessionen
session_start();

// Kollar om SESSION['username'] har ett värde, annars kasta ut
if(!isset($_SESSION['username'])){
    header('location: index.php?mess=Du har inte rätt att vara här');
}
?>

dbConnection.php

<?php
// Variabler
$host = "localhost"; // Den server där databasen ligger
$user = "root";      // Ditt användarnamn
$pwd  = "root";      // Ditt lösenord
$db   = "user";   // Databasen vi vill jobba mot

// dsn - data source name
$dsn = "mysql:host=".$host.";dbname=".$db;

// Inställningar som körs när objektet skapas
$options  = array(
	PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'UTF8'",
	PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION,
	PDO::ATTR_EMULATE_PREPARES, false);

// Skapa objektet eller kasta ett fel
try {
	$pdo = new PDO($dsn, $user, $pwd, $options);
}
catch(Exception $e) {
    die('Could not connect to the database:<br/>'.$e);
}
?>

deleteAdmin.php

<?php
// koppla upp mot databasen
include('dbConnection.php');

// hämta värden från formuläret
$id = $_GET['id'];

// Bygg upp sql-satsen och kör den sedan mot databasen.
$sql = "DELETE FROM user WHERE id = :id";
$stm = $pdo->prepare($sql);
$stm->execute( array('id' => $id));

// skicka vidare
header("location: admin.php?mess=Admin med id {$id} är borttagen.");
?>

editAdmin.php

<?php
// kollar om användaren är inloggad
include('check_login.php');
// koppla upp mot databasen
require('dbConnection.php');

// hämta värden från formuläret
$id = $_GET['id'];

// Bygg upp sql-satsen och kör den sedan mot databasen.
$sql = "SELECT * FROM user WHERE id = :id;";
$stm = $pdo->prepare($sql);
$stm->execute( array('id' => $id));
$res = $stm->fetch(PDO::FETCH_ASSOC);

// Lagra data från databasen i lokala variabler
$username = $res['username'];
$password = $res['password'];
$email = $res['email'];
?>

<!DOCTYPE html>
<html lang="sv">
<head>
	<meta charset="UTF-8">
	<link rel=stylesheet href="style.css" type="text/css">
	<title>User application</title>
</head>
<body>
<article>
	<?php
		echo "<h1>Du är inloggad som {$_SESSION['username']} [id: {$_SESSION['id']}]</h1>";

		// Skriv ut meddelandet om det har skickats något sådant.
		if(isset($_GET['mess'])){
			echo "<p class='mess'>{$_GET['mess']}</p>";
		}
// Detta sätt kallas Heredoc och är smidigt när vi blandar html med php-variabler
// det går inte att köra annan php-kod som selektioner eller liknande.
$form =<<<EOD
	<fieldset><legend>Uppdatera admin</legend>
		<form method="post" action="updateAdmin.php?id={$id}">
				<p>Id:<br/>
				{$id}</p>
			<p>Username:<br />
			<input type="text" name="username" value="{$username}" required></p>
			<p>Password:<br />
			<input type="text" name="password" required></p>
			<p>Email:<br />
			<input type="text" name="email" value="{$email}" required></p>
			<p><input type="submit" name="submit" value="uppdatera"> <input type="reset" name="reset" value="rensa"></p>
		</form>
	</fieldset>
EOD;

// Skriver ut innehållet i variabeln $form som skapades ovan och innehåller formuläret
echo $form;
?>

<p><a href="logout.php">Logga ut</a></p>
</article>
</body>
</html>

index.php

<!DOCTYPE html>
<html lang="sv">
<head>
	<meta charset="UTF-8">
	<link rel=stylesheet href="style.css" type="text/css">
	<title>User application</title>
</head>
<body>
<article>
	<h1>Logga in</h1>
	<?php
	// Skriv ut meddelandet om det har skickats något sådant.
		if(isset($_GET['mess'])){
			echo "<p class='mess'>{$_GET['mess']}</p>";
		}
	?>
	<form method="POST" action="login.php">
		<p>Användarnamn<br /><input type="text" name="username"></p>
		<p>Lösenord <br /><input type="password" name="password"></p>
			<p><input type="submit" value="Logga in"> <input type="reset" value="Rensa"></p>
	</form>
</article>
</body>
</html>

login.php

<?php
// Öppnar sessionen
session_start();

// koppla upp mot databasen
require_once('dbConnection.php');

// hämta värden från formuläret
$username = trim($_POST['username']);
$password = sha1(trim($_POST['password']));

// Bygg upp sql-satsen och kör den sedan mot databasen.
$sql = "SELECT id FROM user WHERE username = :username AND password = :password;";
$stm = $pdo->prepare($sql);
$stm->execute( array('username' => $username, 'password' => $password));
$res = $stm->fetch(PDO::FETCH_ASSOC);

// Om korrekt användarnamn ocg lösenord har angivits så loggas användaren in,
// annars skickas hen tillbaka till startsidan med ett meddelande.
if(isset($res['id'])){
    $_SESSION['username'] = $_POST['username'];
    $_SESSION['id'] = $res['id'];
    header('location: admin.php');
} else {
    header('location: index.php?mess=Felaktig inloggning!');
}
?>

logout.php

<?php
session_start();        // öppnar sessionen
session_unset();        // tömmer sessionen
session_destroy();      // förstör sessionen

// Skicka vidare till index.php med meddelande
header('location: index.php?mess=Du är utloggad!');
?>

updateAdmin.php

<?php
// koppla upp mot databasen
include('dbConnection.php');

// hämta värden från formuläret
// trim tar bort blanka tecken före och efter, strtolower gör om strängen till gemener
// sha1() är den hash-funktion som vi använder.
$id = $_GET['id'];
$username = trim(strtolower($_POST['username']));
$password = sha1($_POST['password']);
$email = $_POST['email'];

// Bygg upp sql-satsen och kör den sedan mot databasen.
$sql = "UPDATE user SET username = :username, password = :password, email = :email WHERE id = :id";
$stm = $pdo->prepare($sql);
$stm->execute( array('username' => $username, 'password' => $password, 'email' => $email, 'id' => $id));

// skicka vidare till admin-sidan med ett meddelande.
header("location: admin.php?mess=Admin med id {$id} är uppdaterad.");
?>