Moikka
Aloitin harjoittelemaan MySQL:ää, kun sitä niin moneen paikkaan tarvitsee.
Putkan oppaan perusteella loin tämmöisen koodin.
<?php echo "<html><body>"; $yhteys = mysql_connect("localhost", "tunnus", "salasana"); CREATE TABLE varasto (nimi TEXT, hinta INT (6), maara INT (4)); INSERT INTO varasto (nimi, hinta, maara) VALUES ('laskin', '10', '10'); INSERT INTO varasto (nimi, hinta, maara) VALUES ('kamera', '120', '5'); INSERT INTO varasto (nimi, hinta, maara) VALUES ('televisio', '950', '5'); //haetaan kaikki tavarat $kysely = "SELECT * FROM varasto"; //suoritetaan kysely $haku = mysql_query($kysely, $yhteys) or die("Virhe kyselyssä!"); echo "<table border>"; echo "<tr><td><b>nimi</b></td><td><b>hinta</b></td><td><b>määrä</b></td></tr>"; //käydään tavarat läpi for ($i = 0; $i < mysql_num_rows($haku); $i++) { //haetaan nimi, hinta ja määrä muuttujiin $nimi = mysql_result($haku, $i, "nimi"); $hinta = mysql_result($haku, $i, "hinta"); $maara = mysql_result($haku, $i, "maara"); //tulostetaan taulukon rivi echo "<tr><td>$nimi</td><td>$hinta €</td><td>$maara kpl</td></tr>"; } echo "</table>"; echo "</body></html>"; ?>
Tämä vaan ei toimi, ei tulosta mitään. Mistä johtuu? :O
Rocceri kirjoitti:
CREATE TABLE varasto (nimi TEXT, hinta INT (6), maara INT (4)); INSERT INTO varasto (nimi, hinta, maara) VALUES ('laskin', '10', '10'); INSERT INTO varasto (nimi, hinta, maara) VALUES ('kamera', '120', '5'); INSERT INTO varasto (nimi, hinta, maara) VALUES ('televisio', '950', '5');
Nää pitää ajaa myös omina kyselyinä, kuten teet "SELECT *":n kanssa. Lisäksi kannattaa katsella virheilmoituksia, ja päätellä niiden perusteella missä mennään vikaan.
Ahaa..
mysql_query(CREATE TABLE varasto (nimi TEXT, hinta INT (6), maara INT (4))); mysql_query(INSERT INTO varasto (nimi, hinta, maara) VALUES ('laskin', '10', '10')); mysql_query(INSERT INTO varasto (nimi, hinta, maara) VALUES ('kamera', '120', '5')); mysql_query(INSERT INTO varasto (nimi, hinta, maara) VALUES ('televisio', '950', '5'));
Tämä tuskin on oikea tapa kun tekee errorin 500.
Koitin laittaa
mysql_query("CREATE TABLE varasto (nimi TEXT, hinta INT (6), maara INT (4))"); mysql_query("INSERT INTO varasto (nimi, hinta, maara) VALUES ('laskin', '10', '10')"); mysql_query("INSERT INTO varasto (nimi, hinta, maara) VALUES ('kamera', '120', '5')"); mysql_query("INSERT INTO varasto (nimi, hinta, maara) VALUES ('televisio', '950', '5')");
mutta nyt tämä sanoo, että virhe kyselyssä.
https://www.php.net/function.mysql-query ->> Example #2 Valid Query
Katseles tuolta miten sun koodi eroaa tuosta.
Kyllä nuo queryt toimii ainakin suoraan mysqliin laitettuna ihan oikein. Millä rivillä ja mikä se sun virhees on tarkemmin mikä tulee ?
Eli pitäisi tehdä esimerkiksi funktio $query ja antaa sitten arvoksi se mysql kysely. Esim $query = "SELECT * From varasto"; ja sitten hakea sitä mysql_query($query, $yhteys); tai mysql_query($query);?
TeNDoLLA: Tältä näyttää, en osaa sanoa mikä on virhe. En katsos itse pääse käsiksi error logiin.
<?php echo "<html><body>"; $yhteys = mysql_connect("localhost", "tunnus", "salasana"); mysql_query("CREATE TABLE varasto (nimi TEXT, hinta INT (6), maara INT (4))"); mysql_query("INSERT INTO varasto (nimi, hinta, maara) VALUES ('laskin', '10', '10')"); mysql_query("INSERT INTO varasto (nimi, hinta, maara) VALUES ('kamera', '120', '5')"); mysql_query("INSERT INTO varasto (nimi, hinta, maara) VALUES ('televisio', '950', '5')"); //haetaan kaikki tavarat $kysely = "SELECT * FROM varasto"; //suoritetaan kysely $haku = mysql_query($kysely, $yhteys) or die("Virhe kyselyssä!"); echo "<table border>"; echo "<tr><td><b>Nimi</b></td><td><b>Hinta</b></td><td><b>Määrä</b></td></tr>"; //käydään tavarat läpi for ($i = 0; $i < mysql_num_rows($haku); $i++) { //haetaan nimi, hinta ja määrä muuttujiin $nimi = mysql_result($haku, $i, "nimi"); $hinta = mysql_result($haku, $i, "hinta"); $maara = mysql_result($haku, $i, "maara"); //tulostetaan taulukon rivi echo "<tr><td>$nimi</td><td>$hinta €</td><td>$maara kpl</td></tr>"; } echo "</table>"; echo "</body></html>"; mysql_close($yhteys); ?>
Virhe johtuu siitä, ettet valitse käytettävää tietokantaa ollenkaan.
<?php $yhteys = mysql_connect("localhost", "sdad", "ndas") or die(mysql_error()); mysql_select_db('tietokanta') or die(mysql_error()); // valitaan kanta ?>
Lisäksi saisit tietää oikeasti sen errorin jos käyttäisit tämän sijasta:
<?php $haku = mysql_query($kysely, $yhteys) or die("Virhe kyselyssä!"); ?>
Tätä:
<?php $haku = mysql_query($kysely, $yhteys) or die(mysql_error()); ?>
Joka ilmoittaa aika selvästi erroriksi, että "No database selected".
Juu, nyt toimii :)
Paitsi, että kun päivittää sivun/tulee sille uusiksi tämä luo uudelleen tuon taulukon. Eli tulee lisää taulukoita siihen.
Mistä johtuu? :O
EDIT: Tein uuden harjoituksen.
<?php echo "<html><body>"; //Määritetään yhteydet $yhteys = mysql_connect("localhost", "tunnus", "salasana"); mysql_select_db('yllapito') or die("Tietokantaa ei löytynyt"); mysql_query("CREATE TABLE autot (Nimi TEXT, Hinta INT (6), Maara INT (4))"); mysql_query("INSERT INTO autot (Nimi, Hinta, Maara) VALUES ('BMW 530i', '76900', '1')"); mysql_query("INSERT INTO autot (Nimi, Hinta, Maara) VALUES ('BMW 330iX', '52950', '1')"); $kysely = "SELECT * FROM autot WHERE nimi = 'BMW 530i' or nimi = 'BMW 330iX'"; $haku = mysql_query($kysely, $yhteys); echo "<table border>"; echo "<tr><td><b>Nimi</b></td><td><b>Hinta</b></td><td><b>Määrä</b></td></tr>"; //käydään tavarat läpi for ($i = 0; $i < mysql_num_rows($haku); $i++) { //haetaan nimi, hinta ja määrä muuttujiin $nimi = mysql_result($haku, $i, "Nimi"); $hinta = mysql_result($haku, $i, "Hinta"); $maara = mysql_result($haku, $i, "Maara"); //tulostetaan taulukon rivi echo "<tr><td>$nimi</td><td>$hinta €</td><td>$maara kpl</td></tr>"; } echo "</table>"; echo "</body></html>"; mysql_close($yhteys); ?>
Sivulla on nyt siis kaksi autoa taulukossa. Kun sivun päivittää, niin sivulle ilmestyy samat autot toisen kerran.. Niin jatkuu, että tulee joka päivityksestä aina kumpaakin autoa yksi lisää..
Totta kai kun teet joka kerta samat kyselyt.
Trilogin vastaus siis suomennettuna, jotta varmasti puhutaan samasta asiasta. Poista siis nuo CREATE ja INSERT lauseet, riittää kun ne kerran ajetaan. Lisäksi kannattaa heti opetella käyttämääm tietokantaa aina jotakin turvallista rajapintaa pitkin, jotta kyselyt olisivat mahdollisimman turvallisia.
Periaatteessa nuo kyselyt kannattaa eristää normaaleilta käyttäjiltä. Tällöin siis normaali kirjautumaton käyttäjä ei saa suoritettua esimerkiksi DELETE, INSERT, DROP, ALTER yms "vaarallisia" komentoja. Mielummin sallitaan tavalliselle käyttäjälle ainoastaan etukäteen mietityt ja turvallisiksi muunnetut SELECT kyselyt.
Tämä tuntuu tietysti tylsältä ja turhalta, koska teet luultavasti sivuja vielä vain itsellesi. Tämä jorina onkin tarkoitettu tilanteeseen, jossa teetkin julkiselle palvelimelle sivua, joka käyttää tietokantaa. Ei ole nimittäin kivaa palautella tietokantaa vaikkapa suhteellisen suositulle foorumille, kun varmuuskopiot on vaikkapa vain 3 tuntia vanhat. Tuossa ajassa saattaa tulla useitakin viestejä, jotka siis häviävät, kun varmuuskopiot palautetaan.
Osittain tästäkiin syystä rajoittaisin mysql_error() funktion näyttämistä normaaleille käyttäjille, koska se ikävä kyllä sisältää liian arkaluontoista dataa muun muassa taulujen ja kenttien nimet.
Tuon mysql_error():n näyttämiseen voisi käyttää jotain tämän tyylistä:
<?php function db_query($query) { global $conf; if ($conf['admin']) return mysql_query($query) or die(mysql_error()); else return mysql_query($query); } $result = db_query("SELECT * ..."); ?>
Tästä varmasti päästään vielä turvallisempaan ja viisaampaan ratkaisuun, mutta siinä tulee omat taitoni vastaan.
Itse ehkä tekisin jotenkin seuraavasti:
<?php /** * Ladataan asetukset * Tuottaa $kayttaja[...] taulukon */ require("liita/asetukset.php"); /* Osittain debuggausta varten */ $hakuLauseke = "SELECT CONCAT(etunimi, ' ' , sukunimi) AS nimi FROM henkilot ORDER BY sukunimi"; $henkilot = mysql_query($hakuLauseke, $yhteys); if($kayttaja['oikeus'] > MODERAATTORI && !$henkilot){ $kpl = $sivu->createElement("p", "Virhe kyselyssä {$hakuLauseke}" . mysql_error()); $sisaltoSolmu->appendChild($kpl); }else{ /* Haku onnistui */ } ?>
trilog kirjoitti:
Totta kai kun teet joka kerta samat kyselyt.
Miten voin rajoittaa sen niin, että se tekee tämän vain kerran?
Rocceri kirjoitti:
trilog kirjoitti:
Totta kai kun teet joka kerta samat kyselyt.
Miten voin rajoittaa sen niin, että se tekee tämän vain kerran?
Jaa-a, riippuu ihan toteutuksesta. Täällä putkassa esimerkiksi tarkastetaan onko tähän viestilaatikkoon jotain kirjoitettu, ja jos on, lisätään uusi viesti tietokantaan INSERT -lauseella.
Voit vaikka laittaa eteen ehdon
<?php if (!empty($_GET['lisaa_auto'])) { mysql_query("INSERT INTO autot (Nimi, Hinta, Maara) VALUES ('".$_GET['lisaa_auto']."', '76900', '1')"); } ?>
Ja sitten voit vaikka tehdä lomakkeen, tai linkin jolla voit lisätä auton niin halutessasi.
Esimerkkini on vähän huono, sillä se mahdollistaa sql-injektion. Mutta taitaa olla tässä vaiheessa vähän turhan aikaista alkaa luennoimaan siitä.
Rocceri kirjoitti:
trilog kirjoitti:
Totta kai kun teet joka kerta samat kyselyt.
Miten voin rajoittaa sen niin, että se tekee tämän vain kerran?
Luitko tuota mun viestiä, jossa kehoitin sinua poistamaan kyseiset rivit. Niiden tarkoitus on siis ensinnäkin luoda sopiva taulu, johon noita auton tietoja lisätään. Toisekseen Niiden tarkoitus on lisätä kahden auton tiedot kyseiseen tauluun.
Muuten, kun tuota harjoitusta koodailen, niin miten voi antaa yhdelle empty arvolle monta tarkistettavaa?
Jos laittaa
if (!empty($_GET['lisaa_auto'])) { tee jotain }
niin voiko laittaa
if (!empty($_GET['lisaa_auto'] && $_GET['lisaa_hinta'])) { tee jotain }
vai miten pitäisi tehdä?
Sinun vaihtoehdon oikea muoto on:
Mutta voit myös tehdä tuosta funktion, ettei tarvitse kirjoitella samaa koodia moneen kertaan:
Etsitkö tapaa päivittää tietoa kantaan? Sinulla lienee jokin lomake, jossa on nuo kyseiset tiedot eikös vaan? Mikäli näin voisit kokeilla seuravaa tapaa hoitaa asia.
<?php if(isset($_GET['lisaa_auto'])){ $kysely = "UPDATE autot SET Nimi = '$nimi', Hinta = $hinta, Maara = $maara WHERE auto_id = $id LIMIT 1"); echo $kysely; /* Jos tuntuu hyvältä, niin aja kantaan, muutoin korjaa kysely */ } ?>
Eli siis tuossa koodissa on virhe, joka sinun tulee korjata. Tämä ei ole vinoilumielessä kirjoitettu viesti, vaan tämän tarkoituksena on opettaa sinulle ongelman ratkaisua. Virhe on helppo havaita, kun tulostat tuon kyselyn.
Tein näin:
Älä tee noin! Ensinnäkin hinta ja määrä ovat numeraaleja, joten niitä ei kuulu laittaa hipsujen sisään. Toisekseen tuo kysely on todella vaarallinen, koska se sisältää vaarallisen helpon injektiovaaran. Käytä mielummin tuota minun edellä mainitsemaani tapaa, jossa lomakkeelta tullut data käsitellään muuttujaksi.
Korostan tässäkin langassa asiaa, eli koskaan ei saa ajaa kantaan kyselyä, jonka sisällöstä ei olla ihan varmoja.
Joo, voisin käyttääkkin. En vaan huomannut ennen kun postasin omani... 26 sekuntia eroa. :D
Jatkoin harjoittelua, ja tein tämmöisen ns. verkkokaupan. MySQL taulut jne. on kunnossa. Kun sivulle saavutaan, niin koodin pitäisi asettaa keksi jossa on sisältömä kelloaika jolloin sivulle on saavuttu.
Tämä kuitenkin printtaa tälläisen varoituksen sivulle:
Warning: Cannot modify header information - headers already sent by (output started at C:\xampplite\htdocs\sql.php:3) in C:\xampplite\htdocs\sql.php on line 8
Tältä riviltä löytyy juuri tuo setcookie. Mitä tämä tarkoittaa?
Toinen juttu.
Jos käyttäjällä on 100 euroa käytössä, niin tämä heitetään myös keksiksi. Sitten jos kävijä ostaa 15 eurolla vaikka elokuvia, niin 100 eurosta lähtee tämä 15. Miten PHP:llä lasketaan tämmöinen 100 - 15 lasku?
Entä, mikä olisi järkevin tapa tuohon äskeiseen laskutoimitukseen:
Jos käyvijä ostaa tavaran, niin poistanko keksin ja asetan uudelleen, vai voiko tämän korvata jotenkin?
Rocceri kirjoitti:
Tämä kuitenkin printtaa tälläisen varoituksen sivulle:
Warning: Cannot modify header information - headers already sent by (output started at C:\xampplite\htdocs\sql.php:3) in C:\xampplite\htdocs\sql.php on line 8Tältä riviltä löytyy juuri tuo setcookie. Mitä tämä tarkoittaa?
Mikset käyttänyt hakua?
Rocceri kirjoitti:
Jatkoin harjoittelua, ja tein tämmöisen ns. verkkokaupan. MySQL taulut jne. on kunnossa. Kun sivulle saavutaan, niin koodin pitäisi asettaa keksi jossa on sisältömä kelloaika jolloin sivulle on saavuttu.
Tämä kuitenkin printtaa tälläisen varoituksen sivulle:
Warning: Cannot modify header information - headers already sent by (output started at C:\xampplite\htdocs\sql.php:3) in C:\xampplite\htdocs\sql.php on line 8Tältä riviltä löytyy juuri tuo setcookie. Mitä tämä tarkoittaa?
Olet tulostanut jotakin ennen otsikoiden lähetystä. Kaikki headereihin liittyvä pitää olla valmiina ennen mitään tulostusta. Eli sessiot, keksit jne ennen mitään tulostusta. Välilyöntikin on tulostusta.
Rocceri kirjoitti:
Toinen juttu.
Jos käyttäjällä on 100 euroa käytössä, niin tämä heitetään myös keksiksi. Sitten jos kävijä ostaa 15 eurolla vaikka elokuvia, niin 100 eurosta lähtee tämä 15. Miten PHP:llä lasketaan tämmöinen 100 - 15 lasku?
<?php echo 100 - 15; ?>
Tuon olisit ehkä osannut tehdä itsekin. :)
Teuro kirjoitti:
<?php echo 100 - 15; ?>Tuon olisit ehkä osannut tehdä itsekin. :)
Ohho, en tiennytkään että menee näin yksinkertaisesti. :D Tulipa se nyt opittua.
Joo, ja keksit sain toimimaan.
EDIT: Tästä tulikin mutkikkaampaa kuin ensiksi ajattelin.
Tein koodin
<?php //Alkutekstit echo "<html>\n<head>\n<title>MySQL kysely</title>\n</head>\n<body>\n"; echo "Tervetuloa Verkkokauppaan! Sinulla on 20 minuuttia aina kerrasta aikaa tehdä ostoksesi.<br> Sen jälkeen ostoksesi ja kuluttamasi rahat nollataan, ja voit aloittaa alusta.<br>"; //Luodaan yhteys... $yhteys = mysql_connect('localhost', '', '') or die(mysql_error()); //...test tietokantaan mysql_select_db("test") or die(mysql_error()); //Missä suunnassa on tavaroiden sijoittelu? $suunta = isset($_GET['suunta']) ? 'ASC' : 'DESC'; $linkki = isset($_GET['suunta']) ? '' : '&suunta'; $otsikko = isset($_GET['otsikko']) ? $_GET['otsikko'] : 'hinta'; //Tarkistetaan ettei ole tyhjä tavara if(!empty($_GET['tuote'])) { if(!empty($_GET['hinta'])) { if(!empty($_GET['maara'])) { if(!empty($_GET['tilattavissa'])) { //Jos ei ole tyhjää kenttää, kirjoitetaan tieto mysql_query("INSERT INTO varasto (nimi, hinta, maara, tilattavissa) VALUES ('".$_GET['tuote']."', '".$_GET['hinta']."', '".$_GET['maara']."', '".$_GET['tilattavissa']."')"); } } } } //Tuotteen poistamista varten if(!empty($_GET['poista'])) { if($_GET['pw'] == "salis") { mysql_query("DELETE FROM varasto WHERE nimi = '".$_GET['poista']."'"); } } //Tuotteen nimen päivitystä varten if(!empty($_GET['paivita'])) { if(!empty($_GET['nimi'])) { mysql_query("UPDATE varasto SET nimi = '".$_GET['nimi']."' WHERE nimi = '".$_GET['paivita']."'"); } } //Tuotteen hinnan päivitystä varten if(!empty($_GET['paivita'])) { if(!empty($_GET['hinta'])) { mysql_query("UPDATE varasto SET hinta = '".$_GET['hinta']."' WHERE nimi = '".$_GET['paivita']."'"); } } //Tuotteen määrän päivitystä varten if(!empty($_GET['paivita'])) { if(!empty($_GET['maara'])) { mysql_query("UPDATE varasto SET maara = '".$_GET['maara']."' WHERE nimi = '".$_GET['paivita']."'"); } } //Tuotteen tilattavuuden päivitystä varten if(!empty($_GET['paivita'])) { if(!empty($_GET['tilattavissa'])) { mysql_query("UPDATE varasto SET tilattavissa = '".$_GET['tilattavissa']."' WHERE nimi = '".$_GET['paivita']."'"); } } //Kysellään tietoja varasto $kysely = "SELECT * FROM varasto ORDER BY $otsikko $suunta"; //Jos virhe, tulostetaan virhesanoma $haku = mysql_query($kysely, $yhteys) or die(mysql_error()); //Luodaan taulukko tavaroille echo '<table border>'; echo "\n"; echo '<br><tr><td><b><a href="?otsikko=nimi'. $linkki .'">Tuotteen nimi:</a></b></td> <td><b><a href="?otsikko=hinta'. $linkki .'">Hinta: </a></b></td> <td><b><a href="?otsikko=maara'. $linkki .'">Myymälässä: </a></b></td> <td><b><a href="?otsikko=tilattavissa'. $linkki .'">Varastossa: </a></b></td> <td><b>Osta tuote:</b></td></tr>'; echo "\n"; //Käydään tavarat läpi for ($i = 0; $i < mysql_num_rows($haku); $i++) { $nimi = mysql_result($haku, $i, 'nimi'); $hinta = mysql_result($haku, $i, 'hinta'); $maara = mysql_result($haku, $i, 'maara'); $tilattavissa = mysql_result($haku, $i, 'tilattavissa'); //Tulostetaan tavarat echo "<tr><td>$nimi</td><td>{$hinta}€</td><td>$maara kpl</td><td>$tilattavissa</td><td><a href=\"sql.php?osta=$nimi\">Osta tämä tuote</a></td></tr>\n"; } //Lopetetaan dokumentti echo "</table>\n"; //Ostamiseen $osta = $_GET["osta"]; if ($_GET["osta"]) { echo "<form action=\"\" method=\"GET\">\n"; echo "Olet ostamassa tuotetta '<b>".$_GET['osta']."</b>'.<br><br>"; echo "<a href=\"?ostettu=$osta\">Osta tuote </a><br>"; echo "<a href=\"?\">Ei kiitos</a><br></form>"; } if ($_GET["ostettu"]) { echo "<br>Tuote '<b>".$_GET['ostettu']."</b>' on ostettu! "; } echo "</body>\n</html>"; ?>
Nyt pitäisi tehdä näin:
Alkuun asetan 'aika' keksin, jolle annan sisällöksi kelloajan sekunnilleen date() -funktiolla ja asetetaan rahamäärä raha keksiksi sisällöllä 100.
Sitten kun luettelosta valitsee jonkin tavaran kohdalta "Osta tämä tuote", niin koodi kysyy ostetaanko vai ei. Kun painaa kyllä, niin lasketaan keksin raha määrä - ostokseen kulunut raha.
<?php $rahat = $_COOKIE["raha"]; $nyt = $rahat - $hinta; /* Tästä en tiedä yhtään, uskoisin että tulostaa vain 100 - 15? */ ?>
Sitten poistetaan keksi.
Sen jälkeen luodaan uusi keksi
Tässä laskettiin vasta rahat, mutta miten laitetaan tavarat kekseiksi?Tiedostoon en kirjoittaisi niitä, koska voi olla monta käyttäjää samaan aikaan.
Kutakuinkin näin se menisi:
1. Pistät arrayhyn tuotteet
2. serializoit sen arrayn stringiksi, jonka voi tallentaa sitten cookieen
3. tallennat cookien
4. unsierializoit cookien datan kun haluat sen takas käyttöön, jolloin se stringi siellä cookiessa muuttuu taas siihen arrayhin mikä se alunperin oli.
<?php $keksi = serialize($tuotteet); // tuotteet on taulukko // Tallennat cookiehen $keksin. // Sitten kun haluat takas käyttöön tuotteet arrayn niin $tuotteet = unserialize($cookiesta_haettu_data); ?>
Et halua tehdä sitä noin. Koodisi määrä kasvaa todella nopeasti, kun päivitettäviä kenttiä tulee lisää. Päivität siis kaikki tarpeelliset kentät kerralla. Lisäksi nimen perusteella rajaus on huono idea, koska kannassa voi ihan hyvin olla samalla nimellä monia tuotteita. Mielummin juoksevan id:n perusteella rajaus ja LIMIT 1 perään, jotta mahdollinen vahinko tulee yhteen tietueeseen.
Muutoinkin opettele mielummin ihan rauhassa ohjelmointia ja ota tietokannat mukaa vasta sitten, kun ole sinut tuon php:n kanssa. Tällä hetkellä suurin osa projekteistasi eteen juurikin siihen tahtiin, kuin minä ja muutama muu tekee sinulle valmista koodia.
En nyt kuitenkaan tahdo mollata sinua, koska motivaatiosi tuntuu oleavan melko korkealla opettelun suhteen, enkä halua sitä latistaa millään muotoa. Ohjelmoinnissa monasti kannattaa aina miettiä, että miten saan koodin määrää vähennettyä. Pieni määrä hyvää koodia on usein helpompi hallita, kuin suuri määrä huonoa koodia.
Miten muuten voin laittaa tuonne alas missä lukee
if($_GET["ostettu"] { .... }
toiminnon, että siellä vasta luodaan se keksi missä on sen hetkiset rahat?
Päivität raha tilanteen ton iffin sisällä ja tallennat sen siihen raha keksiin? Vai mitä meinasit. Osaathan sä jo cookieita tallentaa. Itse kyllä käyttäisin sessioita tuommoisen väliaikaisen datan tallennukseen. Ja kun kyse on verkkokaupasta, niin ostot / tilaukset tulisi tallentaa tietokantaan ja varmistaa, että ne menee sinne ja menee oikein. Ostettujen tuotteiden säilöminen keksiin tai sessioon ei ole mikään järin mahtava idea (oikeassa elämässä). Tietenkin meneehän se ihan harjotuksena.
TeNDoLLA kirjoitti:
Päivität raha tilanteen ton iffin sisällä ja tallennat sen siihen raha keksiin? Vai mitä meinasit.
Joo, tätä meinasin.. Mutta, eihän tuossa toimi jos lättää nuo setcookiet tuonne. Mutta, laitoin tonne koodin alkuun, että jos on muuttuja ostettu, niin tuhotaan se toinen keksi ja tehdään uusi. Eli se ei ole huoli enään.
Mutta, kun tämä tulee yhdelle käyttäjälle, niin voisi tehdä tämän yhdellä tekstitiedostolla. Sen voin tehdä ihan hujauksessa, mutta sitä ennen. Miten poistetaan tekstitiedostosta vaikka rivi numero 3? Siis koodilla tietysti.
Rocceri kirjoitti:
Miten poistetaan tekstitiedostosta vaikka rivi numero 3? Siis koodilla tietysti.
Tästähän on ollut juuri aihe:
https://www.ohjelmointiputka.net/keskustelu/
Tuo on tosin rivin muuttaminen, mutta samalla logiikalla vaan. ;)
Mietitäämpä tuota verkkokaupan toteutusta yleisellä tasolla. Rajataan ensin ongelmaa, jotta puhumme samasta asiasta, sekä että ratkaisemme oikeaa ongelmaa. Ongelma purkaantuu minusta seuraaviin osasiin:
Jatkossa mukaan saattaa tulla vielä paljon muutakin, mutta aloitetaan ensimmäisestä rajauksesta.
Käyttäjät. Nämä ovat siis kauppasi käyttäjiä nimensä mukaisesti. Mitä käyttäjä tarvitsee, jotta asiointi on mahdolista? Miten käyttäjät tunnistetaan?
Tuotteet Näitä varten käyttäjät ovat tulleet kauppaasi. Useimmat henkilöt eivät jaksa kahlata valikoita. Tuoteluettelo on lähes yhtä huono, mutta haku on monelle helppo tapa löytää tuotteita. Pääsemme siis organisointiin. Tuotteilla tulee olla useita hakuehtoja, jotta tehokkaat hakutoiminnot olisi mahdollista toteuttaa. Miten tuotteet on nimetty? Onko samannimisiä tuotteita? Onko samalla tuotteella useita valmistajia? Onko eriäviä takuuehtoja? Mitä kenttiä tuotteille tehdään?
Ostoskori Ostoskori on näkyvin yhteys käyttäjien ja tuotteiden välillä. Tämä on tärkeää rakentaa hyvin toimivaksi. Miten tuotteet lisätään koriin? Miten tunnistetaan jokaiselle käyttäjälle oma kori? Miten varmistetaan, ettei koriin lisätyt tuotteet häviä?
html merkkaus Sivuston uskottavuuden ja ylläpidon kannalta erityisen hankala toteutta hyvin, koska sivustolle tulee useita elementtejä. Erityisen tarkkana on oltava tagien avauksen ja sulkemisen kanssa. Usealla tiedostolla tulee takuulla ongelmia, joten parasta lienee siirtyä vaikkapa sivupohjiin, jotta ulkoasu tulee yhdestä pohjasta, joka on helppo vaihtaa.
Tyylittely Käyttäjille toinen selkeästi näkyvä osuus kannattaa toteuttaa selkeästi omassa tiedostossaan. Sivupohjaa tehdessä kannattaa miettiä erilaisiä luokkia, joita voi käyttää sivulta toiselle. Tällä vähennetään oleellista osiltaan samanlaisien tyyliluokkien tuottaminen.
Ohjelmointi (php + mysql) Käyttäjille täysin näkymätön osuus, mutta toiminnan kannalta todella tärkeä. Tähän ei voi oikein antaa tyhjentäviä kysymyksiä, mutta tärkeintä on ymmärtää, että näillä kahdella voidaan saada peruuttamatonta tuhoa aikaiseksi. Kantaan ei saa ajaa vaarallisia kyselyitä. Kaikki UPDATE ja DELETE lauseet tulee varustaa LIMIT 1 määreellä, jotta mahdollinen tuho rajoittuu yhteen tietueeseen. ALTER lauseet tulee estää tavallisilta käyttäjiltä, mutta miksei myös kaikilta, koska taulujen muunnos lennossa ei ole yleensä tarpeellista.
Tulipas paasattua, mutta mieti näitä asioita. Tämän ei siis ollut tarkoitus olla tyhjentävä vastaus ongelmaasi, vaan lähinnä siirtää ajatteluasi koodaamisesta suunnitteluun.
Hmm.. Voinhan sen näinkin ottaa, jos kyse on suuremmasta asiasta, utta tällä hetkellä tilanne on sellainen, että tälläisiä käyttäjiä ei perjaatteessa ole, vaan kun tulet sivulle niin olet aina uusi henkilö ja voit lisätä tuetteita ostoskoriisi painemalla osta tämä tuote nappulaa.
Tämä siis ei ole mikään sillä lailla toimiva, vaan tämän pitäisi merkata ylös mitkä tuotteet on 'ostettu' ja tulostaa tuotteen nimi ja hinta ostoskorin taulukkoon. Olen saanut melkein kaiken toimimaan. Ainoat kaksi ongelmaa on seuraavat: Kun tuotetta ostetaan, lähetetään muuttuja osta jolla on arvona halutun tuotteen nimi. (Esim. www.esimerkki.fi/kauppa.php?osta=Nokia N96) Sitten pitäisi lähettää myös hinta kauppa.php?osta=Nokia N96&hinta=590
.
Noh, jostain syystä tämän tuotteen nimi tulostaessa on Nokia N96&hinta=590. Tämän kyllä uskoisin olevan jokin kirjoitusvirhe koodissani, jonka korjaan tuotapikaa.
Kun 'ostettu' tuote kirjoitetaan tiedostoon ostokset.txt, niin rivi on seuraava: tuotteen_nimi|tuotteen_hinta
. Toinen ongelma on kyllä jokseenkin kummallinen: Kun koitan tulostaa tietoja taulukkoon tiedostosta jossa on kaksi yllä mainittua riviä, niin käy näin:
+--------+-------+ | Tavara | Hinta | +--------+-------+ | Tuote1 | Hinta | +--------+-------+ +--------+-------+ | Tavara | Hinta | +--------+-------+ | Tuote2 | Hinta | +--------+-------+
Vaikka sen kuuluisi olle näin:
+--------+-------+ | Tavara | Hinta | +--------+-------+ | Tuote1 | Hinta | +--------+-------+ | Tuote2 | Hinta | +--------+-------+
PS. Teuro: Kun saan tämän valmiiksi, alan vääntämään tuon sinun viestin pohjalta. =)
Tässä tuli koko eilinen ja tänäänkin aikas kauan väännettyä tuota taulukkoa, mutta ei toimi. Testasin laittaa taulukon jonnekkin muualle. Kaikkialla muualla taulukko toimii oikein, mutta tuossa ostoskorissa se näkyy ihan väärin.
<?php //Asetukset $rahamaara = "2000"; //Alkutekstit echo "<html>\n<head>\n<title>MySQL kysely</title>\n</head>\n<body>\n"; echo '<a href="?">Etusivulle</a> | <a href="?ostoskori=true">Ostoskori</a><br><br>'; if ($_GET["ostoskori"] == "true") { $ostokset = file("ostokset.txt"); $ostoslista = count($ostokset); echo "Sinulla on yhteensä <b>$ostoslista</b> ostosta.<br><br>\n"; for ($i = 0; $i < $ostoslista; $i++) { $lista = explode("|", $ostokset[$i], 2); $tavara = $lista[0]; $hintaaa = $lista[1]; echo "<table border=\"1\"><tr><td width=\"300\"><b>Tuote:</b></td><td width=\"30\"><b>Hinta:</b></td></tr>"; echo "<tr><td>$tavara</td><td>{$hintaaa}€</td></tr>"; echo "</table>"; } } else { //Luodaan yhteys... $yhteys = mysql_connect('localhost', '', '') or die(mysql_error()); //...test tietokantaan mysql_select_db("test") or die(mysql_error()); //Missä suunnassa on tavaroiden sijoittelu? $suunta = isset($_GET['suunta']) ? 'ASC' : 'DESC'; $linkki = isset($_GET['suunta']) ? '' : '&suunta'; $otsikko = isset($_GET['otsikko']) ? $_GET['otsikko'] : 'hinta'; //Tarkistetaan ettei ole tyhjä tavara if(!empty($_GET['tuote'])) { if(!empty($_GET['hinta'])) { if(!empty($_GET['maara'])) { if(!empty($_GET['tilattavissa'])) { //Jos ei ole tyhjää kenttää, kirjoitetaan tieto mysql_query("INSERT INTO varasto (nimi, hinta, maara, tilattavissa) VALUES ('".$_GET['tuote']."', '".$_GET['hinta']."', '".$_GET['maara']."', '".$_GET['tilattavissa']."')"); } } } } //Tuotteen poistamista varten if(!empty($_GET['poista'])) { if($_GET['pw'] == "880880") { mysql_query("DELETE FROM varasto WHERE nimi = '".$_GET['poista']."'"); } } //Tuotteen nimen päivitystä varten if(!empty($_GET['paivita'])) { if(!empty($_GET['nimi'])) { mysql_query("UPDATE varasto SET nimi = '".$_GET['nimi']."' WHERE nimi = '".$_GET['paivita']."'"); } } //Tuotteen hinnan päivitystä varten if(!empty($_GET['paivita'])) { if(!empty($_GET['hinta'])) { mysql_query("UPDATE varasto SET hinta = '".$_GET['hinta']."' WHERE nimi = '".$_GET['paivita']."'"); } } //Tuotteen määrän päivitystä varten if(!empty($_GET['paivita'])) { if(!empty($_GET['maara'])) { mysql_query("UPDATE varasto SET maara = '".$_GET['maara']."' WHERE nimi = '".$_GET['paivita']."'"); } } //Tuotteen tilattavuuden päivitystä varten if(!empty($_GET['paivita'])) { if(!empty($_GET['tilattavissa'])) { mysql_query("UPDATE varasto SET tilattavissa = '".$_GET['tilattavissa']."' WHERE nimi = '".$_GET['paivita']."'"); } } //Kysellään tietoja varasto $kysely = "SELECT * FROM varasto ORDER BY $otsikko $suunta"; //Jos virhe, tulostetaan virhesanoma $haku = mysql_query($kysely, $yhteys) or die(mysql_error()); //Luodaan taulukko tavaroille echo '<table border>'; echo "\n"; echo '<br><tr><td><b><a href="?otsikko=nimi'. $linkki .'">Tuotteen nimi:</a></b></td> <td><b><a href="?otsikko=hinta'. $linkki .'">Hinta: </a></b></td> <td><b><a href="?otsikko=maara'. $linkki .'">Myymälässä: </a></b></td> <td><b><a href="?otsikko=tilattavissa'. $linkki .'">Varastossa: </a></b></td> <td><b>Osta tuote:</b></td></tr>'; echo "\n"; //Käydään tavarat läpi for ($i = 0; $i < mysql_num_rows($haku); $i++) { $nimi = mysql_result($haku, $i, 'nimi'); $hinta = mysql_result($haku, $i, 'hinta'); $maara = mysql_result($haku, $i, 'maara'); $tilattavissa = mysql_result($haku, $i, 'tilattavissa'); //Tulostetaan tavarat echo "<tr><td>$nimi</td><td>{$hinta}€</td><td>$maara kpl</td><td>$tilattavissa</td><td><a href=\"sql.php?osta=$nimi&hinta=$hinta\">Osta tämä tuote</a></td></tr>\n"; } //Lopetetaan dokumentti echo "</table>\n"; //Ostamiseen $osta = $_GET["osta"]; $hintaa =$_GET["hinta"]; if ($_GET["osta"]) { echo "<form action=\"\" method=\"GET\">\n"; echo "Olet ostamassa tuotetta '<b>".$_GET['osta']."</b>'.<br><br>"; echo "<a href=\"?ostettu=$osta&hinta=$hintaa\">Osta tuote </a><br>"; echo "<a href=\"?\">Ei kiitos</a><br></form>"; } if ($_GET["ostettu"]) { echo "<br>Tuote '<b>".$_GET['ostettu']."</b>' on ostettu! "; $tuotteennimi = $_GET['ostettu']; $tuotteenhinta = $_GET['hinta']; $rivi = "$tuotteennimi|$tuotteenhinta\n"; $tiedosto = fopen("ostokset.txt", "a"); fwrite($tiedosto, $rivi); fclose($tiedosto); } } echo "</body>\n</html>"; ?>
Joka ainut kerta, mitä ikinä teenkään tuolle koodille tuolla ylhäällä, niin se näyttää tuloksen väärin.
+--------+-------+ | Tavara | Hinta | +--------+-------+ | Tuote1 | Hinta | +--------+-------+ +--------+-------+ | Tavara | Hinta | +--------+-------+ | Tuote2 | Hinta | +--------+-------+
Näin pikaseen katottuna näyttäs siltä, että sulla on se koko tablen tulostus otsikoineen päivineen for loopin sisällä, joten se tulostaa koko tablen joka kierroksella. Eikä se näytä tulostusta väärin, vaan just niinkuin olet laittanut sen tulostamaan.
TeNDoLLA kirjoitti:
Näin pikaseen katottuna näyttäs siltä, että sulla on se koko tablen tulostus otsikoineen päivineen for loopin sisällä, joten se tulostaa koko tablen joka kierroksella. Eikä se näytä tulostusta väärin, vaan just niinkuin olet laittanut sen tulostamaan.
Jooh, nyt sain toimimaan. Kiitos :) Nyt pitää vielä tehdä koodi joka tuhoaa tiedoston sisällön 20 minuutin välein.. Mutta, mitenköhän tämäkin onnistu.. Pitää hetki miettiä.
Rocceri kirjoitti:
TeNDoLLA kirjoitti:
Näin pikaseen katottuna näyttäs siltä, että sulla on se koko tablen tulostus otsikoineen päivineen for loopin sisällä, joten se tulostaa koko tablen joka kierroksella. Eikä se näytä tulostusta väärin, vaan just niinkuin olet laittanut sen tulostamaan.
Jooh, nyt sain toimimaan. Kiitos :) Nyt pitää vielä tehdä koodi joka tuhoaa tiedoston sisällön 20 minuutin välein.. Mutta, mitenköhän tämäkin onnistu.. Pitää hetki miettiä.
En usko että onnistuu kovin helposti jos aiot PHP:llä tehdä ilman, että sinulla ei olisi jossain selaimessa kyseinen sivu auki.
ankzilla kirjoitti:
En usko että onnistuu kovin helposti jos aiot PHP:llä tehdä ilman, että sinulla ei olisi jossain selaimessa kyseinen sivu auki.
Sitäpä tässä on tarkoitus tehdä. Myös pitäisi saada rahamäärät toimimaan. Nyt kun ostaa tuotteen, niin myymälästä vähenee aina yksi kyseistä tavaraa. Sitten jos on 0 jotain tuotetta, niin 'tilataan' varastosta aina 5 kerralla ja vähennetään se varastosta.
Mitä järkeä sitä tietoa on päivittää silloin, kun sitä ei kukaan lue?
Eikös koko systeemi olisi helpompi tehdä niin, että lätkäistään date() funktio jonnekkin, ja sitte ajan ja päivämäärän perusteella tehdään ne kaikki kyselyt juuri silloin kun joku tulee sivulle :P
Rocceri kirjoitti:
Jooh, nyt sain toimimaan. Kiitos :) Nyt pitää vielä tehdä koodi joka tuhoaa tiedoston sisällön 20 minuutin välein.. Mutta, mitenköhän tämäkin onnistu.. Pitää hetki miettiä.
En ole tätä aihetta kovin tarkasti seurannut, mutta miksi sotket tiedostoja mukaan jos harjoittelet tietokannan käyttöä?
trilog kirjoitti:
En ole tätä aihetta kovin tarkasti seurannut, mutta miksi sotket tiedostoja mukaan jos harjoittelet tietokannan käyttöä?
Joo, niin se oli aluksi, mutta juuri 10 minuuttia sitten sain kaiken tallennettua tietokantaan ja tehtyä vielä jokaiselle tuotteelle oman poistamisnapin, ja siihen toiminnon joka palauttaa tuotteen hinnan - 10%. Eihän käytetystä tavarasta saa täyttä hintaa. :D
ankzilla kirjoitti:
Mitä järkeä sitä tietoa on päivittää silloin, kun sitä ei kukaan lue?
Eikös koko systeemi olisi helpompi tehdä niin, että lätkäistään date() funktio jonnekkin, ja sitte ajan ja päivämäärän perusteella tehdään ne kaikki kyselyt juuri silloin kun joku tulee sivulle :P
Joo, enpä tullut ajatelleeksi tätä. Mutta, nyt kun on tietokannat niin yksinkertaisesti ajan sen mysql_queryllä pois.
mysql_query("DELETE FROM varasto WHERE nimi = 'tuote'");
Hei, miten tälläiseen 'verkkokauppaan' kannattaisi tehdä seuraava:
Kun tuotetta ostaa, niin koodi lukee taulukon ostokset, ja jos siellä on jo saman niminen tuote niin se tekisi halutut käskyt?
trilog kirjoitti:
Lasketaanko tietokannan sisältö arrayksi? Minun mielestä tuolla ei ole mitään tekemistä tietokannasta haun kanssa?
Rocceri kirjoitti:
... niin koodi lukee taulukon ostokset, ...
Minulle ainakin taulukosta tulee ensimmäisenä mieleen array, eli taulukko. Tarkoitit kuitenkin varmaan tietokannan taulusta etsimistä, josta päästäänkin:
Rocceri kirjoitti:
Lasketaanko tietokannan sisältö arrayksi? Minun mielestä tuolla ei ole mitään tekemistä tietokannasta haun kanssa?
jolla on hyvinkin paljon tekemistä tietokannan kanssa (ks. mysql_fetch_array). Voit etsiä sen PHP:n puolella ed. esittämälläni tavalla, tai sitten SQL-kyselyllä rajata:
SELECT * FROM ostokset WHERE tuotenimi = '$tuote';
Jos tuloksia löytyy, niin tuote on ostoksissa muussa tapauksessa ei.
Toimisiko näin? (En päässyt tuonne PHP nettiin, tekee errorin 500)
<?php $yhteys = mysql_connect("localhost", "", ""); mysql_select_db("test"); $tarkistettava = $_GET["tavara"]; $tarkistatavara = "SELECT FROM ostokset WHERE nimi = '$tarkistettava'"; mysql_query($taskitatavara, $yhteys); if ($tarkistatavara) { //Tee käskyt } else { //Normaali suoritus } mysql_close($yhteys); ?>
Vai, pitäisikö tehdä näin:
<?php $yhteys = mysql_connect("localhost", "", ""); mysql_select_db("test"); $tarkistettava = $_GET["tavara"]; $tarkistatavara = "SELECT FROM ostokset WHERE nimi = '$tarkistettava'"; $kysely = mysql_query($taskitatavara, $yhteys); if ($kysely) { //Tee käskyt } else { //Normaali suoritus } mysql_close($yhteys); ?>
mysql_query()
funktio palauttaa falsen jos kysely on virheellinen. Yllä oleva ei siis tämän takia toimi, joten sinun tulee käyttää tarkistukseen esimerkiksi mysql_num_rows
funktiota tarkaasteksi kuinka monta riviä kysely palauttaa.
Tumettaja kirjoitti:
mysql_query()
funktio palauttaa falsen jos kysely on virheellinen. Yllä oleva ei siis tämän takia toimi, joten sinun tulee käyttää tarkistukseen esimerkiksimysql_num_rows
funktiota tarkaasteksi kuinka monta riviä kysely palauttaa.
Selvä. Koitan saada tehtyä. Tällä hetkellä teen yhdellä toisella tavalla..
Kyselyssäkin on virhe. Puuttuu siis määritys mitä kenttiä kyselyyn otetaan mukaan.
trilog kirjoitti:
Kyselyssäkin on virhe. Puuttuu siis määritys mitä kenttiä kyselyyn otetaan mukaan.
No, jostain syystä unohtui. Nyt olen omaan koodiini korjannut.
Heitänpä väliin oliopohjaisen esimerkin preparoidusta lausekkeesta (testaamaton, pahoittelen, mysli jäi toisten housujen taskuun):
<?php $mysqli = new MySQLi('localhost', 'my_user', 'my_password', 'test'); /* tarkistetaan yhteys */ if ($mysqli->connect_errno()) { throw new Exception("Yhteyden luonti epäonnistui: {$mysqli->connect_error()}"); } $tavara = ''; if (isset($_GET['tavara'])) { $tavara = $_GET['tavara']; } else { throw new Exception('Hakuehtoa ei annettu'); } /* luodaan preparoitu lauseke */ $q = 'SELECT hinta FROM ostokset WHERE nimi=?'; if ($stmt = $mysqli->prepare($q)) { /* sidotaan parametrit lausekkeeseen */ $stmt->bind_param("s", $tavara); /* suoritetaan tietokantahaku */ $stmt->execute(); /* sidotaan tulosparametrit */ $stmt->bind_result($hinta); /* * Haetaan tulos. * Useamman tuloksen kanssa käytetään * while($stmt->fetch()) */ if ($stmt->fetch() !== null) { printf("%s maksaa %s euroa", $tavara, $hinta); } else { echo 'Ei hakutuloksia'; } /* suljetaan lauseke */ $stmt->close(); } /* suljetaan yhteys */ $mysqli->close(); ?>
Ja tuohon muutama oma poikkeusluokka ja oma poikkeuskäsittelijä. PDO tietysti vielä tukisi nimettyjä parametrejä...
Ihan ok näyttää, vaikken tajua oliohjelmoinnista pätkääkään.
Nyt olen saanut siistittyä koodia vaikka kuinka paljon:
Olen laittanut asetukset eri tiedostoon ja otan ne require_once
lla käyttöön.
Sitten on tullut lisää toimintoja;
- Jos on monta samaa tuotetta, koodi päivittää toisen tuotteen määräksi nykyinen + 1.
- Lisäys, poisto ja muut tapahtuvat lomakkeen kautta.
... Ja paljon muuta.
Nyt vielä on sellainen ongelma, että tuotteita voi olla maksimissaan 2.
Jotain kummallista tapahtui kun koodasin, ja nyt jos on ostettu tuote kun myymälässä on 0 kpl kyseistä tavaraa, niin tämä laittaa myymälään -1 ja tilaa varastosta kun sivun päivittää :)
Laita unsigned attribuutiksi jos tarkoitus on, ettei pitäisi mennä miinuksen puolelle.
ankzilla kirjoitti:
Laita unsigned attribuutiksi jos tarkoitus on, ettei pitäisi mennä miinuksen puolelle.
Aluksi se oli tarkoitus, että 0 on minimi, mutta kun nyt katselin muitakin verkkokauppoja, niin meneväthän nekin sillä tavalla.
Aihe on jo aika vanha, joten et voi enää vastata siihen.