Avatar billede m0nk3y Nybegynder
21. maj 2005 - 21:20 Der er 44 kommentarer og
1 løsning

Problemer med heltal!

Hej.

Jeg er igang med at lave en shop, hvor man skal kunne skrive antal i et textfelt. Der skal maximum kunne bestilles 300.

Jeg prøvede først at lave en if-sætning, hvor den tjekkede om min $_REQUEST["antal"] var over 0 og under 300, og ellers skulle der komme en fejl. Men den kunne ikke rigtig behandle min 'antal' som en integer, så prøvede jeg noget andet, hvor den køre en while-løkke op til 300 og hvor den så tjekkede hele tiden med en if-sætning om $i var ligemed $_REQUEST["antal"], hvis den så ikke havde fået en eneste positiv, så kom der fejl meddelse.
Det virkede såmen fint nok, MEN der er et lille problem, for hvis jeg skriver "16sdf4f" i mit antal-felt (uden anførelsestegn selvfølgelig) så kunne den godt tilføje det til kurven, da if-sætningen så 16sdf4f som 16, så når min $i nåede op til 16 gav den positivt fra sig.
Nogle der ved hvad jeg skal gøre? Enten en måde, så jeg kun kan skrive heltal i mit textfelt, og gøre så den ikke er under 1 og over 300, eller en idé til, hvordan jeg får min if-sætning til at være mere kritisk.

Håber der var nogle der forstod mig, det blev vidst lidt rodet, ellers må i lige spørge om flere detajler, eller en forenkelse.
Hæver med glæde pointene!

- Kristian Iversen
Avatar billede hmortensen Nybegynder
21. maj 2005 - 21:35 #1
Bør kunne bruge is_nummeric()

if (is_nummeric($var) && $var > 0 && $var < 301)
Avatar billede nielle Nybegynder
21. maj 2005 - 21:40 #2
$Antal = $_REQUEST["antal"];

$Lovlig = "JA";

if (is_numeric($Antal)
{
    // Det er ikke nog med en test vha is_numeric
    // Den tillader nemlig også tal som "1e3".
    if (preg_match("/[1-9]\d{0,2}/", $Antal))
    {
        if (0 < $Antal AND $Antal < 300)
        {
            // Lovlig værdi
        }
        else
        {
            $Lovlig = "NEJ";
        }
           
    }
    else
    {
        $Lovlig = "NEJ";
    }
}
else
{
    $Lovlig = "NEJ";
}
Avatar billede m0nk3y Nybegynder
21. maj 2005 - 21:44 #3
har lige afprøvet det og den siger bare:
Fatal error: Call to undefined function: is_nummeric() in D:\_WWWroot\Jens\shop4\index.php on line 18
Avatar billede hmortensen Nybegynder
21. maj 2005 - 21:46 #4
Fordi jeg ik kan stave :)
Der er kun et 'm' i
Avatar billede m0nk3y Nybegynder
21. maj 2005 - 21:47 #5
2 sek, ser det er en stavefejl. Men nu har jeg rettet den, og kan se at den ikke virker optimal som nielle også skriver, da jeg skrev 1e3 tilføjede den 100 antal af varen, til min indkøbskurv.
Men jeg prøver lige det script nielle har lavet.
Avatar billede m0nk3y Nybegynder
21. maj 2005 - 21:47 #6
forsent igen, det sker da også hver eneste gang! :/
Avatar billede nielle Nybegynder
21. maj 2005 - 21:50 #7
if (is_numeric($Antal) && preg_match("/[1-9]\d{0,2}/", $Antal) && 0 < $Antal && $Antal < 300)
    echo "Lovlig";
else
    echo "Ikke lovlig":
Avatar billede nielle Nybegynder
21. maj 2005 - 21:52 #8
Grunden til at "1e3" accepteres af is_numeric er at det faktisk er et lovligt tal. Det er "videnskabelig notation" (også kaldet "Euler notation" somme tider).

Betyden af 1e3 er: 1 * 10^3 = 1000
Avatar billede m0nk3y Nybegynder
21. maj 2005 - 21:55 #9
og det vil det også gøre ved det du lavede?
Fordi så må det jo blive sådan, hvis det ikke kan være anderledes, folk må også kunne se, hvis der ligger 100 af en vare for meget i kurven.

Men jeg tester endnu, jeg tilpasser lige koden resten af min kode, da den er lidt kringlet.
Avatar billede nielle Nybegynder
21. maj 2005 - 21:59 #10
Ved det ekstra tjek jeg har tilføjet - preg_match("/[1-9]\d{0,2}/", $Antal) - sikre man sig at set indtastede består af ét cifre mellem 1-9 og mellem 0-9. Dette tjek sikre altså at det der er indtastet er en af tallene '1', '2', ..., '999'.

Og nej, 1e3 vil ikke passere denne test som ok.
Avatar billede m0nk3y Nybegynder
21. maj 2005 - 21:59 #11
Det ser ud til at virke nogenlunde, dog kan jeg godt tilføje varer med decimaler, så hvis jeg skriver 1.5 så får jeg halvanden vare. Er det noget der kan gøres noget ved?
Avatar billede nielle Nybegynder
21. maj 2005 - 22:06 #12
Den slags tal burde testen preg_match("/[1-9]\d{0,2}/", $Antal) altså ikke lade slippe igennem!
Avatar billede nielle Nybegynder
21. maj 2005 - 22:07 #13
Ahhh! En fejl. ERet testen til:

preg_match("/^[1-9]\d{0,2}$/", $Antal)

Altså:

if (is_numeric($Antal) && preg_match("/^[1-9]\d{0,2}$/", $Antal) && 0 < $Antal && $Antal < 300)
Avatar billede ksoren Nybegynder
21. maj 2005 - 22:10 #14
nielle, hvorfor insisterer du på at teste med is_numeric?

det regulære udtryk vil altid sørge for at det er et tal..
Avatar billede nielle Nybegynder
21. maj 2005 - 22:12 #15
Hvad kan jeg sige - tidlig senilitet :^)
Avatar billede hmortensen Nybegynder
21. maj 2005 - 22:16 #16
Vil tror det her er mindre krævende end reg.exp:
if ($Antal == (int)$Antal && $Antal > 0 && $Antal < 301)

$Antal == (int)$Antal tester om det er et heltal
Avatar billede nielle Nybegynder
21. maj 2005 - 22:20 #17
Hvad får dig til at tro at regulære udtryk er langsomme? - ikke at det heller han nogen praktisk betydning i dette tilfælde med kun et tal.
Avatar billede hmortensen Nybegynder
21. maj 2005 - 22:26 #18
Fra manualen (http://dk2.php.net/preg_match)
Do not use preg_match() if you only want to check if one string is contained in another string. Use strpos() or strstr() instead as they will be faster.

Vil tro at det samme gælder her.
Avatar billede m0nk3y Nybegynder
21. maj 2005 - 22:29 #19
Jamen, det ser jo ud til at virke nielle.

I har begge hjulpet meget, så jeg synes da i har fortjent 100 point hver. Hvad siger i til at nielle lægger et svar her, og at jeg så opretter et nyt spm til hmortensen?
Avatar billede nielle Nybegynder
21. maj 2005 - 22:30 #20
Eftersom dit alternativ - (int)$Antal - involvere en konvertering af en tekst-streng til et tal, så er jeg bestemt ikke sikker på at det faktisk ikke er mere effektivt at bruge et regulært udtryk i dette tilfælde.

Generelt kan jeg fortælle at motoren nede under regulære udtryk er endog meget effektivt implementeret.
Avatar billede hmortensen Nybegynder
21. maj 2005 - 22:31 #21
Ligemeget med point.
Bare det virker for dig. Det er trodsalt det, det drejer sig om.
Avatar billede m0nk3y Nybegynder
21. maj 2005 - 22:32 #22
ja, men du har jo trodsalt også brugt tid på det, så jeg synes da også du skal have noget ud af det...
Avatar billede ksoren Nybegynder
21. maj 2005 - 22:34 #23
Jeg har lige lavet en benchmark af de to metoder, og den regulære metode er klart den langsomste
Avatar billede hmortensen Nybegynder
21. maj 2005 - 22:35 #24
Et lille sidespring:
Hvordan laver du den benchmark ?
microtime start/slut ?
Avatar billede ksoren Nybegynder
21. maj 2005 - 22:36 #25
<?php
$antal = 50;

$start = time();
for($i=0; $i<3000000; $i++){
    $result = $antal == (int)$antal && $antal > 0 && $antal < 301;
}
$varighed = time() - $start;
echo "hmortensen's metode: $varighed<br>";


$start = time();
for($i=0; $i<3000000; $i++){
    $result = preg_match("/^[1-9]\d{0,2}$/", $antal) && 0 < $antal && $antal < 300;
}
$varighed = time() - $start;
echo "den regulære metode: $varighed<br>";


?>

resultat:

hmortensen's metode: 8
den regulære metode: 30
Avatar billede hmortensen Nybegynder
21. maj 2005 - 22:44 #26
Kunne vidst godt bruge en anden server :)
hmortensen's metode: 18
den regulære metode: 80
Avatar billede nielle Nybegynder
21. maj 2005 - 22:51 #27
For the record: Nu har jeg også lavet en benchmark - godt nok i C# - og der var RexExp metoden ca. dobbelt så langsom som casting-metoden. Det er ikek hvad jeg ville kalde "væsentlig langsommere" men det er trods alt langsommere.
Avatar billede nielle Nybegynder
21. maj 2005 - 22:52 #28
Hvis jeres benchmark skulle være mere troværdigt så testede I ikke kun for et fast tal $antal = 50.
Avatar billede nielle Nybegynder
21. maj 2005 - 23:02 #29
Mine tal - efter at have efterlignet benchmarken så godt som det er muligt i C# - er:

hmortensen's metode: 1,86 sek.
den regulære metode: 3,78 sek.

Med den faste væredi Antal = 50 og 3000000 iterationer.
Avatar billede nielle Nybegynder
21. maj 2005 - 23:16 #30
Bortset fra al den interessante snak som performance, så har hmortensen’s metode stadig den svaghed at den lader tal på formen "1e2" passere igennem som godkendte. Dette kan give interessante problemer når værdien af $antal skal skrives til databasen.
Avatar billede nielle Nybegynder
21. maj 2005 - 23:20 #31
Kort sagt kan man sige at testen på "is_numeric($antal)" og "$antal==(int)$antal" har nødagtig de samme styrker og svagheder.

Og det var jo faktisk netop for at fikse ovennævnte svaghed ved is_numeric, at jeg overhovedet indførte preg_match i løsningen i første omgang.
Avatar billede hmortensen Nybegynder
21. maj 2005 - 23:21 #32
Gør den altså ikke her.

Har lagt et eksempel her:
http://test.no-mercy.dk/1.php
Avatar billede nielle Nybegynder
21. maj 2005 - 23:32 #33
Cool. My bad. Troede at (int) virkede som en typecast men den er altså virkeligt snarere et tjek.
Avatar billede hmortensen Nybegynder
21. maj 2005 - 23:33 #34
Hvis vi har
$var = "1e2";
og så udskriver
echo (int)$var;
vil det give 1

og vi er enige om at "1e2" og "1" ikke er det samme :)
Avatar billede nielle Nybegynder
21. maj 2005 - 23:45 #35
Hvad hvis du nu ikke har "-tegn rundt om din værdi? Altså:

$var = 1e2;
echo (int)$var;
Avatar billede hmortensen Nybegynder
21. maj 2005 - 23:48 #36
Ikke testet, MEN det her kommer fra en form, og vil derfor være en string.
Avatar billede m0nk3y Nybegynder
21. maj 2005 - 23:51 #37
Nå, men ved i hvad. Jeg tror jeg snart går i seng, så hvis der var nogle der skulle have nogle point, så må i lige smide et svar, ellers tager jeg dem til mig igen.
Avatar billede hmortensen Nybegynder
21. maj 2005 - 23:53 #38
Ik mig.
Vi har allesammen lært lidt her ;)
Avatar billede nielle Nybegynder
21. maj 2005 - 23:57 #39
21/05-2005 23:48:45> Se *det* er jo værd at få testet efter. Er vi nu også 100% sikker på at vi får teksten "1e2" og ikke tallet 1e2 fra $_POST("antal")? :^|

m0nk3y> Tag du dem bare igen - det er som hmortensen siger. Under alle omstændigheder er 100 point alt for meget for en opgave som denne. :^)
Avatar billede hmortensen Nybegynder
22. maj 2005 - 00:00 #40
Data fra en form gir string, men tester da lige for god ordens skyld
Avatar billede ksoren Nybegynder
22. maj 2005 - 00:01 #41
hmortensen's metode har en anden svaghed:

$var = "2 en streng";
echo ((int)$var) == $var;

giver true, da venstre side er en integer, og højre side derfor bliver casted til en integer inden sammenligning. Dvs den sammenlinger: 2 == 2
Avatar billede hmortensen Nybegynder
22. maj 2005 - 00:07 #42
"2 en streng" går ikke igennem.

Har lige prøvet med en form, og der går 1e2 heller ikke igennem.
Avatar billede ksoren Nybegynder
22. maj 2005 - 00:16 #43
Den går nu fint igennem her.

<?php
$antal = "2 en streng";

if($antal > 0) echo "ok1<br>";
if(((int)$antal) == $antal) echo "ok2<br>";
if($antal == (int)$antal && $antal > 0 && $antal < 301) echo "ok3<br>";
?>

resultat:
ok1
ok2
ok3
Avatar billede hmortensen Nybegynder
22. maj 2005 - 00:21 #44
Min fejl, det gør den faktisk.
Avatar billede hmortensen Nybegynder
22. maj 2005 - 00:28 #45
Så skulle der ik være nogle smuthuller:
if (is_numeric($tal) && $tal == (int)$tal && $tal > 0 && $tal < 301)
Avatar billede Ny bruger Nybegynder

Din løsning...

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.

Loading billede Opret Preview
Kategori
Vi tilbyder markedets bedste kurser inden for webudvikling

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester