Kirjautuminen

Haku

Tehtävät

Oppaat: MySQL ja PHP: Osa 2 - PHP ja PDO

  1. Osa 1 - Johdanto
  2. Osa 2 - PHP ja PDO
  3. Osa 3 - Hakukyselyt I
  4. Osa 4 - Hakukyselyt II
  5. Osa 5 - Hakukyselyt III
  6. Osa 6 - Lisäys, muutos ja poisto
  7. Osa 7 - Tietotyypit
  8. Osa 8 - Tietokannan suunnittelu
  9. Osa 9 - Monta taulua
  10. Osa 10 - Lisätietoa
  11. Liite 1 - MySQL:n komentorivityökalu
  12. Liite 2 - phpMyAdmin-sovellus

Kirjoittaja: Antti Laaksonen (2009).

Nykyaikainen tapa käyttää MySQL-tietokantaa PHP:llä on PDO-rajapinta, joka on mukana PHP:ssä versiosta 5.1 alkaen. PDO:lla voi käyttää MySQL:n lisäksi muitakin tietokantoja yhtenäisellä tavalla.

Esimerkkitaulu

Oppaassa käytetään samaa esimerkkitaulua kuin ensimmäisessä osassa. Taulun nimi on tuotteet, ja siihen on tallennettu kolme riviä:

+----+----------+-------+
| id | nimi     | hinta |
+----+----------+-------+
|  1 | kaali    |     3 |
|  2 | porkkana |     2 |
|  3 | peruna   |     3 |
+----+----------+-------+

Yhdistys ja kysely

Seuraava PHP-koodi yhdistää tietokantaan, hakee taulusta tuotteet kaikki rivit ja näyttää ne taulukossa. Tässä MySQL-palvelimen osoite on localhost, käyttäjän nimi on antti, salasana on abc ja tietokannan nimi on testit.

<?php
// muodostetaan yhteys tietokantaan
try {
    $yhteys = new PDO("mysql:host=localhost;dbname=testit", "antti", "abc");
} catch (PDOException $e) {
    die("VIRHE: " . $e->getMessage());
}
// virheenkäsittely: virheet aiheuttavat poikkeuksen
$yhteys->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// merkistö: käytetään latin1-merkistöä; toinen yleinen vaihtoehto on utf8.
$yhteys->exec("SET NAMES latin1");

// valmistetaan kysely
$kysely = $yhteys->prepare("SELECT * FROM tuotteet");
// suoritetaan kysely
$kysely->execute();

// näytetään kyselyn tulokset taulukossa
echo "<table>";
// käsitellään tulostaulun rivit yksi kerrallaan
while ($rivi = $kysely->fetch()) {
    // $rivi["nimi"] sisältää nimen
    // $rivi["hinta"] sisältää hinnan
    echo "<tr>";
    echo "<td>" . htmlspecialchars($rivi["nimi"]) . "</td>";
    echo "<td>" . htmlspecialchars($rivi["hinta"]) . "</td>";
    echo "</tr>";
}
echo "</table>";
?>

Yllä oleva koodi tulostaa sivulle seuraavan taulukon:

Kyselyssä on kaksi vaihetta: ensin kysely valmistetaan metodilla prepare, sitten se suoritetaan metodilla execute. Metodi fetch palauttaa yksi kerrallaan kyselyn tuottamat rivit, kunnes rivejä ei enää ole, jolloin metodi palauttaa arvon false ja silmukka päättyy.

Kun kysely suoritetaan PHP:n kautta, sen loppuun ei tarvitse kirjoittaa puolipistettä.

Kyselyn parametrit

Jos kyselyssä on muuttuvia parametreja, kuten rivien hakuehdot, niiden kohdalle merkitään kysymysmerkki kyselyn valmistuksessa. Sitten kyselyn suorituksessa ilmoitetaan parametrien senkertaiset arvot niiden esiintymisjärjestyksessä.

Seuraava koodi hakee vain rivit, joissa hinta on 3:

// valmistetaan kysely
$kysely = $yhteys->prepare("SELECT * FROM tuotteet WHERE hinta = ?");
// suoritetaan kysely
$kysely->execute(array(3));

Seuraava koodi taas hakee rivit, joissa nimi on peruna tai porkkana:

// valmistetaan kysely
$kysely = $yhteys->prepare("SELECT * FROM tuotteet WHERE nimi = ? OR nimi = ?");
// suoritetaan kysely
$kysely->execute(array("peruna", "porkkana"));

Tässä kyselyssä PDO lisää merkkijonojen ympärille heittomerkit. Muutenkin PDO huolehtii automaattisesti siitä, että parametrit lisätään kyselyyn oikein.

Yksi tulosrivi

Seuraava koodi tulostaa rivien määrän taulussa tuotteet:

$kysely = $yhteys->prepare("SELECT COUNT(*) FROM tuotteet");
$kysely->execute();

$tulos = $kysely->fetch();
echo "Taulussa on " . $tulos["COUNT(*)"] . " riviä.";

Muut kyselyt

Kyselyt INSERT, UPDATE, DELETE suoritetaan vastaavasti kuin kysely SELECT.

Seuraava koodi muuttaa porkkanan hinnaksi 4:

$kysely = $yhteys->prepare("UPDATE tuotteet SET hinta = ? WHERE nimi = ?");
$kysely->execute(array(4, "porkkana"));

Seuraava koodi kertoo äskeisessä kyselyssä muuttuneiden tai poistettujen rivien määrän:

$maara = $kysely->rowCount();
echo "Kysely vaikutti " . $maara . " riviin.";

Virheen etsiminen

Seuraavan koodin kysely ei toimi, koska taulun nimi on väärin:

$kysely = $yhteys->prepare("SELECT * FROM tuoteet");
$kysely->execute();

Virhettä voi etsiä lisäämällä koodiin poikkeusten käsittelyn:

try {
    $kysely = $yhteys->prepare("SELECT * FROM tuoteet");
    $kysely->execute();
} catch (PDOException $e) {
    die("VIRHE: " . $e->getMessage());
}

Tässä tilanteessa virheviesti on "Table 'testit.tuoteet' doesn't exist", joka kertoo jo melko tarkasti, mistä virhe johtuu.

Esimerkki

Seuraavassa esimerkissä luodaan järjestelmä, jonka kautta voi katsella tuotteiden tietoja sekä lisätä uusia tuotteita. Voit kokeilla toimivaa järjestelmää tässä.

Luodaan aluksi tiedosto yhteys.php, joka luo yhteyden tietokantaan:

<?php
try {
    $yhteys = new PDO("mysql:host=localhost;dbname=testit", "antti", "abc");
} catch (PDOException $e) {
    die("VIRHE: " . $e->getMessage());
}
$yhteys->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$yhteys->exec("SET NAMES latin1");
?>

Tämän jälkeen tietokantaa voi käyttää, kunhan liittää mukaan tiedoston yhteys.php, eikä yhdistyskomentoa tarvitse kirjoittaa joka tiedoston alkuun.

Tiedosto lista.php näyttää listan kaikista tuotteista:

<?php
include("yhteys.php");

echo "<h1>Tuotelista</h1>";

$kysely = $yhteys->prepare("SELECT * FROM tuotteet");
$kysely->execute();

echo "<ul>";
while ($rivi = $kysely->fetch()) {
    $id = $rivi["id"];
    $nimi = htmlspecialchars($rivi["nimi"]);
    echo "<li><a href=\"tuote.php?id=$id\">$nimi</a>";
}
echo "</ul>";

echo "<p><a href=\"uusi.php\">Uusi tuote</a></p>";
?>

Tuotelistassa tuotteen nimi on linkki tiedostoon tuote.php, jossa näkyy yhden tuotteen nimi ja hinta. Listan alapuolella on linkki tiedostoon uusi.php, jonka kautta voi lisätä uuden tuotteen.

Tiedosto tuote.php näyttää yhden tuotteen tiedot:

<?php
include("yhteys.php");

$kysely = $yhteys->prepare("SELECT * FROM tuotteet WHERE id = ?");
$kysely->execute(array($_GET["id"]));

$tulos = $kysely->fetch();

echo "<p>Tuotteen nimi: " . htmlspecialchars($tulos["nimi"]) . "</p>";
echo "<p>Tuotteen hinta: " . htmlspecialchars($tulos["hinta"]) . "</p>";

echo "<p><a href=\"lista.php\">Takaisin</a></p>";
?>

Näytettävän tuotteen tunnusnumero ilmoitetaan sivun osoitteessa: esimerkiksi tuote.php?id=3 näyttää sen tuotteen tiedot, jonka tunnusnumero on 3.

Tiedosto uusi.php sisältää lomakkeen uuden tuotteen lisäämiseen:

<h1>Tuotteen lisäys</h1>
<form action="lisays.php" method="post">
<p>Nimi: <input type="text" name="nimi"></p>
<p>Hinta: <input type="text" name="hinta"></p>
<p><input type="submit" value="Lisää"></p>
</form>

Tiedosto lisays.php lisää tuotteen tietokantaan ja ohjaa vastaavalle tuotesivulle:

<?php
include("yhteys.php");

$kysely = $yhteys->prepare("INSERT INTO tuotteet (nimi, hinta) VALUES (?, ?)");
$kysely->execute(array($_POST["nimi"], $_POST["hinta"]));

$id = $yhteys->lastInsertId();
header("Location: tuote.php?id=$id");
?>

Tässä käytettiin hyödyllistä metodia lastInsertId, joka ilmoittaa viimeksi lisätyn rivin tunnusnumeron. Näin käyttäjä voidaan ohjata uutta tuotetta vastaavalle sivulle.


Kommentit

latenleffahylly [15.07.2012 23:28:33]

#

Upeita nämä oppaat, toteutus aivan huipputasoa, kiitos valtavasta työmäärästä tämänkin amatöörin hyväksi.

TeamSakke [04.08.2014 15:34:51]

#

Todella hyvä opas ja paljon hyödyllisiä vinkkejä aloittelijoille, mutta sen verran haluan korjata, että tuossa kohtaa "Yhdistys ja kysely" taulukon tulostamiseen, että jos haluttaisiin tuollainen taulukko, pitäisi vielä lisätä <table border> nykyisen pelkän <table> tilalle.

Metabolix [04.08.2014 15:42:09]

#

TeamSakke kirjoitti:

pitäisi vielä lisätä <table border> nykyisen pelkän <table> tilalle.

Noin ei ainakaan pitäisi tehdä. Taulukon ulkonäkö riippuu taulukon CSS-tyyleistä; myös pelkkä <table> voi sisältää tuollaiset reunat, jos niin säädetään. Joka tapauksessa ulkonäkö on täysin epäolennainen tämän oppaan kannalta.

olioinen [07.04.2015 01:45:08]

#

Hyödyllinen perusopas. Nopeasti muistuu asiat mieleen. Itse aion kokeilla tuota PDO-tekniikkaa Symfonyn parissa. Näyttäisi toimivan samankaltaisesti.

Kirjoita kommentti

Huomio! Kommentoi tässä ainoastaan tämän oppaan hyviä ja huonoja puolia. Älä kirjoita muita kysymyksiä tähän. Jos koodisi ei toimi tai tarvitset muuten vain apua ohjelmoinnissa, lähetä viesti keskusteluun.

Muista lukea kirjoitusohjeet.
Tietoa sivustosta