2008.11_Sklep internetowy w PHP i SQLite_[Aplikacje Biznesowe].pdf

(908 KB) Pobierz
441067342 UNPDF
E-commerce
Sklep internetowy
w PHP i SQLite
Zaprojektuj i zbuduj w mniej niż godzinę
Gotowych rozwiązań na rynku e-commerce są setki. Znajdziemy gotowe
skrypty o funkcjonalności systemów aukcyjnych, sklepów internetowych
oraz systemów barterowych. To najczęściej sprawdzone i tanie rozwiązania,
regularnie aktualizowane – dlatego skorzystanie z nich najczęściej bywa bardzo
kuszące. Jednak czy zawsze uzasadnione? Najczęściej o wiele lepiej stworzyć
własną platformę e-commerce. Nie jest to trudne – nam zajmie to 60 minut.
Dowiesz się:
• Jak zaprojektować od podstaw sklep interne-
towy;
• W jaki sposób korzystać z SQLite;
• Jak wykorzystać sesje do przechowywania da-
nych użytkownika.
Powinieneś znać:
• Co najmniej podstawy PHP oraz SQL;
• Podstawy programowania obiektowego.
zostać również umieszczony w konkretnej
kategorii – ułatwi to przeszukiwanie sklepu
użytkownikowi.
Klient naszego sklepu w przypadku doko-
nania zakupu powinien przekazać nam da-
ne niezbędne do zrealizowania zamówienia
(m.in. imię, nazwisko, adres, dane do faktu-
ry, dane wysyłki). Przyjęliśmy więc, że w ce-
lu dokonania zakupu konieczne jest posia-
danie konta w systemie. Rejestracja powin-
na być oczywiście bezpłatna, a klient powi-
nien mieć również możliwość samodzielne-
go usunięcia konta.
Warto również pomyśleć o systemie ra-
batów – pozwoli to zatrzymać klienta oraz
uatrakcyjnić cenowo naszą ofertę. Rabat mo-
żemy uzależnić od wielu elementów – wiel-
kości zakupów, kodu promocyjnego podane-
go podczas rejestracji lub przekroczenie okre-
ślonej wartości wszystkich zakupów od chwi-
li zarejestrowania konta. W naszym sklepie
rabat będzie przydzielany ręcznie przez ad-
ministratora – czytelnik jednak bez więk-
szych problemów będzie w stanie dopasować
system rabatowy do własnych potrzeb.
Ostatnim niezbędnym elementem jest lista
zamówień. Zastanówmy się jakie informacje
są naprawdę potrzebne do sprawnego obsłuże-
nia klienta. W większości przypadków powin-
no wystarczyć imię i nazwisko zamawiającego,
adres wysyłki, data złożenia zamówienia, stan,
data wysłania towarów oraz oczywiście zamó-
wione towary.
go wpływu na poziom trudności pracy. Dlate-
go nasz sklep zbudujemy wykorzystując PHP5
oraz… SQLite.
Poziom trudności
Przed rozpoczęciem pracy…
… należy zastanowić się nad funkcjonalnością
sklepu. Chcemy oczywiście sprzedawać okre-
ślone produkty – to oczywiste. Zastanówmy
się jednak, co dokładnie chcemy przedsta-
wić potencjalnemu nabywcy. Na pewno bę-
dzie to nazwa produktu oraz jego opis. Lu-
dzie lubią widzieć, co kupują, wskazane jest
więc umieszczenie co najmniej jednego zdję-
cia. Część produktów wymaga dokładniejsze-
go sfotografowania, tak więc nie powinniśmy
ograniczyć maksymalnej liczby zdjęć. Oczy-
wiście niezbędne jest również uwzględnienie
ceny oraz stawkę podatku VAT. W zależno-
ści od typu produktów można pomyśleć rów-
nież nad dodatkowymi polami określający-
mi jego parametry (dla sklepu z butami war-
to pomyśleć o polach z rozmiarami, sprzeda-
jąc dyski twarde warto zaznaczyć ich pojem-
ność) a jeśli znamy stan magazynu możemy
również wykorzystać tą informację. Nie ma
bowiem sensu pokazywać użytkownikowi to-
waru, którego nie mamy na stanie, lub który
został już raz sprzedany. Produkt powinien
żać gotowych rozwiązań może być wie-
le. Dla prostego sklepu internetowego,
w którym właściciel chce zaoferować kilka pro-
duktów wykorzystanie osCommerce może być
nieoptymalne. Dodatkowo modyfikowanie ta-
kiej gotowej platformy również nie należy do
rzeczy najprostszych – jeśli dostępna jest do-
kumentacja, wystarczy się z nią zapoznać. Jeśli
jednak jej nie ma, pozostaje metoda prób i (nie-
stety najczęściej) błędów. W obu przypadkach
potrzebujemy czasu – który możemy poświę-
cić na stworzenie własnego, dedykowanego roz-
wiązania. Za chwilę zobaczysz, że w mniej niż
60 minut można zbudować sklep interneto-
wy, który pomimo okazałej nazwy jest po pro-
stu interfejsem pośredniczącym pomiędzy ba-
zą danych a użytkownikiem, wykonującym na
niej określone operacje. Struktura takiej ba-
zy najczęściej nawet nie jest bardzo skompli-
kowana, tak więc można użyć praktycznie do-
wolnego silnika baz danych. Nie ma to żadne-
Minuta pierwsza – baza danych
Na początku prac zaprojektujemy struktu-
rę naszej bazy danych. Do stworzenia ba-
20
11/2008
P owodów, dla których nie warto wdra-
441067342.050.png 441067342.058.png 441067342.059.png 441067342.060.png 441067342.001.png 441067342.002.png 441067342.003.png 441067342.004.png 441067342.005.png 441067342.006.png
Sklep internetowy w PHP i SQLite
zy można użyć zewnętrznych narzędzi (np.
zewnętrzny SQLite Manager działający ja-
ko dodatek do przeglądarki Mozilla Firefox)
lub napisanego samodzielnie prostego skryp-
tu w PHP.
Wystarczy do tego podstawowa znajomość
języka SQL oraz funkcji wbudowanych w PHP
służących do komunikacji z bazą sqlite.
Gotowy skrypt przedstawiony jest na Li-
stingu 1. Jego działanie jest proste – łączy-
my się z plikiem bazy danych, oraz wywo-
łujemy 5 zapytań tworzących 5 tabel – ta-
belę do przechowywania informacji o użyt-
kownikach, produktach, dostępnych kate-
goriach, oraz dwie tabele do przechowywa-
nia informacji o zamówieniach użytkowni-
ka. Strukturę utworzonych tabel przedsta-
wia Rysunek 1.
Część z was najprawdopodobniej zauwa-
żyła, że brakuje pól w których będą przecho-
wywane informacje o zdjęciach produktów.
Zamiast tego, zdjęcia będą miały nazwę od-
powiadającą unikalnemu polu zawierające-
mu unikalne ID produktu, znak separato-
ra (podkreślnik) oraz kolejny numer zdję-
cia produktu. Pozwoli to na umieszczenie
praktycznie nieograniczonej ilości zdjęć.
PHP dostarcza nam mechanizm umożliwia-
jący proste sprawdzenie czy plik w określo-
nej lokalizacji istnieje (służy do tego funk-
cja file_exist() ) – dzięki temu nie musi-
my przechowywać informacji o tym fakcie w
bazie danych.
Zdziwić może również brak atrybutów
AUTOINCREMENT przy tworzeniu bazy. Jest to
związane z tym, że w SQLite wszystko jest łań-
cuchem znaków. Typ kolumny pomaga silniko-
wi bazy dane te odpowiednio posortować, oraz
zwiększa przejrzystość tabel.
Autorzy jednak udostępnili substytut atry-
butu – wystarczy zadeklarować w tabeli pole
INTEGER PRIMARY KEY .
Minuta 10 – obiekty
W kolejnym kroku utworzymy klasy repre-
zentujące trzy podstawowe typy obiektów
które zdefiniowaliśmy na początku artyku-
łu – dla użytkownika, produktu, oraz za-
mówienia.
W każdej klasie oprócz pól charaktery-
stycznych dla bazy danych znajduje się rów-
nież prywatne pole error – wykorzystamy
je do zapisywania informacji o ewentual-
nym błędzie (na przykład błędzie podczas
połączenia z bazą danych, lub nieprawidło-
wych danych logowania). Przyjmijmy rów-
nież, że wszystkie funkcje i metody zwraca-
ją wartość logiczną – prawdę, gdy realizowa-
na operacja się powiedzie, oraz fałsz gdy wy-
stąpi jakikolwiek błąd. Dzięki temu spraw-
dzenie poprawności wykonania nawet cy-
klu operacji jest dziecinnie proste – sprowa-
dza się do wprowadzenia kilku instrukcji wa-
runkowych.
Listing 1. Skrypt tworzący tabele w bazie danych
<? php
include 'conig.php' ;
if ( $db = sqlite_open ( $sqlitePath , 0666, $sqliteerror ))
{
sqlite_query ( $db , 'CREATE TABLE "users" ( "users_id" INTEGER PRIMARY KEY , "users_username" TEXT NULL , "users_name" TEXT NULL
, "users_city" TEXT NULL , "users_postcode" TEXT NULL , "users_adress" TEXT NULL , "users_phone" TEXT NULL
, "users_mail" TEXT NULL , "users_dname" TEXT NULL , "users_deliverycity" TEXT NULL , "users_password" TEXT
NULL , "users_deliverypostcode" TEXT NULL , "users_deliveryaddress" TEXT NULL , "users_discount" TEXT NULL ,
"users_nip" TEXT NULL );' ) ;
sqlite_query ( $db , 'CREATE TABLE "products" ("products_id" INTEGER PRIMARY KEY , "products_name" TEXT NULL , "products_
description" TEXT NULL , "products_price" TEXT NULL , "products_tax" INT NULL , "products_count" INT NULL ,
"products_categoryid" INT NULL );' ) ;
sqlite_query ( $db , 'CREATE TABLE "category" ( "category_id" INTEGER PRIMARY KEY , "category_name" NULL);' ) ;
sqlite_query ( $db , 'CREATE TABLE "orders" ( "order_id" INTEGER PRIMARY KEY , "order_userid" INT NULL , "order_date" INT NULL ,
"order_status" TEXT NULL , "order_sdate" INT NULL );' ) ;
sqlite_query ( $db , 'CREATE TABLE "order_products" ( "product_id" INTEGER PRIMARY KEY , "order_id" INT NOT NULL , "op_amount" INT
NOT NULL );' ) ;
sqlite_close ( $db ) ;
echo 'Tabele zosta³y utworzone!' ;
}
else
{
die ( 'Wystąpił błąd: ' . $sqliteerror ) ;
}
?>
Listing 2. Zawartość pliku conig.php
<? php
$sqlitePath = './sklep2.sqlite' ;
session_start () ;
function __autoload( $class_name ) {
require_once './class/' . $class_name . '.php' ;
}
?>
www.sdjournal.org
21
441067342.007.png 441067342.008.png 441067342.009.png 441067342.010.png 441067342.011.png 441067342.012.png 441067342.013.png 441067342.014.png 441067342.015.png 441067342.016.png 441067342.017.png
E-commerce
Listing 3a. Fragment klasy user – służącej do obsługi użytkownika
class user
{
public $id ;
public $username ;
public $password ;
public $name ;
public $city ;
public $postcode ;
public $adress ;
public $phone ;
public $mail ;
public $dname ;
public $deliverycity ;
public $deliverypostcode ;
public $deliveryadress ;
public $discount ;
public $nip ;
private $error ;
function __constuct( $id = '' )
{
if ( $id != '' )
$this - > load ( $id ) ;
}
function load( $id )
{
if ( $db = sqlite_open ( $sqlitePath , 0666, $this - > error ))
{
$value = sqlite_array_query ( $db , "SELECT * FROM users
WHERE users_id = '".$id."'");
}
}
function checklogin( $username , $password )
{
if ( $db = sqlite_open ( $sqlitePath , 0666, $this - > error ))
{
$value = sqlite_array_query ( $db , "SELECT users_id
FROM users WHERE users_username =
'".$username."' AND users_password =
MD5 ( ". $password ." ) " ) ;
if ( sqlite_num_rows ( $db ) == 0 )
{
$this - > error = 'Nieprawid³owa nazwa u¿ytkownika
lub has³o!' ;
sqlite_close ( $db ) ;
return -1;
}
return $value [ 'users_id' ] ;
}
else
{
return 0;
}
}
function add( $username , $password , $name , $city , $postcode ,
$adress , $phone , $mail , $dname ,
$deliverycity , $deliverypostcode ,
$deliveryadress , $discount , $nip )
{
$this - > username = sqlite_escape_string ( $username ) ;
$this - > password = sqlite_escape_string ( $password ) ;
$this - > name = sqlite_escape_string ( $name ) ;
$this - > city = sqlite_escape_string ( $city ) ;
$this - > postcode = sqlite_escape_string ( $postcode ) ;
$this - > adress = sqlite_escape_string ( $adress ) ;
$this - > phone = sqlite_escape_string ( $phone ) ;
$this - > mail = sqlite_escape_string ( $mail ) ;
$this - > dname = sqlite_escape_string ( $dname ) ;
$this - > deliverycity = sqlite_escape_
string ( $deliverycity ) ;
$this - > deliverypostcode = sqlite_escape_string ( $delivery
postcode ) ;
$this - > deliveryadress = sqlite_escape_
string ( $deliveryadress ) ;
$this - > discount = sqlite_escape_string ( $discount ) ;
$this - > nip = sqlite_escape_string ( $nip ) ;
if ( $this - > validate ())
{
if ( $db = sqlite_open ( $sqlitePath , 0666, $this - > error
))
if(sqlite_num_rows( $value ) == 0)
{
$this ->error = " Brak u¿ytkownika o podanym id!";
return false;
}
$this - > id = $value [ 'users_id' ] ;
$this - > username = $value [ 'users_username' ] ;
$this - > password = $value [ 'users_password' ] ;
$this - > name = $value [ 'users_name' ] ;
$this - > city = $value [ 'users_city' ] ;
$this - > postcode = $value [ 'users_postcode' ] ;
$this - > adress = $value [ 'users_adress' ] ;
$this - > phone = $value [ 'users_phone' ] ;
$this - > mail = $value [ 'users_mail' ] ;
$this - > dname = $value [ 'users_dname' ] ;
$this - > deliverycity = $value [ 'users_deliverycity' ] ;
$this - > deliverypostcode = $value [ 'users_
deliverypostcode' ] ;
$this - > deliveryadress = $value [ 'users_
deliveryadress' ] ;
$this - > discount = $value [ 'users_discount' ] ;
$this - > nip = $value [ 'users_nip' ] ;
$this - > error= '' ;
sqlite_close ( $db ) ;
return true;
}
else
{
return false;
{
sqlite_array_query ( $db , "INSERT INTO users (users_
id, users_username, users_password,
users_name, users_city, users_postcode,
users_adress, users_phone, users_mail,
users_dname, users_deliverycity, users_
deliverypostcode, users_deliveryadress,
users_discount, users_nip) VALUES
22
11/2008
441067342.018.png 441067342.019.png 441067342.020.png 441067342.021.png 441067342.022.png 441067342.023.png 441067342.024.png
 
Sklep internetowy w PHP i SQLite
W naszym systemie skorzystamy z mecha-
nizmu automatycznego ładowania plików
z klasami wprowadzonego w piątej wersji
PHP. Dlatego klasy, z których będziemy korzy-
stać bezpośrednio w skrypcie musimy umie-
ścić w osobnych plikach o nazwach takich sa-
mych jak nazwy klas.
Sama funkcja __autoload() umieszczona
została w pliku config.php . Plik ten dołącza-
ny jest na początku projektu – gwarantuje to,
że funkcja będzie dostępna w każdym miej-
scu skryptu.
W pliku tym zdefiniowaliśmy również na-
zwę pliku z bazą danych oraz wystartowaliśmy
mechanizm sesji.
Klasa posiada zdefiniowany jednoparame-
trowy konstruktor. Podanie parametru nie
jest jednak konieczne – jeśli nie zostanie po-
dany, zostanie utworzony pusty obiekt. Jeśli
jednak jako parametr podamy id użytkow-
nika, zostanie wywołana metoda load() któ-
��������
��������������
�����
���������������
������������������
�������������������������
�������������������
����������������
������������������
�����������������������
��������������
������������
�������������
������������
�������������������
���������������
���������������
�������������������
�����������������
����������������
���������������
����������������
�����������������������
��������������������������
���������������������������
��������������������������
�������������������
��������������
�������
�������
Użytkownik
Na Listingu 3a i 3b przestawiono fragment
klasy reprezentującej użytkownika. Powinna
ona dostarczyć nam wszystkich operacji nie-
zbędnych do obsługi użytkownika. Wszyst-
kie pola wyłączając pole $error są publicz-
ne – chcemy mieć bowiem do nich dostęp
w każdym miejscu skryptu. Oczywiście mo-
żesz utworzyć zmienne prywatne i utwo-
rzyć metodę do ich zwracania. Pole error
nie powinno być modyfikowane z zewnątrz
klasy – dlatego pozostanie prywatne, a do-
stęp do jego zawartości spoza klasy odby-
wa się wyłącznie za pośrednictwem meto-
dy geterror() .
��������
������
���������������
�������������
������������
����������������
��������������
�����������������
���������������
�������
�������
�������
Rysunek 1. Schemat utworzonej bazy danych
Listing 3b. Fragment klasy user – służącej do obsługi użytkownika
(NULL, " . $this - > username. ", " . $this -
> password. ", " . $this - > name. ",
" . $this - > city. ", " . $this - > postcode. ",
" . $this - > adress. ", " . $this - > phone. ",
" . $this - > mail . ", " . $this - > dname. ",
" . $this - > deliverycity. ", " . $this -
> deliverypostcode. ", " . $this -
> deliveryadress. ", " . $this - > discount. ",
" . $this - > nip. ");" ) ;
sqlite_close ( $db ) ;
return true;
}
else
{
return false;
}
}
}
function validate( )
{
//realizację funkcji validate pozostawiamy czytelnikowi.
//funkcja powinna zwróciæ false gdy nie podano wszystkich
wymaganych pól
return true;
}
function geterror( )
{
return $this - > error;
}
}
Listing 4. Metoda updatecount() klasy product
function updatecount( $id , $newcount )
{
if ( $db = sqlite_open ( $sqlitePath , 0666, $this - > error ))
{
sqlite_array_query ( $db , "UPDATE products SET products_
count = '".$newcount."' WHERE products_
id = '".$this->id."' ;" ) ;
sqlite_close ( $db ) ;
return true;
}
else
{
return false;
}
}
www.sdjournal.org
23
441067342.025.png 441067342.026.png 441067342.027.png 441067342.028.png 441067342.029.png 441067342.030.png 441067342.031.png 441067342.032.png 441067342.033.png 441067342.034.png 441067342.035.png 441067342.036.png 441067342.037.png 441067342.038.png 441067342.039.png 441067342.040.png 441067342.041.png 441067342.042.png 441067342.043.png 441067342.044.png 441067342.045.png 441067342.046.png 441067342.047.png 441067342.048.png 441067342.049.png
E-commerce
Listing 5. Fragment odpowiedzialny za wyświetlenie kategorii oraz spisu towarów
<? php
include 'conig.php' ;
$error = '' ;
$categories = array () ;
$products = array () ;
if ( $db = sqlite_open ( $sqlitePath , 0666, $error ))
{
//wybieramy wszystkie dostêpne kategorie
$table = sqlite_array_query ( $db , 'SELECT * FROM category' ) ;
foreach ( $table as $value )
{
$categories [] = array ( $value [ 'category_id' ] , $value [ 'category_name' ]) ;
}
//Wyœwietlamy u¿ytkownikowi menu z wyborem kategorii:
echo ' < div name= "categories" > ';
foreach($categories as $category)
{
echo ' < a href= "list.php?category='.$category[0].'" > '.$category[1].' < /a >< br > ';
}
echo ' < /div > ';
//sprawdzamy, czy u¿ytkownik wybra³ kategorie:
if ( $_GET [ 'category' ] == '' )
{
echo ' < div name= "message" > Witaj w naszym sklepie internetowym! Wybierz interesuj¹c¹ Ciê kategorie! < /div > ';
}
else
{
//jeœli tak - pobieramy towary z bazy:
$table = sqlite_array_query ( $db , 'SELECT products_id FROM products WHERE products_categoryid = "' .sqlite_escape_string ( $_
GET [ 'category' ]) . '" AND products_count>0;' ) ;
if ( count ( $table ) ==0 )
{
echo ' < div name= "message" > Nie znaleziono produktów w kategorii! < /div > ';
}
else
{
foreach($table as $value)
{
$products[] = $value[' products_id' ] ;
}
//oraz wyœwietlamy:
echo ' < div name= "products" > ';
foreach($products as $id)
{
$product = new product($id);
echo ' < div name= "singleproduct" >< a href="details.php?productid='.$product- > id. '">' . $product - > name.' < /a >< br >
Cena netto: '.$product->price.' ( + '. $product->tax.' ) < br >
Opis: '.substr($product->description, 0, 150).' < a href="details.php?productid='.$product- > id.'" >[ ... ] dalej < /a >< /div > ';
}
echo ' < /div > ';
}
}
sqlite_close($db);
}
else
{
die(' Wyst¹pi³ b³¹d: '. $error ) ;
}
?>
24
11/2008
441067342.051.png 441067342.052.png 441067342.053.png 441067342.054.png 441067342.055.png 441067342.056.png 441067342.057.png
 
Zgłoś jeśli naruszono regulamin