Problemy z mysql_real_escape_string
 

Ze spooorym opóźnieniem, ale w końcu zabieramy się za drugą część naszej klasy do obsługi bazy danych, a mianowicie postaram się opisać sposób jej wykorzystania.
Skoro nasza klasa, jak mówi tytuł, jest prosta to i sposób wykorzystania ma na celu przede wszystkim pokazać jedną z możliwości.

" /> Problemy z mysql_real_escape_string
 

Ze spooorym opóźnieniem, ale w końcu zabieramy się za drugą część naszej klasy do obsługi bazy danych, a mianowicie postaram się opisać sposób jej wykorzystania.
Skoro nasza klasa, jak mówi tytuł, jest prosta to i sposób wykorzystania ma na celu przede wszystkim pokazać jedną z możliwości.

"/> Prosta klasa php do zarządzania bazą danych MySQL cz. 2

Start » Home > Blog > Prosta klasa php do zarządzania bazą danych MySQL cz. 2

Prosta klasa php do zarządzania bazą danych MySQL cz. 2

Autor: Daniel Goździk
|
29 October 2010
|
|
 
 
 
Prosta klasa php do zarządzania bazą danych MySQL

Słowem wstępu

Ze spooorym opóźnieniem, ale w końcu zabieramy się za drugą część naszej klasy do obsługi bazy danych, a mianowicie postaram się opisać sposób jej wykorzystania.
Skoro nasza klasa, jak mówi tytuł, jest prosta to i sposób wykorzystania ma na celu przede wszystkim pokazać jedną z możliwości.

Jak możemy wykorzystać naszą klasę?

Powiedzmy, że budujemy mini-aplikację php. Od czego zaczniemy ? oczywiście od określenia odpowiedniej struktury folderów i plików. Struktura naszej aplikacji może wyglądać następująco:
— classes
— css
— js
— inc
— index.php

Podstawowa struktura folderów i plików. Gdzie folder css będzie zawierać style css, folder js pliki JavaScript, inc pliki ładowane ? funkcja include()  lub require()  – i plik index.php.
W poniższym przykładzie interesują nas tylko dwa elementy: folder classes oraz plik index.php, resztę pominiemy.

W folderze classes umieszczamy plik z nasza “prostą klasą php do zarządzania bazą danych mysql”
Struktura naszej aplikacji wygląda następująco:
— classes
—- class_db.php
— index.php

Musimy teraz załadować naszą klasę w głównym pliku aplikacji ? index.php
Będzie to wyglądało mniej więcej tak:

<?php
  require_once('classes/class_db.php');
?>

Dlaczego require() a nie include()?? Dlaczego require_once(), a nie require()?? W tym temacie odsyłam już do manuala php:
http://pl.php.net/manual/en/function.require.php 
http://pl.php.net/manual/en/function.require-once.php 

Dobrym pomysłem jest dodać warunek przed wywołaniem funkcji require_once(). Sprawdzimy czy nasz plik istnieje, jeżeli tak ładujemy naszą klasę, jeżeli nie ? pokazujemy komunikat o nieodnalezieniu pliku, który możemy sformatować dużo lepiej niż standardowy błąd php.
Tak więc po zmianach nasz kod wyglądać będzie następująco:

 
<?php
...
$class_db_file = 'classes/class_db.php';
if (file_exists($class_db_file)):
  require_once($class_db_file);
else:
  echo 'Klasa db() nie została odnaleziona';
  exit;
endif;
...
?>

Instrukcja exit; powoduje zakończenie działania naszej aplikacji. Jeżeli bazy danych są istotnym elementem naszej aplikacji (a pewnie tak właśnie jest), nie ma sensu dalsze przetwarzanie kodu. Na 90% pojawi się sporo błędów w miejscach gdzie wykonane były jakiekolwiek operacje na bazie danych.

Ale w naszym przypadku wszystko działa poprawnie, klasa plik z klasą został odnaleziony, klasa dołączona do aplikacji, tak więc teraz pora na kolejny krok…

Implementacja klasy

Zacznijmy od zdefiniowania zmiennych naszej klasy. Na początku klasy db() mamy linijki odpowiedzialne za podanie danych dostępu do bazy danych (host, nazwa, login i hasło). Początek naszej klasy wyglądał następująco:

<?php
class db {
  private $db_host = 'localhost';
  private $db_name = 'nazwa_bazy';
  private $db_user = 'admin';
  private $db_passw = 'passw';
...
?>

W tym miejscu powinniśmy zmodyfikować tę część naszej klasy, aby podać dane odpowiednie dla naszej bazy danych. Co gorsza powinniśmy to robić za każdym razem kiedy chcemy wykorzystać klasę w kolejnych projektach, ale że czas to pieniądz z pomocą przychodzą nam stałe php.
Przerobimy naszą klasę tylko raz. Powyższy kod modyfikujemy w następujący sposób:

<?php
class db {
  private $db_host = DB_HOST;
  private $db_name = DB_NAME;
  private $db_user = DB_USER;
  private $db_passw = DB_PASSW;
...
?>

Tak zmodyfikowaną klasę możemy wykorzystywać do obsługi dowolnej bazy danych, bez każdorazowej ingerencji w plik class_db.php. Jedyną operację jaką musimy wykonać to zadeklarowanie stałych w pliku index.php tuż przed operacją require_once() – załadowaniem naszej klasy.
Tak więc nasz plik index.php będzie mieć postać:

<?php
define(DB_HOST, 'db_host'); // host naszej bazy danych najczęściej localhost lub IP bazy
define(DB_NAME, 'db_name'); // nazwa naszej bazy danych
define(DB_USER, 'user_name'); // nazwa użytkownika
define(DB_PASSW, 'user_passw'); // hasło dostępu dla użytkownika

$class_db_file = 'classes/class_db.php';
if (file_exists($class_db_file):
  require_once($class_db_file);
else:
  echo 'Klasa db() nie została odnaleziona';
  exit;
endif;
...
?>

Przy budowie większych aplikacji prawdopodobnie będziemy wykorzystywać plik z ustawieniami i właśnie w nim możemy dodać zdefiniowane elementy dla naszej bazy danych. Jeżeli kiedykolwiek “bawiliście” się CMS’ami
( Word Press , Joomla , Drupal  itp. ) na pewno napotkaliście na pliki typu settings.php, config.php, configuration.php itp., które to składają się przeważnie z ciągu definicji ? define(ELEMENT, ‘value’);
Jeżeli mamy już zdefiniowane dane dostępu do bazy, zobaczy jak wyglądać będzie…

Wykorzytsanie klasy db()

Na warsztat bierzemy jeden z najbardziej oklepanych przykładów ? tabela z produktami, zawierająca podstawowe informacje: id, producent, produkt, cena.

id brand product price
1 7th Sunrise website 1000 000 $
2 7th Sunrise catalog 600 000 $
3 7th Sunrise layout 100 000 $

Powiedzmy, że mamy sklep internetowy z produktami i chemy wyświetlić dostępne produkty ? musimy więc pobrać z bazy listę produktów wraz z ich właściwościami. Tak więc tworzymy funkcję odpowiedzialną za pobranie informacji z bazy danych, która jako wynik zwróci nam listę produktów w postaci tablicy, ale…pierwszym krokiem będzie utworzenie obiektu naszej klasy db:

<?php
...
$db = new db(); // tworzymy objekt $db klasy db, new oznacza nowy obiekt
...
?>

Następnie tworzymy funkcję odpowiedzialną za pobranie produktów:

...
$db = new db();

function select_all_products($db){
  if ($db->connect()):
    $sql = "SELECT * FROM `products`;";
    if ($results = $db->select($sql):
      $returned = array();
      while ($row = mysql_fetch_array($results):
        $returned[] = array(
          'id'  =>  $row['id'],
          'brand'  =>  $row['brand'],
          'product'  =>  $row['product'],
          'price'  =>  $row['price']
         );
      endwhile;
      return $returned;
    else:
      echo 'Błąd pobrania danych mysql: ' . $db->error;
      return false;
    endif; 
    $db->close();     
  else:
    echo 'Błąd połączenia mysql: ' . $db->error;
    return false;
  endif;
}
...

I po kolei:

  if ($db->connect()):

sprawdzamy czy połączenie z bazą danych zostanie utworzone, jeżeli nie zwracamy komunikat z błędem mysql, który zawarty jest w zmiennej error naszej klasy oraz false jako wynik funkcji select_all_products()

  else:
    echo 'Błąd połączenia mysql: ' . $db->error;
    return false;
  endif;

Jeżeli połączenie zostanie nawiązane:

    $sql = "SELECT * FROM `products`;";
    if ($results = $db->select($sql):

Następnie pod zmienną $results podstawiamy wynik zapytania, jeżeli zwróci false (błąd przy operacji na bazie):

    else:
      echo 'Błąd pobrania danych mysql: ' . $db->error;
      return false;
    endif;

wyświetlamy błąd operacji na bazie ($db->error) oraz zwracamy false jako wynik funkcji.

Jednakże jesteśmy dobrej myśli i przypuszczamy, że wszystko poszło ok i mamy zwróconą wartość z bazy danych, a dokładnie tablicę z wierszami i kolumnami.
Aby operować na wynikach z bazy danych musimy użyć funkcji mysql_fetch_array() . Jako, że pobieramy cała tablicę, a nie jeden wiersz ? musimy zrobić to w pętli:

      while ($row = mysql_fetch_array($results)):

co znaczy mniej więcej ‘dla każdego wiersza zwróconego w zapytaniu ($results) pod zmienną $row podstaw wynik. Jako wynik funkcja select_all_product() również zwróci tablicę z tablicami :) , czyli tablicę, której elementami są również tablice reprezentujące kolejne wiersze tabeli products

returned[0] = array(
  id => wiersz_1[kolumna_id],
  barnd => wiersz_1[kolumna_brand],
  itd...
 );

jako wartości dla $row[] podajemy w cudzysłowach nazwy kolumn tabeli products. Niestety dla każdej kolumny musimy osobno podawać $row['nazwa_kolumny']. Jeżeli mamy 3, 4 kolumny nie jest to duży problem, ale co jeżeli mamy pokaźną tablicę produktów gdzie oprócz id, producenta, nazwy, ceny mamy jeszcze np. rozmiary, kolory, ilość na magazynie itd. Itd. aż do kilkunastu kolumn?? Od czego mamy pętlę typu foreach ? Funkcję select_all_products() możemy zmodyfikować następująco:

...
  $sql = "SELECT * FROM `products`;";
    if ($results = $db->select($sql):
      $returned = array();
      while ($row = mysql_fetch_array($results):
        $mx = array();
         foreach ($row as $key => $val):
           $mx[$key] = $val;
         endforeach;
         $returned[] = $mx;
         );
      endwhile;
      return $returned;
...

Na koniec zamykamy połączenie z bazą:

...
$db->close();
...

Dzięki temu możemy utworzyć tablicę oszczędzając kilkanaście linijek kodu.

Aby wyświetlić wynik naszej funkcji:

...
$selected_products = select_all_products($db);
var_dump($selected_products);
...

Obsługa błędów

Do obsługi błędów spowodowanych operacjami na bazie danych, wykorzystujemy zmienną $error, która została utworzona na początku klasy db(). Wewnątrz funkcji klasy db() w przypadku wystąpienia błędu MySQL, jego treść zostanie podstawiona pod zmienną $db->error. Dzięki temu możemy dowolnie sformatować ew. Błąd. Możemy też wyświetlać go tylko podczas testów, następnie użytkownikowi wyświetlić tylko niezbędną informację np. “wystąpił błąd połączenia z bazą danych“. Nie ma potrzeby pokazywać użytkownikom całej treści zwróconego przez bazę błędu, tym bardziej, że może on często zawierać informacje, których nie chcemy ujawniać, takie jak nazwa użytkownika, nazwa bazy, host itp.

Inne możliwości wykorzystania

Naszą klasę db() możemy również wykorzystać wewnątrz innej klasy, wystarczy tylko w definicji zmiennych utworzyć:

class inna_klasa {
...
  public $db;
...

Następnie wewnątrz funkcji _construct() tworzymy objekt klasy db() i podstawiamy pod zmienną $db klasy:

...
function _construct(){
  $class_db_file = 'classes/class_db.php';
  if (file_exists($class_db_file):
    require_once($class_db_file);
    $this->db = new db();
  else:
    echo 'Brak pliku z klasą db';
  endif;
}
...

Funkcja operująca na bazie danych wewnątrz klasy inna_klasa() będzie wyglądać trochę inaczej. Jako przykład posłuzy nam funkcja dopisująca wiersz do tabeli products:

...
function insert_product(){
if ($this->db->connect()):
    $brand = 'producent';
    $product = 'nazwa produktu';
    $price = 'cena produktu';
    $sql = "INSERT INTO `products` VALUES (null, '$brand', '$product', '$price');";
    if ($this->db->query($sql)):
      return true;
    else:
      echo 'Błąd zapisu bazy danych: ' . $this->db->error;
       return false;
    endif;
    $this->db->close();
  else:
    echo 'Błąd połączenia z bazą danych: ' . $this->db->error;
    return false;
  endif;
}
...

Podstawową różnicą jest sposob dostępu do funkcji $this->db->nazwa_funkcji() zamiast $db->nazwa_funkcji().
I to już chyba wszystko. Wszelkie uwagi, pomysły rozwinięcia mile widziane…

REALIZACJA: Blog, MySQL, PHP

 
 

12 odpowiedzi do “Prosta klasa php do zarządzania bazą danych MySQL cz. 2”

  1. Artur 14 April 2011 at 18:17
    Witam dziękuje za bardzo przystępne opisanie klasy do obsługi bazy danych, ale czy w tym fragmencie: if (file_exists($class_db_file): nie brakuje drugiego nawiasu zamykającego? Ten fragment nie powinien wyglądać tak: if (file_exists($class_db_file)):
    50
     
    • Daniel Goździk 14 April 2011 at 19:50
      Oczywiście, że powinien. Dziękuję za zwrócenie uwagi na ten dosyć istotny błąd, który już został poprawiony.
      51
       
  2. Artur 13 May 2011 at 07:55
    załóżmy że do tej klasy chce dopisać funkcje realizującą mysql_fetch_array(), i mysql_num_rows(), to powinienem dać if($result = mysql_fetch_array($this->query($sql))) { return $result; czy if($result = mysql_fetch_array($this->select($sql))) { return $result; if($result = mysql_num_rows($this->query($sql))) { return $result; czy if($result = mysql_num_rows($this->select($sql))) { return $result;
    66
     
    • Daniel Goździk 14 May 2011 at 10:58
      Zdecydowanie $this->select(), funkcja query() służy do pozostałych operacji, takich jak UPDATE, INSERT, DELETE i zwraca true przy sukcesie lub false jeżeli operacja na bazie się nie powiedzie. Tylko funkcja select() zwraca dane z bazy, na których możemy wykonywać dalsze operacje.
      70
       
  3. bassyl 03 June 2011 at 23:38
    Czy funkcja select_all_products() jest umieszczona w klasie db(), czy całkowicie poza nią i nie jest umieszczona w żadnej klasie? Po wprowadzeniu prezentowanych skryptów, małej przeróbce – dostosowaniu do własnych potrzeb – skrypt wyświetla błąd: “Fatal error: Call to a member function connect() on a non-object in /home itd.” Linijka, w której jest ten błąd: “if ($db->connect())” O co w tym chodzi? Połączenie jest wykonywane obiektowo metodą connect klasy db(), więc co nieobiektowo jest zwracane – wartość true (boolean). Gdzie jest błąd w prezentowanym na tej stronie skrypcie?
    84
     
    • Daniel Goździk 06 June 2011 at 06:36
      W tej części artykułu ukazane są sposoby wykorzystania klasy. Funkcja select_all_products() jest tylko przykładem, jedną z możliwości użycia klasy. Nie jest częścią klasy. Natomiast co do zwracanego błędu, to wygląda na to że $db nie jest obiektem. Przed wywołaniem jakiejkolwiek funkcji musi nastąpić utworzenie obiektu klasy, czyli np. $db = new db(); Dopiero wtedy można operować na funkcjach klasy i samym obiekcie, np. $db->connect()
      85
       
    • Doładowania telefonu 21 January 2012 at 17:09
      Też miałem ten błąd co bassyl Fatal error: Call to a member function connect() on a non-object in Po analizie kodu udało mi się wywnioskować, że w funkcji function select_all_products() powinien zostać przekazany jako argument obiekt klasy db. Funkcja powinna mieć postać: function select_all_products($db) . Pojawiła się też literówka w : var_dump($selecEted_products); Po wprowadzeniu poprawek wszystko działa.
      255
       
      • Daniel Goździk 21 January 2012 at 18:57
        Bardzo słuszna uwaga. Dziękuję za zwrócenie uwagi. Faktycznie brak parametru przy deklarowaniu funkcji. Ewentualnie “global $db;” na początku funkcji też powinno załatwić sprawę.
        256
         
  4. Gravis 16 June 2011 at 15:57
    Hej a czy my przypadkiem nie mamy roku 2011?
    87
     
    • Daniel Goździk 17 June 2011 at 13:12
      No mamy mamy… czyżbym w powyższym poście twierdził inaczej?
      90
       
  5. Koriolan 25 December 2011 at 12:49
    Opis klasy jest SUPER . . . Poza mała wątpliwościa: Jesteś pewien, że query nie zwraca wyniku zapytania “SELECT . . .”
    239
     
  6. Koriolan 25 December 2011 at 13:33
    Sorry moje wątpliwości są bez sensu. Funkcję se lect() i query() są metodami klasy a nie funkcjami php. Mylnęło mi się
    240
     
 

Dodaj odpowiedź

 
 

 
 
Do góry