JarlG Skrevet 21. oktober 2009 Del Skrevet 21. oktober 2009 (endret) Hei! Det har seg slik at eg, som følar eg har teken på både HTML og CSS, samt ein del Javascript, har bestemt meg for å lære meg PHP og MySQL. I den anledning har eg tenkt å setje ferdigheitane mine på prøve ved å (i kvartfall prøve) å utvikle ei lita gjestebok, som kanskje eventuelt kunne bitt til eit lite forum - begge relativt lite funksjonell i fyste omgang. Dette er altså absolutt inga arbeidslogg, men heller eit sted der eg gjerne ville kunne spørje om tips ang. "er det slik dette bør gjerast?" eller liknande. Spørsmål som dreier seg om sikkerheit vil eg også sikkert spørje om. Hittil har eg utvikla eit lite system der kven som helst kan svare med innlegg, og legge ved namn. Javascript sjekkar om formen er utfylt, før den blir sendt. Formen er veldig enkel, og den blir behandla av eit PHP-script som blir lagt ved seinare i innlegget. <form action="" method="post" id="svarForm"> Navn: <input type="text" name="name" id="name" /> <textarea name="input" id="input"></textarea> <input type="submit" id="submit" value="Send" /> </form> Innlegga blir lagra i ein multidimensjonal array, og vises slik; <?php foreach ($innlegg as $innlegget) { echo "<div class='innlegg'>" . "<span class='innleggForfatter'>" . htmlspecialchars($innlegget['forfatter'], ENT_QUOTES, "UTF-8") . "</span>" . "<span class='innleggInfo'>" . $innlegget['id'] . ", " . htmlspecialchars($innlegget['tid'], ENT_QUOTES, "UTF-8") . "</span>" . "<p>" . htmlspecialchars($innlegget['tekst'], ENT_QUOTES, "UTF-8") . "</p>"; }; ?> I denne spoileren ligger koden som behandlar innlegg, samt legger alle innlegg sine verdiar inn i ein multidimensjonal array $innlegg på formen $innlegg[postnr(id)][element] der elementet kan vere 'tekst', 'forfatter', 'tid' og 'id'. <?php include "connect.php"; // mysqli_real_escape_string - relatert if (get_magic_quotes_gpc()) { function stripslashes_deep($value) { $value = is_array($value) ? array_map('stripslashes_deep', $value) : stripslashes($value); return $value; } $_POST = array_map('stripslashes_deep', $_POST); $_GET = array_map('stripslashes_deep', $_GET); $_COOKIE = array_map('stripslashes_deep', $_COOKIE); $_REQUEST = array_map('stripslashes_deep', $_REQUEST); } // Hvis det finnes en post, legg den til i databasen if (isset($_POST['input']) && isset($_POST['name'])) { $innlegg = mysqli_real_escape_string($connect, $_POST['input']); $name = mysqli_real_escape_string($connect, $_POST['name']); $sqlInsertInto = "INSERT INTO innlegg SET forfatter = \"$name\", tekst = \"$innlegg\", tid = NOW()"; if (!mysqli_query($connect, $sqlInsertInto)) { echo "Error: " . mysqli_error($connect); } else { header("Location: ."); }; }; // Legg innleggene inn i en multidimensjonel array $sqlHentInnlegg = mysqli_query($connect, "SELECT * FROM innlegg"); $i = 0; while ($temp = mysqli_fetch_array($sqlHentInnlegg)) { $innlegg[$i]['forfatter'] = $temp['forfatter']; $innlegg[$i]['tekst'] = $temp['tekst']; $innlegg[$i]['tid'] = $temp['tid']; $innlegg[$i]['id'] = $temp['id']; $i++; }; ?> Eg hadde vore veldig takknemleg dersom nokon kunne forklart kva den fyste delen av koden gjer (den er kopiert og limt), altså den som er "mysqli_real_escape_string" -relatert. Dette er da ein funksjon som konverterer symbol som brukast i kode, til ein streng som refererer til dette symbolet, slik at eit innlegg ikkje kan bli oppfatta som kode(og dermed gjere skade), ikkje sant? Vidare så vil eg spørje om dette i det heile tatt er ei god løysning på eit slikt system? Tenkjer då spesielt på oppsettet av tabellen i mysql-databasen som har fire kolonner ved namn 'id', 'forfatter', 'tekst' og 'tid'. Tenkjer også på sikkerheit. Har også eit lite problem med og få tid til å vise timer og minuttar, istaden for berre ein dato - korleis kan eg gjere det? Forklar helst kva dykk gjer dersom dykk legg ved tips til forbetringar - dette er eit læreprosjekt. Takkar mykje for svar! Kan forresten tilføye at eg arbeidar med ei løysning der eg kan definere med som administrator, og dermed slette innlegg via ein knapp med value="Slett". Har eit spørsmål vedrørande det, også; <?php if ($_POST['passord'] == "Hemmelig") { $administrator = true; } else { $administrator = false; }; [...] if ($administrator == true) { kode for å generere sletteknapper for kvart innlegg }; ?> Vil dette vere trygt? Er dette ein god løysning? Ville det evt. vore betre å kutte fyste if-en, og sette dens conditionals i den siste? Igjen, takk! Endret 21. oktober 2009 av JarlG Lenke til kommentar
TheClown Skrevet 21. oktober 2009 Del Skrevet 21. oktober 2009 Eg hadde vore veldig takknemleg dersom nokon kunne forklart kva den fyste delen av koden gjer (den er kopiert og limt), altså den som er "mysqli_real_escape_string" -relatert. Dette er da ein funksjon som konverterer symbol som brukast i kode, til ein streng som refererer til dette symbolet, slik at eit innlegg ikkje kan bli oppfatta som kode(og dermed gjere skade), ikkje sant? Det er en funksjon som konverterer html til andre "uskadelige" symboler, og fjerner quotes og legger til qoutes slik at det ikke skal være mulig å skrive inn noe i feltene som skader databasen (eller sletter den). Ang. sikkerhet vil det bare funke i det du logger inn som admin. Skriv session_start(); øverst og skriv: if($_POST['passord'] == "Hemmelig") { $_SESSION['admin'] = true; } if ($_SESSION['admin'] == true) { // Logga inn! } else { // Ikke logga inn! } Lenke til kommentar
JarlG Skrevet 21. oktober 2009 Forfatter Del Skrevet 21. oktober 2009 (endret) Tusen takk for svar! 'session_start();', korleis fungerer denne funksjonen? Er det cookie-relatert? Dersom det er tilfellet, tenkjer eg at '$_SESSION['admin'] = true;' lagrar ein verdi i cookien? Igjen, takk! Red.: Takk, Kris! (googlet faktisk, men fant ingenting som var forståelig ) Endret 21. oktober 2009 av JarlG Lenke til kommentar
Kris Skrevet 21. oktober 2009 Del Skrevet 21. oktober 2009 http://www.php.net/manual/en/book.session.php http://www.w3schools.com/PHP/php_sessions.asp Lenke til kommentar
PlastBox Skrevet 22. oktober 2009 Del Skrevet 22. oktober 2009 (endret) Ser ut som om du er godt på vei, og det er godt å se noen her på forumet som faktisk gjør en innsats for å lære i stedenfor å poste "HAI U CAN I HAZ PHPZ K THX BAI"! ^^ Sessions er server-side cookies i mangel av en bedre forklaring. Vanlige cookies er verdier som lagres i en fil hos klienten, mens sessions benytter seg av en unik id nettleseren tildeles når de går inn på siden og lagrer selve infoen på serveren. Når du setter en $_SESSION-variabel vil den være tilgjengelig for det nettleservinduet siden ble hentet i for alle script innen samme domene, og ingen skummel informasjon lagres client-side. Å lage et forum utav dette er vel en passelig stor utfordring for en nybegynner. Du trenger først login-form: <form action="login.php" method="post"> Brukernavn: <input type="text" name="username" /><br /> Passord: <input type="password" name="password" /><br /> <input type="submit" value="Logg inn" /> </form> Så et enkelt script som validerer innloggingen: (forutsetter en MySQL-tabell `users` med userID (INT, autoincrement, unique), username (VARCHAR(50) ellerno) og password (VARCHAR(40)) <?php session_start(); if(!empty($_GET['logout'])) { session_destroy(); /* linken for å logge ut blir "login.php?logout=1" session_destroy(); fjerner alle satte $_SESSION-variabler */ } elseif(!empty($_POST['username']) && !empty($_POST['password'])) { foreach($_POST as $key => $value) { $$key = mysql_real_escape_string($value); /* vi looper igjennom alle $_POST verdier, der $key er "nøkkelen" (name-veltet i html-koden) og $value er det man skrev inn. $$key lager en variabel, så om $key == 'username' settes variabelen $username = mysql_real_escape_string($value) (altså verdien av $_POST['username']). Dette er en rask, enkel måte å sanitere all data som evt. skal brukes i en databasespørring så du slipper SQL-injection sårbarhet. */ } include("connect.php"); $tmp = mysql_query("SELECT * FROM `users` WHERE username = '".$username."' AND password = '".md5($password)."'"); /* merk funksjonen md5() I basen lagrer du ikke passordene, men en md5()-hash av passordet. Så sammenligner du md5()-hashen av det sendte passordet med hashen som ligger i basen. På denne måten kan ingen, inkludert degselv finne ut hva brukerenes passord er. */ if(mysql_num_rows($tmp) == 1) //sjekker at spørringen returnerte én rad, altså én bruker { $user = mysql_fetch_object($tmp); //henter ut data av spørringen som et objekt $_SESSION['username'] == $user->username; } } header('Location: index.php'); //sender brukeren direkte tilbake til index.php (eller f.eks. loginform.php eller whatever) ?> For sider/funksjoner bare innloggede brukere skal kunne se/bruke sjekker du enkelt og greit: if(!empty($_SESSION['username'])) { //bruker er innlogget } else { //bruker er ikek innlogget } Dersom du ønsker å lage noe forum-aktig utav det, eller i det minste ha muligheten til å svare på noen andres svar, må du legge til kolonnen "parentID (INT, default=0)" i gjestebok-basen din. Dette fungerer slik at om du skriver et innlegg som får ID 104 (og parentID 0 siden det er default), og jeg velger å svare på det får min post parentID 104. Slik bygger du opp en trestruktur. ID parentID 1 0 innlegg 1 2 0 innlegg 2 3 0 innlegg 3 4 2 svar på innlegg 2 5 2 enda et svar på innlegg 2 6 1 svar på innlegg 1 7 4 svar på "svar på innlegg 2" osv. Når det gjelder registrering av tid bør du bytte ut NOW() med UNIX_TIMESTAMP() (som i php tilsvarer funksjonen time() ). Disse returnerer antall sekunder siden 1. januar 1970 om jeg ikke tar helt feil, og for å konvertere det til et leselig format bruker du funksjonen date(). Eksempel: $innlegg[$i]['tid'] = date("d/m-Y H:i:s", $temp['tid']); //formatet blir f.eks. 22/10-2009 10:21:34 Edit: Lykke til! Bare å spørre om det er noe. Er ikke sikkert koden min fungerer sånn helt uten videre, klabba det bare sammen nå. =) Endret 22. oktober 2009 av PlastBox Lenke til kommentar
JarlG Skrevet 23. oktober 2009 Forfatter Del Skrevet 23. oktober 2009 Tusen takk for utruleg godt svar! Har ikkje fått gjort så mykje koding sidan sist, men har klart å lage eit lett login-system med ein simpel if-statement, altså ikkje noko database-relatert (enda - for eg skjønner korleis det skal gjerast ). Tidsfunksjonen har eg også fått til, samt ein sletteknapp dersom du er logga inn som admin. I tillegg så har eg lage ein funksjonell logut-knapp. Skal arbeide med eit registrasjonssytem knytta opp mot MySQL, som igjen skal brukast i samanheng med ein login-form. Har klart å laste opp forumet på (link under), men det har ein vesentlig forskjell frå det eg har på /localhost/; nye innlegg kjem under dei eldre. Har ikkje tenkt så lengje på det, men er det nokon kan forklare kvifor? Iom. at det er same kode som er brukt.. Gjesteboka / forumet / resultatet finn dykk her: forum.jarlg.comoj.com . Ser sjølvsagt sjølv at designet er elendig, men måtte berre fyre noko saman i CSS. Uansett, det er det indre som teller! Igjen, takk! Lenke til kommentar
Kris Skrevet 23. oktober 2009 Del Skrevet 23. oktober 2009 Website Under Review You see this page, because the system administrator of 000webhost.com is currently checking this website for malicious content. Så får ikke sett siden din =/ Lenke til kommentar
JarlG Skrevet 23. oktober 2009 Forfatter Del Skrevet 23. oktober 2009 (endret) Rart. Tilgjengelig for meg, og tydeligvis PlastBox. Nylig lagd, så er vel sikkert det. Endret 23. oktober 2009 av JarlG Lenke til kommentar
Kris Skrevet 23. oktober 2009 Del Skrevet 23. oktober 2009 Den er tilgjengelig for deg fordi det er du som har laget siden Lenke til kommentar
JarlG Skrevet 23. oktober 2009 Forfatter Del Skrevet 23. oktober 2009 Klarar å tenkje så langt, så eg seier at den er tilgjengeleg for PlastBox, også. Han har nemleg posta ein post! For øvrig så er eg klar over at det er skrivefeil på bl.a. "log ut"-knappen, ikkje påpek det. Setter pris på at du prøver å hjelpe, Kris! Lenke til kommentar
PlastBox Skrevet 23. oktober 2009 Del Skrevet 23. oktober 2009 Nå får jeg faktisk samme feilen som Kris sier. =P Lenke til kommentar
JarlG Skrevet 25. oktober 2009 Forfatter Del Skrevet 25. oktober 2009 (endret) Skulle vel tru det virker nå? EDIT: KURSIV TEKST ER LØST! Uansett, nå er den versjonen som er lagt ut er ikkje up-to-date lengre, eg seier ifrå når/om den blir det. EDIT: Oppdatert! Har nå prøvd meg på eit login og registrasjonssystem, og har fått til registreringa. Har laga ei ny 'login.php' som index.php header til, dersom "$_SESSION['admin']" ikkje er 'true'. I login.php så settes $_SESSION['admin'] til true dersom brukernavnet og passordet stemmer med ein row i databasen, og queryen berre returnerer ein linje. Deretter header den tilbake til index.php, etter at $_SESSION -variablene er satt. Problem: Jeg blir tatt tilbake til login.php, selv om session-variablene er satt! Kode: starten til index.php <?php session_start(); include "mysql/index.php"; // Behandler innlegg o.l. if ($_SESSION['admin'] != true && !isset($_SESSION['username'])) { // Dersom man ikke er logget inn header("Location: mysql/login.php"); // Gå til login-siden } ?> Logg inn og registrasjonsdel av login.php (er i toppen) <?php if (!empty($_POST['regUsername']) && !empty($_POST['regPassword'])) { include "connect.php"; $username = mysqli_real_escape_string($connect, $_POST['regUsername']); $password = md5(mysqli_real_escape_string($connect, $_POST['regPassword'])); $sqlRegisterUser = "INSERT INTO users SET username = \"$username\", password = \"$password\""; if (!mysqli_query($connect, $sqlRegisterUser)) { echo "Unable to create user; " . mysqli_error($connect); return false; }; header("Location: ../index.php"); } elseif (!empty($_POST['username']) && !empty($_POST['password'])) { include "connect.php"; $username = mysqli_real_escape_string($connect, $_POST['username']); $password = md5(mysqli_real_escape_string($connect, $_POST['password'])); $sqlCheckLogin = mysqli_query($connect, "SELECT * FROM users WHERE username = \"$username\" && password = \"$password\""); if (mysqli_num_rows($sqlCheckLogin) == 1) { if($_POST['username'] == 'jarlg') { $_SESSION['username'] = 'admin'; $_SESSION['admin'] = true; } else { $_SESSION['username'] = $username; } header("Location: ../index.php"); } else { header("Location: login.php"); }; }; ?> Heile login.php, om det er relevant <?php if (!empty($_POST['regUsername']) && !empty($_POST['regPassword'])) { include "connect.php"; $username = mysqli_real_escape_string($connect, $_POST['regUsername']); $password = md5(mysqli_real_escape_string($connect, $_POST['regPassword'])); $sqlRegisterUser = "INSERT INTO users SET username = \"$username\", password = \"$password\""; if (!mysqli_query($connect, $sqlRegisterUser)) { echo "Unable to create user; " . mysqli_error($connect); return false; }; header("Location: ../index.php"); } elseif (!empty($_POST['username']) && !empty($_POST['password'])) { include "connect.php"; $username = mysqli_real_escape_string($connect, $_POST['username']); $password = md5(mysqli_real_escape_string($connect, $_POST['password'])); $sqlCheckLogin = mysqli_query($connect, "SELECT * FROM users WHERE username = \"$username\" && password = \"$password\""); if (mysqli_num_rows($sqlCheckLogin) == 1) { if($_POST['username'] == 'jarlg') { $_SESSION['username'] = 'admin'; $_SESSION['admin'] = true; } else { $_SESSION['username'] = $username; } header("Location: ../index.php"); } else { header("Location: login.php"); }; }; ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="no" lang="no"> <head> <title> Forum </title> <link rel="shortcut icon" href="../elements/favicon.ico" type="image/x-icon" /> <link rel="stylesheet" type="text/css" href="../style.css" /> <script type="text/javascript" src="../javascript.js"> </script> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> </head> <body> <?php if (!isset($_GET['registrer'])) { ?> <form action="login.php" method="post" id="loginForm" > <div id="loginField"> <input type="text" name="username" id="loginUsername" value="Brukernavn" /> <input type="password" name="password" id="loginPassword" value="Brukernavn" /> <input type="submit" id="loginSubmit" value="Logg inn!" /> </form> <form action="" method="get"> <input type="hidden" name="registrer" value="true" /> <input type="submit" id="loginRegister" value="Registrer deg!" /> <div class="floatClear"> </div> </form> </div> <?php } else { ?> <form action="login.php" method="post" id="loginForm" > <div id="loginField"> <input type="text" name="regUsername" id="loginUsername" value="Brukernavn" /> <input type="password" name="regPassword" id="loginPassword" value="Brukernavn" /> <input type="submit" id="submitRegister" value="Registrer deg!" /> </form> </div> <?php }; ?> </body> </html> Føler det er noe ganske basic eg manglar, da det virker som at det er eit problem med at $_SESSIONS ikkje blir lagra etter at brukaren blir referert bort av header(); Sei om det er noko som ser usikkert ut, om det er noko som kunne vore gjort betre - for det er det sikkert, da eg ikkje forstod alle tipsene i din andre spoiler, PlastBox. Har markert det eg ikkje forstod: <?php session_start(); if(!empty($_GET['logout'])) { session_destroy(); /* linken for å logge ut blir "login.php?logout=1" session_destroy(); fjerner alle satte $_SESSION-variabler */ } elseif(!empty($_POST['username']) && !empty($_POST['password'])) { foreach($_POST as $key => $value) { $$key = mysql_real_escape_string($value); /* vi looper igjennom alle $_POST verdier, der $key er "nøkkelen" (name-veltet i html-koden) og $value er det man skrev inn. $$key lager en variabel, så om $key == 'username' settes variabelen $username = mysql_real_escape_string($value) (altså verdien av $_POST['username']). Dette er en rask, enkel måte å sanitere all data som evt. skal brukes i en databasespørring så du slipper SQL-injection sårbarhet. */ } include("connect.php"); $tmp = mysql_query("SELECT * FROM `users` WHERE username = '".$username."' AND password = '".md5($password)."'"); /* merk funksjonen md5() I basen lagrer du ikke passordene, men en md5()-hash av passordet. Så sammenligner du md5()-hashen av det sendte passordet med hashen som ligger i basen. På denne måten kan ingen, inkludert degselv finne ut hva brukerenes passord er. */ if(mysql_num_rows($tmp) == 1) //sjekker at spørringen returnerte én rad, altså én bruker { $user = mysql_fetch_object($tmp); //henter ut data av spørringen som et objekt $_SESSION['username'] == $user->username; } } header('Location: index.php'); //sender brukeren direkte tilbake til index.php (eller f.eks. loginform.php eller whatever) ?> Skal seiast at eg er elendig på arrays av alle typar, men begynner å skjønne at det er noko ein må kunne! FORRESTEN: Foreløpig behandler login.php alt med login, burde kanskje den POSTe til index.php som igjen behandler, istedenfor login.php? Er det kanskje feilen? Har nå endret det slik at index.php behandler alt, og det fungerer! TAKKER FOR SVAR! Endret 25. oktober 2009 av JarlG Lenke til kommentar
Anbefalte innlegg
Opprett en konto eller logg inn for å kommentere
Du må være et medlem for å kunne skrive en kommentar
Opprett konto
Det er enkelt å melde seg inn for å starte en ny konto!
Start en kontoLogg inn
Har du allerede en konto? Logg inn her.
Logg inn nå