12. juli 2012 - 21:07Der er
22 kommentarer og 2 løsninger
Problemer med if-sætning med dobbelt kontrol
Hej Eksperter,
Er løbet ind i et lille problem, der nok bunder i jeg ikke helt har fanget hvordan if-else-sætninger virker.
Jeg vil gerne lave en lille kontrol, for at sikre at navn og nr på en nyoprettet sag er unik. Problemet er at den fanger at både navn og/eller nr allerede er oprettet, men tilføjer alligevel sagen i databasen. Hvad gør jeg galt siden sidste "else" del ikke spriges over?
- - - - - kode - - - - -
// Kontrollerer at navn og sag er unikke $hent_data = mysql_query("select * from sager") or die(mysql_query()); while($data = mysql_fetch_array($hent_data)) { extract($data); if($navn == $_POST['navn'] || $nr == $_POST['nr']) { if($navn == $_POST['navn']) { $_SESSION['status_r'] = "Der er allerede oprettet en sag med det navn. - Sagen er ikke oprettet."; } if($nr == $_POST['nr']) { $_SESSION['status_r'] = "Der er allerede oprettet en sag med det nummer. - Sagen er ikke oprettet."; } } else { // Tilføjer til DB mysql_query("INSERT into sager (navn, nr)" . "VALUES('" . $_POST['navn'] . "', ' " . $_POST['nr'] . "')"); $_SESSION['status_g'] = "Sagen <b>" . $_POST['navn'] . "</b> er blevet tilføjet"; } } // Linker tilbage ?>
Teknologi, AI og forretning er i centrum på Computerworlds Cloud og AI Festival i København d. 18. og 19. september. Se hele programmet for den store konference om strategisk brug af Cloud og AI på: www.cloud-festival.dk
// Kontrollerer at navn og sag er unikke $hent_data = mysql_query("select * from sager") or die(mysql_query()); while($data = mysql_fetch_array($hent_data)) { extract($data); if($navn == $_POST['navn'] || $nr == $_POST['nr']) { if($navn == $_POST['navn']) { $_SESSION['status_r'] = "Der er allerede oprettet en sag med det navn. - Sagen er ikke oprettet."; } else if($nr == $_POST['nr']) { $_SESSION['status_r'] = "Der er allerede oprettet en sag med det nummer. - Sagen er ikke oprettet."; } else { // Tilføjer til DB mysql_query("INSERT into sager (navn, nr)" . "VALUES('" . $_POST['navn'] . "', ' " . $_POST['nr'] . "')"); $_SESSION['status_g'] = "Sagen <b>" . $_POST['navn'] . "</b> er blevet tilføjet"; } } } // Linker tilbage
Meningen med opdelingen af if-sætningen var at gøre det muligt at fortælle hvilken fejl der var. Om det var nummeret, eller navnet der allerede var oprettet.
syntes jeg havde prøve med en else if. Gør det forskel om der er mellem mellem else og if alle "elseif" eller "else if" ?
#5: Hvis koden virker, forstår jeg ikke, hvad du spørger om. I spørgsmålet skriver du, at koden ikke virker som ønsket(?)
Der er ikke nogen forskel i virkningen af, om du skriver elseif eller else if. Derimod er der, som lclemens skriver, marginal forskel på afviklingshastigheden
"I PHP hedder det "}elseif{" uden mellemrum hvor det i Javascript hedder "}else if{" med mellemrum." >> Ja i JavaScript godtages kun med mellemrum. Nej, i PHP er begge lige gyldige.
"Olebole > I dit kode eksempel der vil koden efter "}else{" aldrig blive udført. Altså der bliver aldrig gemt noget i databasen." >> Det er til gengæld korrekt =)
Men der ingen grund til at PHP tygger sig igennem alle rækker i tabellen med: select * from sager Put en WHERE på, med passende betingelser, og lad databasen om at gøre arbejdet.
- undeforstået, at man godt kan lave en OR i en WHERE klausul, men der skal ske noget forskelligt, hvis den ene eller den anden er sat i $_POST, så man slipper ikke for en if/else i PHP =)
#5 Det var et tilfælde at det virkede efter hensigten (Der var kun en linie gemt i DB'en), da jeg kom lidt videre fandt jeg der stadig var en fejl. Koden er forkert skrevet. I tilfælde af der er sammenfald mellem navn og nr i databasen, vil der kun være et sammenfald, ud af samtlige dataudtræk. De resterende gange vil der blive tilføjet en ny linie i databasen.
Skal have lavet koden om, som erikjacobsen foreslår, skal den kun hente data fra tabellen hvor nr og navn er sammenfaldende
Både navn og nr er tilsyneladende unikt og tilsyneladende har du ikke UNIQUE index på hverken navn eller nr idet du kan oprette flere sager med samme nummer eller navn.
Her er hvordan man sætter et index på en tabel (det er dødnemt i phpMyadmin):
ALTER TABLE sager ADD UNIQUE nr_idx (nr); ALTER TABLE sager ADD UNIQUE navn_idx (navn);
Så er du fri for dine if'er og kan lade DB tage sig af det den er god til og lave en
$qry = mysql_query("INSERT into sager (navn, nr)" . "VALUES('" . $_POST['navn'] . "', ' " . $_POST['nr'] . "')") or die(mysql_error)); ### eller errno if (!$qry){ $_SESSION['status_r'] = "Navn eller nummer er optaget. Sagen er ikke oprettet."; }
Indrømmet - her skelnes ikke på hvilken af variablerne der er forkerte, men det kan løses ved at arbejde med teksten fra mysql_error eller mysql_errno.
#15 Det endte med noget i den stil. Jeg er lidt stærkere i php, så brugte en if sætning til at fastlægge fejlen. Smart med at lave navn og nr unik i DB'en.
Nå, jeg kan vist godt lukke. Jeg siger mange tak for svarene, fik løst problemet, og blev samtidig lidt klogere :)
Det må blive en deler mellem vagn og ole, så læg et svar så jeg kan lukke.
For at være sikker på, det er 'det rigtige' der er gået galt ved indsætningen, burde du nok skrive sådan:
if (mysql_errno()==1062){ $_SESSION['status_r'] = "Navn eller nummer er optaget. Sagen er ikke oprettet."; }
Til gengæld tror jeg ikke vagnk har ret. Mysql smider en fejl 1062 ved 'duplicate entry', men kan ikke skelne mellem felterne. Så skal man igang med at parse teksten i mysql_error, men det er næppe særlig hensigtsmæssigt =)
Undskyld jeg ikke har været på mailen i et par dage.
Coder: Når Ole ikke vil have point synes jeg vi to skal dele. Jeg skal ikke tjene på Oles storsind. På den anden siden har du fået en ide, så...
Ole har ret med at du får en fejlmelding der ikke siger hvilket af felterne den er gal med. Problemet kan løses ved at du i den formular der danner $_POST['navn'] og $_POST['nr'] laver en "SELECT max(nr) FROM sager". Du lægger 1 til og præsenterer tallet så brugeren ikke kan ændre det og gemmer tallet i en type='hidden'. Nu kan der så bare være to brugere der på samme tid får det samme sagsnummer og det vil gå galt når den sidste af dem opdaterer. Men så har du jo dit check på den side vi har behandlet her og brugeren ryger tilbage med en fejlmelding der siger noget som "på grund af travlhed på serveren". Hvis et sådant clash skulle forekomme en gang hver tredie måned vil det være til at leve med. Hvis det skulle kunne forekommen flere gange om dagen må du i gang med transactional processing - men det er en helt anden historie.
En måske bedre løsning: Lad vær med overhovedet at blande brugeren ind i det med sagsnummer under oprettelsen. Han opretter en sag og når du lægger den i DB, finder du det nye sagsnummer med en max(nr) og indsætter sagen. Dermed har du effektivt elimineret en mulighed for brugerfejl, og det er jo det det drejer sig om i moderne it.
Ole: Du har stadig ret med prepared statements. Min undskyldning her er at jeg skrev det direkte som jeg ville skrive det i en kommandolinje.
@Vagn: Dig gider jeg slet ikke forsøge at påvirke i den retning. Det er ikke noget personligt, men jeg mener, du har den fornødne viden til selv at træffe velovervejede beslutninger om, hvad du vil bruge. Det er dog ikke at forveksle med evig enighed i alle kroge *o)
Jeg skriver såmænd også selv ofte eksempler i MySQL, fordi det er, hvad spørgeren forstår og kan bruge 'lige nu'. Derefter prøver jeg så at råde dem til at bruge PS.
Idéen med at fange og handle på en 1062 er udmærket. Egentlig er min holdning, at det i udgangspunktet er skidt at 'bygge på fejl'. Undtagelsen er denne slags situationer, som ikke kan forventes at opstå med større frekvens, end den med hvilken en visionær tanke rammer en dansk politiker =)
Derfor bør du efter min mening have pointene - men det er ikke mit valg.
Kære Ole Jeg lærer skam noget hver gang du er med på en tråd.
Vi er helt enige om PS. Efter at jeg for et års tid siden selv blev ramt af en injection (tydelig men heldigvis uskadelig) har jeg været igennem de fleste af min kodestumper. Det har så samtidig resulteret i bardunstramning og en bedre strukturering.
Tak. Ja, refactoring er altid en god ting. Det hørte jeg mine hovedrystende og pandeklaskende forældre samtale om gennem hele min opvækst. Jeg arbejder stadig på at finde ud af, hvad de præcist mente *LoL*
#19 - Jeg ville også gerne slippe for at brugeren selv skal skrive sagsnummeret ind, og styre det automatisk. Problemet er at den kode jeg skriver, skal fungere som et supplement til et andet system (Noget så primitivt som et manuelt excel-ark :) ), hvorfra sagsnumrene kommer fra. Dog burde sammenfald af indtastninger ikke være et problem, eftersom der kun er en enkelt bruger der har rettigheder til at oprette nye sager.
Hvis jeg absolut selv skal have nogle af pointene, så skal du altså belemres med den anden halvdel.
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.