Hvordan kjøre SQL query mot MySQL database med PHP

ThomasK
ThomasKs bilde
Avlogget
Donator
Ble med: 30.12.2009

Hvordan bruker/programmerer man PHP for å kjøre SQL spørringer mot MySQL database?

Jeg vil bruke PHP til å hente ut informasjon fra MySQL databasen ved hjelp av SQL queries.

med hilsen
Thomas Kile

Hjemmeside
Hjemmesides bilde
Avlogget
Bidragsyter
Ble med: 17.06.2008
Guide: Hente data fra MySQL med PHP

Deler av denne guiden i hvordan man bruker PHP til å hente ut data fra MySQL har sammenheng med hvordan man oppretter tabeller og database i MySQL. I tråden det linkes til oppretter vi data som vi skal hente ut i denne guiden.


Koble til MySQL med PHP via db-access.php

For å kjøre query mot MySQL med PHP må man først og fremst opprette en tilkobling til MySQL. Nedenfor er et kodeeksempel på hvordan man kan koble til databasen.

Men før vi ser på scriptet, vil jeg komme med en anbefaling: Jeg anbefaler de som skal opprette en tilkobling til MySQL med PHP til å opprette et eget PHP-script som gjør dette, for så å legge det utenfor webrooten, og så bruke PHP-funksjonen:

<?php
require('/bane/til/db-access.php');
?>

for å hente inn tilkoblingen til MySQL i skript som trenger tilgang til MySQL.

På den måten kan man skifte ut brukernavn, passord og databasenavn i én fil, og dermed vil den endrede påloggingsinformasjonen gjelde for samtlige skript som trenger tilgang til MySQL.

db-access.php

Filen tar seg av tilkoblingen til MySQL, og kan se slik ut:

<?php
// Host til MySQL
$db_host = 'localhost';
// Databasenavn i MySQL
$db_name = 'ditt_databasenavn';
// MySQL bruker
$db_user = 'ditt_brukernavn';
// MySQL passord
$db_pass = 'ditt_passord';

// Kobler til MySQL
$db_connection = mysql_connect($db_host, $db_user, $db_pass);
/**
  Setter karaktersettet til utf8 for tilkoblingen.
  Dette kan gi problemer, så i visse tilfeller kan
  det være nødvendig å fjerne denne innstillingen.
**/
mysql_set_charset('utf8', $db_connection);

// Velger database i MySQL
mysql_select_db($db_name, $db_connection);
?>

Du bytter selvsagt ut detaljene i scriptet med dine personlige databaseinnstillinger.

Kjør en testspørring

For at vi skal kunne kjøre en testspørring, forutsettes det at du har noe å kjøre spørringer på. Her forutsettes det, som nevnt innledningsvis, at du har lagt inn noen data i MySQL.

Det første vi gjør er å opprette en ny PHP-fil. La oss kalle den query.php.

query.php

<?php
// Henter inn db-access.php
require('/bane/til/db-access.php');

// Lager en spørring
$query = 'SELECT * FROM user_table';

// Kjører query (spørring)
$result = mysql_query($query, $db_connection);

// Looper gjennom resultatene
while ($data = mysql_fetch_assoc($result)) {
  print
'BrukerID: ' . $data['user_id'] . '<br />';
  print
'Navn: ' . $data['user_name'] . '<br />';
  print
'Epost: ' . $data['user_email'] . '<br />';
  print
'<hr />';
}
?>

Hvis du har gjort det riktig, og kjører filen query.php skal du nå få ut samtlige brukere du har lagret i databasen.

Legg merke til at $data er en assosiativ array, og at nøklene i arrayen er navnet på feltene i tabellen. Dette er fordi vi bruker PHP-funksjonen mysql_fetch_assoc() til å hente ut data fra MySQL.

Her kan du laste ned PHP scriptet som henter data fra MySQL-databasen og endre db-access.php for å passe ditt oppsett.

Det neste blir å kombinere forms for å kjøre spørringer med forskjellige kriterier.

ThomasK
ThomasKs bilde
Avlogget
Donator
Ble med: 30.12.2009
To feil
  1. Hvor finner jeg ut av hva som er min localhost?
  2. Finner ikke require-filen...

med hilsen
Thomas Kile

Hjemmeside
Hjemmesides bilde
Avlogget
Bidragsyter
Ble med: 17.06.2008
Host til MySQL på webhotell fra BlueHost
  1. Siden du har BlueHost, så er databasehosten localhost.
  2. Det er fordi du ikke bruker riktig PATH (filbane) når forsøker å hente inn filen ved hjelp av require-funksjonen i PHP. For eksemplets skyld: Prøv å legg begge filene i én (og samme) katalog og bruk require-funksjonen på denne måten for å hente den inn:
<?php
require('db-access.php');
?>
ThomasK
ThomasKs bilde
Avlogget
Donator
Ble med: 30.12.2009
Fikk kontakt med databasen

Ja, nå fikk jeg opp en komplett liste med all infoen jeg har lagt inn i databasen...

Også testet å endre på //lager en spørring. Funka fjell det (som du sier);)

Hvordan kan jeg bruke et HTML-form for å sende en spørring?

med hilsen
Thomas Kile

Hjemmeside
Hjemmesides bilde
Avlogget
Bidragsyter
Ble med: 17.06.2008
HTML form med felt for spørring i MySQL via PHP

Bra, da lager vi et form. Opprett et HTML-dokument med navnet index.html og putt følgende form i det:

<form id="query" name="query" method="post" action="query.php">
  <fieldset>
    <legend>Hent brukerdata</legend>
    <label for="user_id">BrukerID:
      <input type="text" name="user_id" id="user_id" />
    </label>
    <input type="submit" value="Sjekk bruker" />
  </fieldset>
</form>

Bytt så ut alt innholdet i query.php med:

<?php
if($_POST) {
   
// Henter inn db-access.php
   
require('db-access.php');

   
// Lager en spørring
   
$query = sprintf(
       
'SELECT * FROM user_table WHERE user_id = \'%s\'',
       
mysql_real_escape_string($_POST['user_id']));

   
// Kjører query (spørring)
   
$result = mysql_query($query, $db_connection) or die(mysql_error());
   
// Looper gjennom resultatene
   
while ($data = mysql_fetch_assoc($result)) {
      print
'BrukerID: ' . $data['user_id'] . '<br />';
      print
'Navn: ' . $data['user_name'] . '<br />';
      print
'Epost: ' . $data['user_email'] . '<br />';
      print
'<hr />';
    }
}
?>

Last opp alt dette på webhotellet ditt, gå til index.html og forsøk å skrive inn en av brukerIDene.

Vi bruker sprintf() og mysql_real_escape_string() for å sikre oss mot SQL injections. Man bør validere brukerinput ytterligere, men for eksemplets skyld holder dette.

Ser du noen sammenhenger? Klarer du å opprette ett felt til i HTML og kjøre SQL-spørringen på flere kriterier fra brukeren?

ThomasK
ThomasKs bilde
Avlogget
Donator
Ble med: 30.12.2009
Jeg fikk det hvertfall til å

Jeg fikk det hvertfall til å funke med en gang da, herlig...

med hilsen
Thomas Kile

Hjemmeside
Hjemmesides bilde
Avlogget
Bidragsyter
Ble med: 17.06.2008
Du er flink!

Er ikke rart det da, du er både tolmodig og dyktig mannebiss! :)

ThomasK
ThomasKs bilde
Avlogget
Donator
Ble med: 30.12.2009
mysql_real_escape_string()

menne, skjønte ikke helt hvordan jeg skulle kunne legge inn flere søkekriterier som måtte stemme overens da, for å få riktig svar.

Altså, forsøkte med

<?php
'SELECT * FROM user_table WHERE user_id, user_name = \'%s\'',
mysql_real_escape_string($_POST['user_id'] && $_POST["user_name"]));
?>

Slik var det ikke, da fikk jeg syntax feil på linje 1 faktisk...

med hilsen
Thomas Kile

Hjemmeside
Hjemmesides bilde
Avlogget
Bidragsyter
Ble med: 17.06.2008
Bygge MySQL query

Nei, akkurat den der er vrien, er mye å holde styr på. Legg merke til hvordan jeg gjør denne. Har indentert litt for å gjøre det tydeligere.

<?php
$query
= sprintf
 
(
   
'SELECT * FROM user_table
       WHERE user_id = \'%s\'
       AND user_name = \'%s\''
,
   
mysql_real_escape_string($_POST['user_id']),
   
mysql_real_escape_string($_POST['user_name'])
  );
?>

Grunnen til at jeg har slashene foran fnuttene, er fordi jeg escaper dem.

Da klarer du kanskje å legge til et tredje kriterie?

ThomasK
ThomasKs bilde
Avlogget
Donator
Ble med: 30.12.2009
Hva betyr disse?

skal prøve, men hva betyr egentlig disse:

  • \'%s\'
  • mysql_real_escape_string()

med hilsen
Thomas Kile

Hjemmeside
Hjemmesides bilde
Avlogget
Bidragsyter
Ble med: 17.06.2008
sprintf og mysql_real_escape_string

Med funksjonen springf() rundt queryen kan man sette inn verdier etter stringen. Basert på hva slags specifier (f.eks %s) vil springf() behandle data forskjellig.

<?php
$string
= sprintf
 
(
   
'Jeg heter \'%s\'',
   
'Hjemmeside'
 
);
print
$string;
// Jeg heter 'Hjemmeside'
?>

Denne vil erstatte %s (string) med Hjemmeside. Man kan bruke forskjellige specifiers, se mer om sprintf i PHP manualen.

mysql_real_escape_string() er en funksjon som escaper diverse for å unngå såkale MySQL injections (en måte å hacke databaser ved å endre spørringen ved hjelp av brukerinput, enten i URL, form eller ved å sende POST til serveren). Også denne funksjonen kan du lese om i PHP manualen.

Hvis du ikke er komfortabel nok til å sette deg inn i akkurat dette enda, så er det viktig å få med seg at disse øker sikkerheten i skripet ditt.

ThomasK
ThomasKs bilde
Avlogget
Donator
Ble med: 30.12.2009
Jepp, mener jeg har fått det

Jepp, mener jeg har fått det til her...

Nå må jeg fyllle inn alle 3 feltene før jeg for frem resultetet.

Har testet litt, og det virker som at alle 3 feltene må samsvare med med riktig "linje" før det blir godkjent.

Har benyttet meg av

WHERE

AND

AND

Er det riktig?

med hilsen
Thomas Kile

Hjemmeside
Hjemmesides bilde
Avlogget
Bidragsyter
Ble med: 17.06.2008
joining av tables i MySQL

Jepp, det stemmer. Man kan også bruke OR (hvis man mener ELLER og ikke OG, slik man gjør med AND), men det skal du jo ikke gjøre i dette tilfellet.

Det går også ann å joine tables. Dvs hente ut informasjon fra to eller flere tables og kombinere data fra dem i resultatene fra MySQL. I de fleste store databaser er det mange relasjoner mellom forskjellige tabeller. Hvis du vil lære litt om det, så er det bare å spørre ved en annen anledning.

Tenk f.eks. på nettby eller facebook. Hvis A er venn med B der, så er A og B to brukere, registrert i samme database tabell. Videre er det en relasjonstabell som sier hvilke brukerIDer som er venner med hvem.

Anyways, du er vel klar for dette scriptet ditt du nå? Du får poppe tilbake i den tråden hvis du har noen flere spørsmål rundt akkurat det. Mulig den neste tråden din vil handle om sessions, hehe. Trøtt som ei strømpe her, men er ikke kvelden riktig enda.

ThomasK
ThomasKs bilde
Avlogget
Donator
Ble med: 30.12.2009
Ja, fått mye forståelse av

Ja, fått mye forståelse av det hele...

Men sitter fortsatt ørlitegrann igjen med, hvordan legger jeg inn en Else når det ikke samsvarer. Altså, en feilmelding bare. Ikke noe spesifisert.Bare:  "Informasjonen du har lagt inn samsvarer ikke med vår database. Skjekk att du har skrevet riktig.".

Noe sånn som det første scriptet jeg hadde satt opp her

 

Noe du kan hjelpe meg sånn på tampen?

med hilsen
Thomas Kile

Hjemmeside
Hjemmesides bilde
Avlogget
Bidragsyter
Ble med: 17.06.2008
MySQL num rows (antall resultater i spørringen)

Klart jeg kan det, hehe. Det spiller jo egentlig ingen rolle hvilke data du har funnet, så lenge du har funnet dem. Hvis det er samsvar mellom det brukeren plottet inn i formet og det som kommer tilbake, så har man én row med data.

For å se til at dette er tilfellet kan man gjøre det slik:

<?php
// Antall resultater er 1
if(mysql_num_rows($result) == 1) {
  print
'<p>Inne</p>';
// Finner ikke resultat
} else {
  print
'<p>Error</p>';
}
?>

Legg merke til at jeg bruker $result her. Det funksjonen mysql_num_rows() gjør, er å returnere en integer (et heltall) som naturlig nok er antall rader i resultatet.

ThomasK
ThomasKs bilde
Avlogget
Donator
Ble med: 30.12.2009
Skjønte ikke helt

Skjønte ikke helt hvor/hvordan jeg skulle implentere det inn...

med hilsen
Thomas Kile

Hjemmeside
Hjemmesides bilde
Avlogget
Bidragsyter
Ble med: 17.06.2008
Modifisert query.php

Her har jeg modifisert query.php litt, slik at du kanskje bedre ser sammenhengene.

<?php
// Sjekker at det blir postet
if($_POST) {
   
// Henter inn db-access.php
   
require('db-access.php');

   
// Lager en spørring
   
$query = sprintf(
       
'SELECT * FROM user_table WHERE user_id = \'%s\'',
       
mysql_real_escape_string($_POST['user_id']));

   
// Kjører query (spørring)
   
$result = mysql_query($query, $db_connection) or die(mysql_error());
   
// Sjekker om det er resultater
   
if(mysql_num_rows($result) == 1) {
       
// Looper gjennom resultatene
       
while ($data = mysql_fetch_assoc($result)) {
          print
'BrukerID: ' . $data['user_id'] . '<br />';
          print
'Navn: ' . $data['user_name'] . '<br />';
          print
'Epost: ' . $data['user_email'] . '<br />';
          print
'<hr />';
        }
   
// Finner ikke 1 resultat
   
} else {
        print
'<p>ERROR ERROR ERROR</p>';
    }
   
// Ble ikke postet
} else {
    print
'<p>Error: Ingenting er postet.</p>';
}
?>

Eksemplene i denne tråden er enkle modeller, man sjekker gjerne mye mer nøysomt om brukerdata er tuklet med osv. Sikkerhet er viktig når man programmerer.

En god idé er å skille HTML, CSS og PHP fra hverandre i mest mulig grad. Ikke slik som her at vi har en salig blanding.

ThomasK
ThomasKs bilde
Avlogget
Donator
Ble med: 30.12.2009
Kryptere brukerinfo i db-access

Du, kan kan kryptere brukerinfoen i db-access.php fila på noe vis?

host, name, user og pass.

 

med hilsen
Thomas Kile

Hjemmeside
Hjemmesides bilde
Avlogget
Bidragsyter
Ble med: 17.06.2008
Sikkerhetstiltak for brukernavn og passord

Det enkle svaret er nei, det lange svaret er ja.

Først: Grunnen til at man ønsker å legge "db-access.php" utenfor public_html, er fordi filene i denne katalogen er tilgjengelig fra world wide web. Hvis noe skulle gå galt på webserveren, f.eks. at PHP-dokumenter ikke tolkes, men sendes til nettleseren i klartekst, så vil brukeren som akkesserer dokumentet se hva det inneholder.

Fjerne mulighet for tilgang med .htaccess

Dette kan riktignok begrenses ved å sette opp en regel i .htaccess, slik:

<files db-access.php>
  order deny,allow
  deny from all
</files>

Merk at .htaccess må ligge i samme katalog som db-access.php i dette tilfellet. Bruk filbane hvis .htaccess ligger under db-access.php i filtreet (hvilket den må gjøre for å ha effekt.

Kryptering av passord

Ved å legge "db-access.php" utenfor public_html, vil den aldri være tilgjengelig fra world wide web.

For å kryptere passordet, må man først kryptere det, så lagre det i kryptert form, så lage en funksjon som dekrypterer passordet. Funksjonen bør ligge i en egen fil, også utenfor public_html, slik at en potensiell hacker ikke har tilgang til den.

Som du ser blir dette en redundant løsning, gitt løsningen jeg skisserte med å legge selve "db-access.php" utenfor public_html, eller begrense tilgangen til den med .htaccess.

ThomasK
ThomasKs bilde
Avlogget
Donator
Ble med: 30.12.2009
query.php filen. Bør den også

query.php filen. Bør den også ligge utenfor public_html?

med hilsen
Thomas Kile

Hjemmeside
Hjemmesides bilde
Avlogget
Bidragsyter
Ble med: 17.06.2008
Webrooten og PHP dokumenter

Nei, det trenger den ikke, den inneholder jo ingen konfedensielle data.

Poenget med å legge ting utenfor webrooten, er at man ikke skal ha tilgang til disse dokumentene fra world wide web via webserveren.

PHP har derimot mulighet for å hente inn ressurser som ligger utenfor webrooten. PHP er jo ikke webserveren, og PHP må ikke brukes i forbindelse med nettsider. Man kan også lage andre ting ved hjelp av PHP, f.eks. skript som utfører vedlikeholdsoppgaver i Linux (men til det ville jeg heller brukt shell scripts though).

ThomasK
ThomasKs bilde
Avlogget
Donator
Ble med: 30.12.2009
Formatere output fra SQL query

Okey, kjempemessig. Har et nytt spørsmål her, hehe.

Har øvd litt på å skrive SQL-queryer hos W3Schools. Litt nede på siden kan man sende en SQL-query. Man får da opp en fin tabell med resultatene.

Jeg får jo kun opp en liste av databasen, hvordan kan jeg få listen til å se noe mer ut som den man får opp hos W3Schools?

Altså, har prøvd å sette inn <table> da, men det funket dårlig. Da fikk jeg feil på linja...

med hilsen
Thomas Kile

Hjemmeside
Hjemmesides bilde
Avlogget
Bidragsyter
Ble med: 17.06.2008
Det du er ute etter å gjøre

Det du er ute etter å gjøre er mao. å lage et table for output fra PHP. Her bruker jeg eksemplet ovenfor og bygger videre på dette.

<?php
// Kjører query (spørring)
$result = mysql_query($query, $db_connection) or die(mysql_error());
// Sjekker om det er resultater
if(mysql_num_rows($result) == 1) {
   
// Bygger opp table
   
$output = '<table id="brukere">';
   
$output .= '<thead><tr>';
   
$output .= '<th>BrukerID</th>';
   
$output .= '<th>Navn</th>';
   
$output .= '<th>Epost</th>';
   
$output .= '</tr></thead>';
   
$output .= '<tbody>';
   
// Looper gjennom resultatene
   
while ($data = mysql_fetch_assoc($result)) {
       
// Legger brukere inn i table
       
$output .= '<tr>';
       
$output .= '<td>' . $data['user_id'] . '</td>';
       
$output .= '<td>' . $data['user_name'] . '</td>';
       
$output .= '<td>' . $data['user_email'] . '</td>';
       
$output .= '</tr>';
    }
   
// Avslutter table
   
$output .= '</tbody>';
   
$output .= '<tfoot></tfoot>';
   
$output .= '</table>';

   
// Skriver ut table
   
print $output;
}
?>

Legg merke til at vi starter variabelen $output med følgende notasjon:

<?php
$output
= 'Første data i variabel';
?>

For så å bruke punktum foran likhetstegnet etterpå, slik:

<?php
$output
.= 'Mer informasjon i variabel';
?>

På denne måten overskriver vi ikke gammel data i variabelen, men legger ny data til. Avslutningsvis printer vi hele variabelen og alt innholdet i den til skjermen.

For å style tabellen bruker du naturligvis CSS.

Svar på forumemnet

(If you're a human, don't change the following field)
Your first name.
Innholdet i dette feltet blir holdt privat og vil ikke bli vist offentlig.