plik


ÿþWY{SZA SZKOAA INFORMATYKI I ZARZDZANIA Z SIEDZIB W RZESZOWIE WYDZIAA ADMINISTRACYJNO-INFORMATYCZNY Kierunek: INFORMATYKA I EKONOMETRIA Specjalno[: SYSTEMY I SIECI KOMPUTEROWE Autor: BARTAOMIEJ SIBAB IMPLEMENTACJA SYSTEMU SKLEPU INTERNETOWEGO NA BAZIE OPROGRAMOWANIA OPENSOURCE PRACA DYPLOMOWA PROMOTOR DR IN{. JANUSZ ZWIERZOWICZ Rzeszów 2001 Wstp Przedstawiony projekt systemu internetowej sprzeda|y towarów jest fragmentem caBo[ci serwisu internetowego firmy. ZostaB on zbudowany przy wykorzystaniu narzdzi i oprogramowania OpenSource. Korzysta z istniejcych w aplikacjach finansowo ksigowych danych, gromadzonych w codziennej dziaBalno[ci przedsibiorstwa. Za kryterium podstawowe przyjto ekonomiczne dostosowanie tworzonych rozwizaD pod ktem zastosowania takiego modelu sklepu internetowego w firmach maBej i [redniej wielko[ci. Kod aplikacji jest wysoce elastyczny i pozwala na swobodne modyfikowanie zarówno formatu wej[cia danych jak i interfejsu u|ytkownika oraz wkomponowanie w istniejcy serwis internetowy firmy. Aktualna dziaBajca aplikacja sklepu internetowego znajduje si pod adresem: http://www.vt.pl/ gdzie jest u|ytkowana i stale rozwijana. W rozwój aplikacji sklepu internetowego oraz caBo[ci serwisu firmy du|y wkBad pracy stale wnosi mój przyjaciel RadosBaw Wierzbicki za co niniejszym skBadam mu podzikowanie. 2 Cel i zakres pracy RozdziaB I omawia zaBo|enia wstpne, przedstawia charakter pracy oraz metody i narzdzia zastosowane w budowie aplikacji. Omówiono tutaj uwarunkowania ekonomiczne powstajcego systemu oraz zaprezentowano baz systemow oprogramowania. RozdziaB II przedstawia teori i funkcjonowanie sklepu internetowego, ukazuje wymagania u|ytkowników dotyczce dziaBania serwisów internetowych firm. Przedstawia wpByw marketingu i reklamy na popularno[ serwisu. Prezentuje zasady dziaBania oraz model logiczny i funkcjonalny tego typu aplikacji internetowych. RozdziaB III prezentuje przygotowanie danych na potrzeby sklepu internetowego. Przedstawia sposoby konwersji, archiwizacji i przesyBania danych pomidzy serwerami i aplikacjami istniejcymi w przedsibiorstwie. Pokazuje procedury konwersji i obróbki danych oraz ich automatyczny zaBadunek do systemu bazodanowego. RozdziaB IV omawia struktur i organizacj bazy danych sklepu. Prezentuje skrypty administracyjne i bazodanowe systemu oraz omawia ich budow i dziaBanie. Przedstawia podziaB funkcjonalny konstruowanych podprocedur oraz struktur bazy SQL. RozdziaB V prezentuje wyszukiwark towarów, koncepcj i zasad dziaBania oraz kod zródBowy. Omawia napotykane problemy optymalizacji zapytaD do bazy danych i sposoby ich rozwizywania. RozdziaB VI przedstawia dalsze cele i kierunki rozwoju projektu sklepu internetowego. Omawia budow interfejsu rejestracji informacji dodatkowych o towarach oraz model i zasad dziaBania  koszyka na towary. Prezentuje stosowane metody [ledzenia i utrzymywania sesji pomidzy webserwerem a przegldark klienta. Podsumowanie pracy omawia zebrane podczas budowy projektu wnioski i do[wiadczenia. 3 RozdziaB I  ZAAO{EN IA WSTPNE, PRZEDSTAWIENIE METOD I NARZDZI UWARUNKOWANIA EKONOMICZNE W czasach gwaBtownego rozwoju Internetu, dziaBalno[ gospodarcza wkracza w nowy etap rozwoju. Nowe mo|liwo[ci jakie stwarza zasig dziaBania, powszechno[ oraz dostpno[ Internetu inspiruj do zainteresowania si rozwojem biznesu na tej platformie. Szczególn dziedzin, w której jest mo|liwy szybki rozwój i poszerzenie podstawowej i tradycyjnej dziaBalno[ci jest handel, rozumiany zarówno jako wymiana pomidzy partnerami jak i dostawcami a ich klientami. Rozwój maBej i [redniej przedsibiorczo[ci wymaga rozwizaD dostosowanych do potrzeb tego segmentu dziaBalno[ci komercyjnej. Rynek ten w krajach Unii Europejskiej czy te| w Stanach Zjednoczonych jest okre[lany jako SOHO (Small Office Home Office). Podstawowym kryterium jest tu wielko[ firmy, ró|nie rozumiana, czsto jako ilo[ zatrudnionych pracowników czy te| wielko[ generowanych przychodów, obrotów itp. Jedyn ró|nic pomidzy Polsk a innymi krajami Europy Zachodniej jest wBa[nie skala wedBug której nastpuje segmentacja. W Polsce przyjmuje si |e [redniej wielko[ci przedsibiorstwo zatrudnia ponad dwudziestu piciu pracowników. Jest to o rzd wielko[ci mniejsza liczba ni| w innych krajach Unii Europejskiej. Analiza potrzeb takich firm wykazaBa, |e podstawowym kryterium wyboru rozwizaD informatycznych wspierajcych i rozszerzajcych dziaBalno[ podstawow s koszty zarówno zakupu, rozwoju jak i utrzymania systemów, oprogramowania i administracji. SpoBeczno[ internetowa jednoznacznie wykazuje ogromne zainteresowanie rozwojem oprogramowania i systemów OpenSource (www.opensource.org) zarówno opartych na licencji GNU GPL jak i BSD. Teksty tych dokumentów umieszczone s pod adresem www.opensource.org/licenses PrzykBadem systemów OpenSource jest np. Linux czy wiele innego doskonaBego oprogramowania okre[lanego wspóln nazw GNU. Kolejnym elementem jest tak|e caBa rodzina Unix owych sieciowych systemów operacyjnych *BSD takich jak FreeBSD (www.freebsd.org), NetBSD (www.netbsd.org), OpenBSD (www.openbsd.org), baz danych takich jak PostgreSQL (www.postgresql.org), jzyków programowania jak PHP (www.php.net) i innych. Tendencje te ostatnio znalazBy poparcie u  wielkich rynku informatycznego. Sun wykupiB i udostpniB na licencji GNU pakiet biurowy StarOffice, IBM przeniósB Linux'a na swoje platformy mainframe, Borland stworzyB [rodowisko Delphi/Kylix do budowy uniwersalnych aplikacji dla [rodowiska Windows/Linux oraz 4 udostpniB baz InterBase itp. PowstaBa organizacja Free Software Foundation (www.fsf.org) wspierajca ten  ruch w kierunku dalszego upowszechniania i popularyzowania tego trendu. Bazujc na osigniciach spoBeczno[ci internetowej w tej dziedzinie za podstaw realizacji systemu umo|liwiajcego maBym i [rednim firmom wkroczenie w sfer e-biznesu przyjto systemy bazujce na tego typu oprogramowaniu. PREZENTACJA BAZY SYSTEMOWEJ OPROGRAMOWANIA Na podstaw do budowy systemu kompleksowo obsBugujcego caBo[ dziaBaD komunikacyjnych, sieciowych, aplikacyjnych a jednocze[nie zapewniajcego wysoki stopieD bezpieczeDstwa caBego systemu zostaB wybrany system Unix z rodziny BSD. FreeBSD jest systemem dedykowanym i optymalizowanym do pracy na platformie Intel (IA32) oraz Alpha. Jest on z powodzeniem stosowany przez najwikszych dostawców usBug internetowych i przeznaczony jest do pracy przy bardzo du|ych obci|eniach. PrzykBadem jego wykorzystania s serwisy web i email np. Yahoo.com lub Hotmail.com, najwikszy serwis ftp ftp.cdrom.com czy te| rodzimy Home.pl. Na serwerze firmy gdzie wykonano wdro|enie kompletnego [rodowiska obsBugujcego caBo[ dziaBalno[ci internetowej zainstalowany zostaB Unix FreeBSD, serwer pocztowy Qmail (www.qmail.org) dedykowany do obsBugi poczty internetowej (nawet do kilku milionów przesyBek dziennie), webserwer Apache (www.apache.org) do obsBugi serwisów WWW oraz dostpu do poczty poprzez przegldark na bazie TWIG (twig.screwdriver.net) a tak|e obsBugi sklepu internetowego dziaBajcego na bazie PostgreSQL (www.postgresql.org), do której dostp i dynamicznie budowane strony wykonano w PHP4 (www.php.net). GwaBtownie rosnc popularno[ tego jzyka przedstawia Rysunek 1. Rysunek 1  Popularno[ jzyka PHP. 5 Serwer internetowy [wiadczy ponadto wiele innych usBug i zabezpieczony zostaB firewallem. Analogicznie, po stronie wewntrznego LAN firmy zostaB uruchomiony drugi serwer na bazie FreeBSD obsBugujcy kilka podsieci firmy oraz zapewniajcy dostp do internetu z wewntrz firmy. Na serwerze w celu poprawienia wewntrznego bezpieczeDstwa sieci równie| uruchomiono firewall oraz translacj adresów. Sie firmowa oparta jest na stacjach roboczych z oprogramowaniem MS Windows natomiast na serwerze FreeBSD sie Windows jest obsBugiwana przez oprogramowanie Samba (www.samba.org). Oprogramowanie finansowo ksigowe stworzone przez firm Comvar (www.comvar.com.pl) na bazie CA Clipper rezyduje na dyskach sieciowych wewntrznego serwera i tam przechowywane s dane. Taka organizacja pozwoliBa na wykorzystanie danych firmy do automatycznego zasilania sklepu internetowego a ponadto udostpniBa caBej firmie wymagane usBugi internetowe przy minimalnych kosztach, bowiem caBe oprogramowanie serwerów bazuje na OpenSource. Schemat dziaBania caBo[ci struktury sieciowej firmy sprawdziB si w cigu kilku lat jego funkcjonowania i gwarantuje wysok jako[ i niezawodno[ dziaBania. Na serwerach dokonywana jest regularna archiwizacja wszystkich danych firmy a samo [rodowisko FreeBSD jako wyjtkowo odporne na awarie wydaje si by wrcz przeznaczone do takich celów. Pocztkowo wyj[ciowym systemem byB Linux, jednak problemy wystpujce z udostpnianiem i poprawn prac sieci Windows oraz podatno[ jego filesystemu (extfs2) na awarie wykluczyBa go z dalszego stosowania, gdy| byB on tutaj najsBabszym ogniwem. Strategia ta znalazBa pózniejsze potwierdzenie w sytuacji, gdy z przyczyn niezale|nych od firmy caBa serwerownia na skutek awarii wodocigów w budynku zostaBa doszcztnie zalana wod. Zniszczeniu ulegBy zasilacze UPS oraz router Cyclades obsBugujcy Bcze do internetu poprzez Polpak Frame Relay. Modemy Lucent DSLPipe obsBugujce Bcza do zdalnych siedzib firmy na terenie miasta nie zostaBy uszkodzone. W serwerach na skutek tej awarii zniszczeniu ulegBy karty sieciowe. Po wymianie kart sieciowych w cigu kilku godzin sie firmowa przywrócona zostaBa do dziaBania a |adne dane zgromadzone na dyskach serwerów nie ulegBy uszkodzeniu. Poprzez zastosowanie struktury skrzynek pocztowych natywnych dla Qmail a okre[lanej jako Maildir, pomimo awarii zasilania w trakcie dostarczania poczty do skrzynek nie ulegBa ona uszkodzeniu. Bie|ca dziaBalno[ firmy, po krótkim czasie niezbdnym na wymian uszkodzonych podzespoBów, mogBa by kontynuowana i |adne dane nie ulegBy zniszczeniu, nie byBo nawet potrzeby odzyskiwania ich z kopii zapasowych. 6 Rysunek 2 przedstawia schematyczn struktur topologiczn sieci firmy: zdalne oddziaBy firmy strefa zdemilitaryzowana (DMZ) Internet siedziba gBówna firmy Rysunek 2  Topologia sieci przedsibiorstwa. 7 RozdziaB II  TEORIA I FUNKCJONOWANIE WYMAGANIA U{YTKOWNIKÓW Podstaw dziaBania sklepu internetowego s dane o towarach, na bazie których mo|liwe jest dalsze jego konstruowanie. W praktyce dziaBania sklepu dane te sBu| prezentacji posiadanych produktów przeznaczonych do sprzeda|y internetowym kanaBem dystrybucji. Z przeprowadzanych analiz zachowaD internautów odwiedzajcych tego typu serwisy, charakterystyczna jest zasada, |e ka|da strona musi zosta zaBadowana w cigu 7-10 sekund od próby wej[cia do serwisu internetowego. DBu|szy czas  od[wietlania strony zniechca internautów i powoduje rezygnacj z dalszej eksploracji zasobów firmy. Szybko[ transferów osigana przez najcz[ciej wykorzystywane do Bczenia z Internetem popularne modemy gwarantuje przepustowo[ w zakresie od 3KB/s do 6KB/s, std wynika i| ilo[ danych wysyBanych przez serwer WWW do przegldarki klienta nie powinna przekracza 30KB do 60KB maksymalnie na podstawowe strony firmowe. Specyficzne jest natomiast podej[cie internautów do stron specjalizowanych np. z prezentacjami multimedialnymi lub szczegóBowymi danymi technicznymi i u|ytkowymi produktów, które wzbudziBy ich zainteresowanie i o których chc uzyska szczegóBowe informacje. Tutaj  cierpliwo[ u|ytkowników Internetu jest du|o wiksza, a ich gotowo[ do  czekania na zaBadowanie strony jest kilku a nawet kilkunastokrotnie wiksza. Takie strony mog mie rozmiary rzdu 100KB i wicej, o ile zbudowane s w taki sposób, |e ju| w trakcie ich Badowania przegldarka wy[wietla stopniowo [cigane dane. Przy najwikszych stronach konieczne wydaje si dzielenie prezentowanych informacji na wiele mniejszych fragmentów, po których u|ytkownik mo|e swobodnie nawigowa za pomoc hyperlinków i ró|nego rodzaju statycznych i dynamicznych odsyBaczy. W dobrym tonie jest konstruowanie stron  lekkich czyli nie przeBadowanych zbdn grafik Badujc si powoli, a przy odno[nikach do plików z wikszymi obrazami czy te| plikami multimedialnymi podawanie ich rozmiaru lub przybli|onego czasu Badowania. Organizacja logiczna i wizualna strony musi by jasna i przejrzysta dla potencjalnego klienta. Jezyk HTML opisu strony musi by zgodny ze obowizujcymi standardami i zwyczajami stosowanymi w budowie stron. Wystpuje tendencja do takiego budowania strony, aby byBa mo|liwa do poprawnej prezentacji nawet przez najprostsze przegldarki trybu tekstowego dostpne na platformach unixowych (jak choby Lynx, Links czy W3M). Oczywi[cie nale|y tak|e wykorzystywa wszelkie nowo[ci jak skrypty Java czy DHTML jednak w taki sposób, aby zapewni poprawne interpretowanie 8 strony we wszystkich najpopularniejszych przegldarkach ró|nych firm i ich kilku ostatnich wersjach. Charakterystycznym wydaje si by celowa rezygnacja w wielu serwisach internetowych ze stosowania ramek i zastpienie ich tabelami. Sklep internetowy ze wzgldu na specyfik swojego dziaBania, musi zapewnia bezpieczeDstwo zgromadzonych danych klientów, szczególnie gdy realizowane s pBatno[ci kartami pBatniczymi. Stosowanym standardem jest szyfrowanie transmisji takich danych przy u|yciu protokoBu SSL. Obecn tendencj jest tak|e scedowanie obowizku weryfikacji i autoryzacji kart pBatniczych na zaufan stron  trzeci w osobie organizacji zajmujcej si autoryzowaniem transakcji elektronicznych. Nowo[ci ostatnio wprowadzan w Polsce przez PolCard S.A. (www.polcard.pl), jako najwikszego krajowego publicznego  operatora transakcji kartowych, jest autoryzowanie online takich transakcji, poprzez przekierowanie transakcji autoryzacji przez sklep do serwera autoryzacji tej firmy. Analiza preferencji u|ytkowników dokonujcych zakupów online wykazuje jeszcze przewa|ajc w[ród polskich internautów strategi realizowania pBatno[ci  za zaliczeniem pocztowym , jednak wystpuj pierwsze oznaki zwikszajcego zainteresowania pBatno[ciami kart pBatnicz. Zwizane jest to z du|ym naciskiem banków i organizowanymi promocjami zarówno przez Visa International (www.visa.com) jak i same banki na promocj i sprzeda| usBug bezgotówkowych. Czsto karta pBatnicza jest obecnie wydawana bez opBat do ka|dego zakBadanego rachunku konta osobistego a bankowe tabele opBat i prowizji tak konstruowane, aby niejako  administracyjnie motywowa klientów do korzystania z bezgotówkowych form pBatno[ci. MARKETING I REKLAMA Ogólna zasada funkcjonowania sklepu internetowego opiera si na kilku filarch. Z jednej strony jest to baza danych o towarach, katalogach, cennikach itp. informacjach, z drugiej s to dane gromadzone na podstawie informacji uzyskiwanych od klientów. Wszystko to wsparte jest analizami i statystykami ogldalno[ci i odwiedzin na firmowych stronach serwisu webowego. Mo|na analizowa liczb odwiedzin, specyfik i rodzaje poszukiwanych towarów i informacji o nich, adresy domen z których nastpuj wej[cia oraz charakterystyk czasow na przestrzeni dnia, tygodnia czy miesica lub roku. Podstaw s logi serwera jak i dane zapisywane w bazie SQL. Analizy te pozwalaj przewidywa okresy wzmo|onego zainteresowania konkretnymi produktami jak i umo|liwiaj na precyzowanie oferty kierowanej do potencjalnego klienta. To daje du|e pole dziaBania w porównaniu do 9 tradycyjnych metod sprzeda|owych, gdzie klient pozostaje anonimowy praktycznie a| do momentu zawarcia konkretnej transakcji. Wsparciem dla strategii marketingowych mo|e by dobrze zaplanowana akcja reklamowa na bazie banerów reklamowych prezentowanych na ró|nych stronach zarówno wBasnego serwisu jak i na zasadzie wymiany banerowej z innymi. Wej[cia poprzez kliknicie w baner mog by analizowane pod ktem charakterystyki Rysunek 3  Internetowa promocja towarów sklepu. wiekowej klienta. Wiadomo bowiem gdzie dany baner byB umieszczony, na jakim serwisie i jaki jest profil internautów odwiedzajcych dany serwis. Nikt przecie| nie bdzie reklamowa drogiego sprztu RTV na serwisach internetowych przeznaczonych dla nastolatków. W takim przypadku wBa[ciwszym bdzie zaprezentowanie sprztu przeno[nego typu walkman czy discman. CaBoksztaBt dziaBaD promujcych sklep internetowy musi by wsparty podstawami zarówno psychologicznymi, ekonomicznymi jak i informatycznymi, majcymi na celu osignicie zamierzonego celu i sukcesu. Prezentowane rozwizania umo|liwiaj rozbudow caBego serwisu o ró|norakie narzdzia wpierajce dziaB marketingu firmy w cenne informacje, na których zebranie tradycyjnymi metodami nale|aBoby 10 wydatkowa zarówno du|e [rodki finansowe jak i po[wici sporo czasu na badania marketingowe. Oczywistym jest tak|e fakt, |e informacje zebrane tradycyjnymi metodami przekBadaj si tak|e na sam sklep internetowy i prezentowan ofert. W obecnych czasach wBa[ciwym wydaje si model dziaBalno[ci dodatkowej i uzupeBniajcej  tradycyjn ekonomi handlu podczas prowadzenia tego typu serwisu internetowego. W przypadku maBych i [rednich przedsibiorstw taki model mo|e prowadzi do poszerzenia kontaktu z potencjalnymi klientami, wyrobienia sobie dobrej marki i pozytywnej opinii w[ród klientów jak i zwikszenia sprzeda|y, udziaBów w rynku czy te| zadowolenia klientów co mo|e mie przeBo|enie na wymierne odnoszone korzy[ci. ZASADA DZIAAANIA Zasada dziaBania sklep internetowego zostaBa oparta o model wirtualnego [rodowiska pozyskiwania informacji o produktach i w przypadku ich atrakcyjno[ci dla klienta ewentualn sprzeda|. Zaobserwowane zachowania dowodz czsto, |e wizyty na stronach sBu| uzyskaniu konkretnych informacji o produkcie. Nie zawsze koDcz si one zrealizowaniem transakcji, jednak czsto klienci przychodzcy do  tradycyjnego sklepu firmowego powoBuj si na informacje uzyskane z serwisu webowego firmy. Zwiadczy to o tym, i| potencjalny klient chce by dobrze poinformowany zanim skontaktuje si ju| z rzeczywistym sprzedawc a nie jego wirtualnym odpowiednikiem. Jednak transakcje na dro|szy sprzt zawierane s w normalnym sklepie. Tutaj uwidacznia si cel dziaBania takiego sklepu jako bardziej informujcy i promujcy konkretny produkt ni| nastawiony [ci[le na sprzeda|. Chcc sprosta temu zadaniu zbudowany od podstaw sklep internetowy udostpnia klientom wygodn wyszukiwark towarów, przegldanie informacji o towarach, nowo[ciach i specjalnych ofertach czy promocjach. Czsto klienci maj ju| wyrobione zdanie o konkretnych producentach i staraj si dokonywa zakupów sprztu tylko konkretnie wybranej serii, modelu czy producenta. W tym celu przegldarka sklepu zostaBa wzbogacona w mo|liwo[ przegldania tematycznego jak i w oparciu o konkretnego producenta. Chcc sprosta tym zadaniom, wymagana byBa rozbudowa moduBu aktualizowania i wprowadzania informacji dodatkowych o towarach. Oprogramowanie finansowo ksigowe firmy nie byBo przeznaczone do tego celu i nie udostpniaBo wymaganych narzdzi. Dane zgromadzone i przetwarzane w bie|cej dziaBalno[ci firmy doskonale nadawaBy si do wykorzystania jako wsad informacyjny o posiadanych towarach, producentach i cenach. Tak|e informacje o odbiorcach oraz dostawcach pozwalaj na uzupeBnienie sklepu o moduB kontaktów 11 ze staBymi partnerami handlowymi i rozszerzenie dziaBalno[ci modelu B2C (business-to- consumer) tak|e o model B2B (business-to-business). Jednocze[nie wykorzystanie posiadanych danych znaczco uBatwia funkcjonowanie sklepu, gdy| s one automatycznie Badowane do bazy danych sklepu i prezentowane w serwisie webowym firmy bez konieczno[ci udziaBu pracowników. Nie jest tu wymagana specjalistyczna wiedza na temat konstruowania zaawansowanych systemów webowych, gdy| sposób w jaki zostaBo to zrealizowane jest uniwersalny i Batwo dostosowywany praktycznie do ka|dej aplikacji finansowo ksigowej obsBugujcej podstawow dziaBalno[ firmy. Zwrotnie informacje ze sklepu internetowego mog by w Batwy sposób Badowane do moduBu zamówieD lub rezerwacji w firmie, tym samym udostpniajc niezbdne informacje do bie|cej dziaBalno[ci firmy. Chcc zapewni wymagane bezpieczeDstwo operacji zdecydowano si na model wsadowego Badowania danych do sklepu oraz jego fizyczne umiejscowienie na odrbnym serwerze. LAN-serwer lokalny Baduje dane do serwera Internetowego, gdzie s one dalej odpowiednio obrabiane i przetwarzane a nastpnie prezentowane w tam zlokalizowanym serwisie internetowym firmy. Taki logiczny podziaB zadaD pozwoliB tak|e na oddzielenie i rozBo|enie obci|eD pomidzy obydwa serwery uniezale|niajc wewntrzn prac firmy od obci|enia generowanego przez internautów a tak|e na podniesienie bezpieczeDstwa w przypadku ataków na serwer internetowy. Konieczno[ zapewnienia cigBej i bezawaryjnej pracy wewntrznego serwera firmy byBa tutaj zadaniem priorytetowym. MODEL LOGICZNY I FUNKCJONALNY Opierajc si na zaBo|eniach wstpnych, stworzony zostaB model dziaBania sklepu internetowego jak i caBoksztaBtu  obecno[ci firmy w Internecie. Roboczo na wewntrzne potrzeby caBo[ oprogramowania obsBugujcego serwis internetowy firmy otrzymaBa nazw  eMarket . DziaBanie caBego systemu sprowadza si do przetwarzania ró|nego rodzaju danych i komunikacji sieciowej co schematycznie obrazuje Rysunek 4. ZaBo|enia pocztkowe dotyczce caBo[ci systemu doprowadziBy do jego logicznej budowy w sensie topologii sieciowej oraz przepBywu danych. Zasoby informacyjne firmy chronione s przed nieuprawnionym dostpem poprzez system uprawnieD zarówno do systemów finansowo ksigowych oraz na ni|szym poziomie dostpu do plików, katalogów i udostpnionych drukarek sieciowych. Korzystanie z zasobów Internetu tak|e wymaga odpowiednich uprawnieD. Ostatnia plaga wirusów pocztowych wymusiBa rezygnacj z maBo bezpiecznych programów pocztowych typu Microsoft Outlook oraz uruchomienie systemu pocztowego 12 w oparciu o webserwer i przegldarki na bazie oprogramowania TWIG, które zostaBo zmodyfikowane i odpowiednio dostosowane do potrzeb firmy. SpowodowaBo to drastyczne zakoDczenie problemów z zawirusowanymi zaBcznikami aktywujcymi si automatycznie na skutek ró|nego rodzaju bBdów w oprogramowaniu pocztowym firmy Microsoft. Wikszo[ systemów, dziaBajcych na serwerach firmy korzysta i wspóBpracuje z baz danych Przetwarzanie danych Zasoby sprztowe systemów Zbiory danych i dokumentów Rysunek 4  Schemat przetwarzania danych. PostgreSQL. Baza ta zostaBa wybrana do zastosowaD wymagajcych du|ych obci|eD jako jedyna obsBugujca standardy SQL takie jak: zaawansowane transakcje i zBczenia tabel, sekwencje, triggery, wbudowany jzyk konstruowania funkcji i procedur uruchamianych po stronie samej bazy danych i wiele innych nowoczesnych metod. Z baz wspóBpracuje webserwer Apache, na którym wykonuj si skrypty PHP generujce dynamicznie strony korzystajc ze zgromadzonych danych. Na serwerze wewntrznym firmy cyklicznie uruchamiaj si procesy pobierajce dane z baz systemu finansowo ksigowego. Dane s wstpnie konwertowane i przygotowywane do zaBadowania do bazy PostgreSQL. Wykonywana jest konwersja strony kodowej ze standardu cp852 na iso-8859-2 a gotowe do zaBadunku zbiory s przesyBane na serwer internetowy firmy. Wicej informacji na temat standardów kodowania polskich znaków mo|na znalez na Polskiej Stronie Ogonkowej (www.agh.edu.pl/ogonki). Tu nastpuje zaBadunek poszczególnych zbiorów do tabel w bazie danych. Wykonywane jest indeksowanie poszczególnych pól i w tym momencie koDczy si faza dostarczenia danych dla potrzeb sklepu. Schematycznie caBo[ tych procesów przedstawia Rysunek 5. Taka logiczna organizacja przepBywu danych jest jakby naturalna dla topologicznej organizacji sieci firmy jak i specyfiki dziaBania samego oprogramowania finansowo 13 ksigowego. Rozdzielenie funkcji wstepnego przygotowania danych od ich prezentowania pozwoliBo na zachowanie bezpieczeDstwa zasobów zgromadzonych na wewntrzym Pliki DBF systemu F/K Konwersja danych ZaBadowanie do bazy SQL Wewntrzny serwer firmy Internetowy serwer firmy Rysunek 5  Schemat procesu obiegu informacji. serwerze firmy poprzez ich fizyczne oddzielenie od warstwy aplikacji internetowych. Dalsza ich prezentacja obci|a serwer internetowy i nie zakBóca dziaBania sieci wewntrznej. Nawet w przypadku ewentualnej awarii czy ingerencji w zasoby serwera internetowego, maszyna  produkcyjna kontynuuje normalne dziaBanie bez wpBywu na bie|c prac firmy. 14 RozdziaB III  PRZYGOT OWANIE DANYCH KONWERSJA DANYCH Aplikacja finansowo ksigowa firmy napisana w Clipperze 5.3 przechowuje dane w postaci plików DBF. Struktura katalogów samej aplikacji zorganizowana jest w postaci katalogu systemu podstawowego oraz podkatalogów poszczególnych magazynów. Na podstawie analizy przechowywanych w poszczególnych plikach danych okre[lono |e wstpnie na potrzeby sklepu internetowego potrzebnych bdzie kilka tabel z systemu podstawowego oraz ze wszystkich poszczególnych magazynów. Rysunek 6 przedstawia fizyczn organizacj aplikacji na dysku sieciowym widzian od strony u|ytkowników sieci Windows a z drugiej strony od wewntrz serwera. Z poziomu u|ytkownika widziana jest struktura katalogów poczwszy od wntrza katalogu  sklep bowiem tak Rysunek 6 - Katalogi. udostpniony zasób Samby jest mapowany jako dysk logiczny. PoBo|enie caBo[ci aplikacji magazynowej na dyskach serwera umo|liwiBo dostp do tych danych pod ktem ich konwersji dla sklepu internetowego, bez zbdnego obci|ania sieci wewntrznej transferami a jedynie obróbk samych danych na poziomie serwera. W celu zapewnienia integralno[ci danych konwersja wykonuje si automatycznie w godzinach nocnych, tak aby to nie kolidowaBo z dziaBalno[ci firmy a jednocze[nie zapewniaBo aktualno[ danych. Charakter dziaBania aplikacji magazynowej wymusiB takie przystosowanie moduBu konwersji do struktury katalogów, aby dodanie kolejnych magazynów automatycznie zapewniaBo pobieranie danych tak|e z nich. W celu konwersji z formatu DBF do formatu tekstowego rozpatrywano dwa warianty. Pierwszy opieraB si na konwersji skryptem napisanym w jzyku Perl natomiast drugi zakBadaB wykorzystanie gotowego i wielokrotnie szybszego programu w jzyku C którego autorem jest Brad Eacker a kod byB opublikowany w 1994r w grupach USENET. Ostatecznie przewa|yBa szybko[ konwersji nad elastyczno[ci rozwizania w Perlu. Chcc jednak zachowa mo|liwo[ dostosowywania  wyciganych danych z tabel DBF, wyj[ciowe pliki po kompletnej konwersji DBF na TXT obrabiane s ju| skryptem shellowym napisanym z wykorzystaniem natywnych unixowi narzdzi takich jak awk czy tr. Poni|szy listing prezentuje ten skrypt opatrzony komentarzami wyja[niajcymi wykonywane dziaBania: 15 #!/bin/sh echo Subject: Konwersja baz eMarket echo echo Przygotowanie baz z MGZ do zasilenia bazy SQL eMarket.... # maska tworzenia plików z prawami odczyt/zapis dla wlasciciela i odczyt dla grupy umask 027 # parametry poczatkowe, sciezki oraz zmienne: KAT_MGZ='/work/sklep/MGZ2' KAT_TMP='/bofh/bazy/emarket/tmp' # sciezka do programu AnsiC konwersji dbf2lst DBFLST='/bofh/bazy/emarket/bin/dbflst' #echo Kasowanie starych zbiorow po poprzedniej konwersji rm -f /bofh/bazy/emarket/tmp/*.LST rm -f /bofh/bazy/emarket/tmp/*.IN echo -n Start wstepnej konwersji zbiorkow zasilajacych glownych $DBFLST $KAT_MGZ/CENNIK.DBF >$KAT_TMP/CENNIK.LST && echo -n . $DBFLST $KAT_MGZ/CENY_DEW.DBF >$KAT_TMP/CENY_DEW.LST && echo -n . $DBFLST $KAT_MGZ/ODBIORCY.DBF >$KAT_TMP/ODBIORCY.LST && echo -n . $DBFLST $KAT_MGZ/DOSTAWCY.DBF >$KAT_TMP/DOSTAWCY.LST && echo . echo -n Start konwersji zbiorkow stanow magazynowych if [ -f $KAT_TMP/MAGAZYN.LST ] ; then rm $KAT_TMP/MAGAZYN.LST fi # wykonujemy w petli przebieg po wszystkich katalogach magazynow for MAGAZYN in `ls -d $KAT_MGZ/MAG_??` ; do $DBFLST $MAGAZYN/MAGAZYN.DBF >>$KAT_TMP/MAGAZYN.LST && echo -n . done echo -n Wycinamy wymagane pola z rekordow # i jak poszlo dobrze to kasujemy niepotrzebne *.LST # konwersja pliku nazw towarow cat $KAT_TMP/CENNIK.LST | awk -F\| 'ORS=""{} {printf "%i", $2} {gsub(" ", "", $3)} {print "|"toupper($3)} {gsub(" ", "", $6)} {print "|"toupper($6)"|"} {printf "%i", $7} {print "|"} {printf "%G", $15} {print "\n"}' >$KAT_TMP/CENNIK.IN && \ rm $KAT_TMP/CENNIK.LST && echo -n . # konwersja pliku cen towarow cat $KAT_TMP/CENY_DEW.LST | awk -F\| 'ORS=""{} {printf "%i",$2}{print "|"} {printf "%G",$6}{print "|"} {print $7"\n"}' >$KAT_TMP/CENY_DEW.IN && \ rm $KAT_TMP/CENY_DEW.LST && echo -n . # konwersja pliku danych o dostawcach cat $KAT_TMP/DOSTAWCY.LST | awk -F\| 'ORS=""{} {printf "%i",$2}{print "|"} {gsub(" ", "", $5)}{print toupper($5)"|"} {gsub(" ", "", $6)}{print toupper($6)"|"} {gsub(" ", "", $7)}{print toupper($7)"|"} {gsub(" ", "", $8)}{print toupper($8)"|"} {gsub(" ", "", $9)}{print toupper($9)"|"} {gsub(" ", "", $10)}{print toupper($10)"|"} {gsub(" ", "", $11)}{print toupper($11)"|"} {gsub(" ", "", $12)}{print toupper($12)"|"} {gsub(" ", "", $14)}{print $14"\n"}' >$KAT_TMP/DOSTAWCY.IN && \ rm $KAT_TMP/DOSTAWCY.LST && echo -n . # konwersja pliku danych o odbiorcach cat $KAT_TMP/ODBIORCY.LST | awk -F\| 'ORS=""{} {printf "%i",$2}{print "|"} {gsub(" ", "", $5)}{print toupper($5)"|"} {gsub(" ", "", $6)}{print toupper($6)"|"} {gsub(" ", "", $7)}{print toupper($7)"|"} {gsub(" ", "", $8)}{print toupper($8)"|"} {gsub(" ", "", $9)}{print toupper($9)"|"} 16 {gsub(" ", "", $14)}{print $14"\n"}' >$KAT_TMP/ODBIORCY.IN && \ rm $KAT_TMP/ODBIORCY.LST && echo -n . # konwersja pliku cen towarow cat $KAT_TMP/MAGAZYN.LST | awk -F\| 'ORS=""{} {printf "%i",$2}{print "|"} {gsub(" ", "", $6)}{print $6"|"} {printf "%G",$14}{print "|"} {printf "%G",$18}{print "\n"}' >$KAT_TMP/MAGAZYN.IN && \ rm $KAT_TMP/MAGAZYN.LST && echo -n . # ustalamy prawa do plikow po konwersji chmod u+rw-x,g+rw-x,o-rwx $KAT_TMP/CENNIK.IN chmod u+rw-x,g+rw-x,o-rwx $KAT_TMP/CENY_DEW.IN chmod u+rw-x,g+rw-x,o-rwx $KAT_TMP/MAGAZYN.IN chmod u+rw-x,g+rw-x,o-rwx $KAT_TMP/DOSTAWCY.IN chmod u+rw-x,g+rw-x,o-rwx $KAT_TMP/ODBIORCY.IN echo echo Zbiorki po konwersji zajmuja\: echo echo "KB: Nazwa:" du -k $KAT_TMP/*.IN echo echo Upload plikow dla bazy emarket cd /bofh/bazy/emarket/tmp echo Zaczynamy transfer... # wywolujemy skrypt ftp transfer na podstawie listy polecen ftp -p < /bofh/bazy/emarket/tmp/transfer echo Zaladowane. ARCHIWIZACJA I PRZESYAANIE DANYCH Skrypty s wywoBywane cyklicznie co noc wykonujc wstpne przygotowanie danych oraz ich przesBanie przy pomocy ftp na serwer internetowy, gdzie nastpuje dalsza faza obróbki danych i ich Badowanie do PostgreSQL. Oprócz skasowania starych zbiorów i wkopiowania na ich miejsce nowych wykonywana jest tak|e archiwizacja. Przy pomocy poni|szej listy poleceD skryptu  transfer dane przekazywane s protokoBem ftp na serwer internetowy: open inet-serwer bin cd /home/bazy/emarket/tmp del /home/bazy/emarket/tmp/CENNIK.IN del /home/bazy/emarket/tmp/CENY_DEW.IN del /home/bazy/emarket/tmp/DOSTAWCY.IN del /home/bazy/emarket/tmp/MAGAZYN.IN del /home/bazy/emarket/tmp/ODBIORCY.IN put /bofh/bazy/emarket/tmp/CENNIK.IN /home/bazy/emarket/tmp/CENNIK.IN put /bofh/bazy/emarket/tmp/CENY_DEW.IN /home/bazy/emarket/tmp/CENY_DEW.IN put /bofh/bazy/emarket/tmp/DOSTAWCY.IN /home/bazy/emarket/tmp/DOSTAWCY.IN put /bofh/bazy/emarket/tmp/MAGAZYN.IN /home/bazy/emarket/tmp/MAGAZYN.IN put /bofh/bazy/emarket/tmp/ODBIORCY.IN /home/bazy/emarket/tmp/ODBIORCY.IN ls bye Wyniki wykonania caBej operacji s  wy[wietlane na standardowe wyj[cie (stdout) a nastpnie wysyBane poczt email do administratora. Pozwala to na kontrol poprawno[ci dziaBania caBej operacji, gdy| odbywa si ona bezobsBugowo. Cykliczno[ wykonania tych dziaBaD realizowana jest dwoma wpisami w pliku konfiguracyjnym crontab. Zapewniaj one 17 oprócz konwersji i przekazania danych na serwer internetowy tak|e archiwizacj caBo[ci systemów finansowo ksigowych firmy i umieszczenie ich w katalogu udostpnionym obsBudze w celu przegrania na wymienne no[niki: # zrob archiwizacje codziennie po dniu roboczym o 3:00 w nocy #minute hour mday month wday what 0 3 * * 1,2,3,4,5,6 /bofh/bin/archiwizacja 2>&1 | /usr/sbin/sendmail operator # zrob konwersje i przekazanie danych o 20:00 0 20 * * 1,2,3,4,5,6 /bofh/bazy/emarket/konwersja 2>&1 | /usr/sbin/sendmail operator Archiwizacja wykonywana jest poni|szym skryptem przygotowujcym paczk do przekopiowania na no[niki wymienne: #!/bin/sh # odpalane z crona codziennie w nocy echo "Subject: Status archiwizacji" echo echo Archiwizacja... dladaty=`date "+20%y%m%d"` echo $dladaty # przygotowanie ksiegowosci echo KSH cd /work/ksieg tar -czf /home/archiwa/ksz$dladaty.tgz ./KSH2/* echo OK. # przygotowanie magazynow echo MGZ cd /work/sklep tar -czf /home/archiwa/mzz$dladaty.tgz ./MGZ2/* echo MGZ OK. echo Archiwa zajmuja obecnie\: echo KBytes Nazwa pliku du -k /home/archiwa/ echo Zajetosc dyskow\: df -ki echo KONIEC STRUKTURA KONWERTOWANYCH PLIKÓW W celu wykonania operacji konwersji danych na potrzeby sklepu internetowego poddano analizie zawarto[ poszczególnych plików DBF systemów magazynowych. Wyodrbniono przydatne tabele i na ich podstawie okre[lone pola niezbdne dla dziaBania sklepu. Poni|szy fragment ka|dego z plików przekazywanych do zaimportowania do bazy SQL obrazuje jakie dane s wykorzystane z systemów finansowo ksigowych firmy: # Fragment pliku CENNIK.IN # struktura pliku: # ind | nazwa towaru cp852 | ozn. producenta | stan | VAT 167636|UCHWYT ZEZ+OBEJMA FI 40|UCHWYT ZEZ+OBEJMA |16|22 982027|YAMAHA RX-V 520 AMPLITUNER AV TI.|YAMAHA RX-V520 TI.|17|22 300405|KAMERA PANASONIC NV-DS27 EG|PANASONIC NV-DS27 |57|22 300052|TELEWIZOR PANASONIC TX 29 AS10P|PANASONIC TX 29 AS|78|22 300051|MAGNETOWID PANASONIC NV-FJ 762 EE|PANASONIC NV-FJ762|78|22 300050|MAGNETOWID PANASONIC NV-FJ 622 EE|PANASONIC NV-FJ622|78|22 51102|PANASONIC RT-60MC MIKROKASETA|PANASONIC RT-60MC |5|22 18 # Fragment pliku CENY_DEW.IN # struktura pliku: # ind | cena netto | symbol waluty 330055|1146.72|ZLP 110003|548.36|ZLP 140021|1638.52|ZLP 167636|14.75|ZLP 500018|10.66|ZLP 51102|6.56|ZLP # Fragment pliku DOSTAWCY.IN oraz ODBIORCY.IN # struktura pliku: # ind | nazwa krotka | nazwa dluga | adres1 ... adres6 | nip 1|WIZJA TV |WIZJA TV|UL.PAWINSKIEGO 5A/BLOK D|02-106 WARSZAWA |||||113-15-59-441 28|PHILIPS AGD|PHILIPS POLSKA SP Z.O.O.|02-222 WARSZAWA |AL. JEROZOLIMSKIE 195 B |||||526-021-09-55 43|THOMSON|THOMSON CONSUMER ELECTRONIC POLAND|UL OKULICKIEGO 7/9|05 - 500 PIASECZNO|||||123-00-05-409 # Fragment pliku MAGAZYN.IN # struktura pliku: # ind | data | stan dyspozycyjny | stan ksiegowy 240029|20010528|2|2 270018|20010703|28|28 270015|20010628|19|19 KONWERSJA STRONY KODOWEJ Dane rejestrowane w systemie finansowo ksigowym firmy s danymi  brudnymi pod wzgldem historycznie stosowanych kodowaD, poczynajc od standardu polskich znaków Mazovia poprzez Latin i inne a koDczc na cp852. Koniecznym byBo dokonanie konwersji tych danych do jednolitego formatu jednak ró|norodno[ stacji roboczych oraz ich wykorzystanie do ró|nych celów wykluczaBa wykonanie tego na gBównych danych firmy oraz na zastosowanie jednakowego kodowania na wszystkich koDcówkach. Konwersj polskich znaków zostaB  obarczony serwer internetowy, gdzie wykonywana jest ona przed wczytaniem danych do bazy SQL. Skrypt konwertujcy jest uniwersalnym narzdziem napisanym przez tragicznie zmarBego w 1996r dziennikarza Krakowskiej Gazety Wyborczej Andrzeja Górbiela (http://studweb.euv-frankfurt-o.de/twardoch/f/pl/comp/gorbiel/). Poni|szy listing przedstawia tego skryptu: #!/bin/sh # # plconv - filtr do konwersji polskich znakow diakrytycznych # # (c) 1994 Andrzej Gorbiel <A.Gorbiel@Ga-Wyb.Krakow.PL> # # a, c' e, l\ n' o' s' z' z. A, C' E, L\ N' O' S' Z' Z~ MAZ="\206\215\221\222\244\242\236\246\247\217\225\220\234\245\243\230\240\241" LAT="\245\206\251\210\344\242\230\253\276\244\217\250\235\343\340\227\215\275" WIN="\271\346\352\263\361\363\234\237\277\245\306\312\243\321\323\214\217\257" ISO="\261\346\352\263\361\363\266\274\277\241\306\312\243\321\323\246\254\257" TXT="acelnoszzACELNOSZZ" MAZTAB="\206\215\221\222\244\242\236\246\247\217\225\220\234\245\243\230\240\241\277\263\ 300\301\302\303\304\305\331\332\264" ISOTAB="\261\346\352\263\361\363\266\274\277\241\306\312\243\321\323\246\254\257\53\174\53\ 53\55\174\55\53\53\53\174" ShowHelp () { echo "Uzycie: $0 standard_we standard_wy [ < plik wejsciowy > plik wyjsciowy]" 19 echo " dopuszczalne standardy:" echo " MAZ - Mazovia" echo " LAT - Latin-2 (MS-DOS CP 852)" echo " WIN - Windows ANSI (CP 1250)" echo " ISO - ISO Latin-2 (CP 8859/2)" echo " TXT - ASCII (7-bit)" exit } SetStd () { case $1 in MAZ) std=$MAZ;; LAT) std=$LAT;; WIN) std=$WIN;; ISO) std=$ISO;; TXT) std=$TXT;; MAZTAB) std=$MAZTAB;; ISOTAB) std=$ISOTAB;; *) ShowHelp; exit;; esac } if [ $# != 2 ]; then ShowHelp; fi SetStd $1 std1=$std SetStd $2 tr "$std1" "$std" ZAAADOWANIE DANYCH DO BAZY POSTGRESQL Pliki w formacie tekstowym wczytywane s po ich otrzymaniu z serwera wewntrznego firmy. W tym momencie wykonywana jest konwersja kodowania na stron kodow iso88592 (obowizujcy standard kodowania polskich znaków na stronach www tzw. iso-latin2). Proces ten wywoBywany jest równie| jako cykliczne zadanie w crontab ie nastpujcym wpisem w plik konfiguracyjny: # zasilenie dla emarket codziennie o 20:30 30 20 * * 1,2,3,4,5,6,7 /home/bazy/emarket/zaladunek 2>&1 | /var/qmail/bin/qmail-inject Skrypt  zaBadunek zbudowany jest podobnie jak skrypt konwersji danych na maszynie wewntrznej i wykonywane dziaBania wy[wietla na standardowe wyj[cie (stdout) co jest poprzez sposób wywoBania w corntab wysyBane jako raport do operatora. Jedyn ró|nic w wywoBaniu skryptu jest to, i| dziaBa on na tej samej maszynie na której zainstalowany zostaB system pocztowy Qmail i dlatego mo|na byBo wykorzysta jeden z pocztowych programów usBugowych do dostarczenia poczty bezpo[rednio do adresata. DziaBania takie maja na celu informowanie obsBugi lub administratorów o wszelkich wystpujcych problemach a tak|e o powodzeniu ka|dego z etapów dziaBania sklepu internetowego. Poni|szy skrypt prezentuje dziaBania wykonywane w czasie importowania danych do bazy PostgreSQL: 20 #!/bin/sh echo "From: zaladunek <operator@localhost>" echo "To: operator" echo "Subject: Zaladowanie danych do bazy eMarket." echo # zdefiniowanie polozenia katalogow roboczych KAT_TMP='/home/bazy/emarket/tmp' PATH=$PATH:/usr/local/pgsql/bin ; export PATH BINARIA='/home/bazy/emarket' cd $BINARIA #echo Sprawdzenie czy sa sciagniete pliki zasilajace... pliki=`ls $KAT_TMP/*.IN | wc -l` if [ $pliki != 5 ] ; then echo Brak pliku zasilajacego. echo Sa tylko te... echo ls -l $KAT_TMP/*.IN echo echo STOP. exit 1 fi echo Jest wszystkie $pliki plikow... echo ls -l $KAT_TMP/*.IN echo # konwersja strony kodowej echo Konwersja pl znakow na ISO ($BINARIA/bin/plznaki LAT ISO < $KAT_TMP/CENNIK.IN > $KAT_TMP/CENNIK.PL) && \ mv $KAT_TMP/CENNIK.PL $KAT_TMP/CENNIK.IN && chmod a+r $KAT_TMP/CENNIK.IN # data i czas rozpoczecia zaladunku echo Zaczynamy o `date` # ustawienie znacznika zaladunku do bazy # skrypty php sklepu blokuja dostep do bazy w przypadku # wykrycia obecnosci tego pliku na czas zaladunku danych echo Tymczasowe zablokowanie dostepu do bazy... touch $KAT_TMP/emarket.tmp # 90-usuntabele $BINARIA/90-usuntabele # 20-zaloztabele $BINARIA/20-zaloztabele # 30-zaladujtabele $BINARIA/30-zaladujtabele # 40-zalozindeksy $BINARIA/40-zalozindeksy # 40-zaladujkatalog $BINARIA/40-zaladujkatalog # 45-optymalizuj $BINARIA/45-optymalizuj # 50-statystyka $BINARIA/50-statystyka echo Konczymy o `date` echo Odblokowanie dostepu do bazy... rm $KAT_TMP/emarket.tmp echo echo Koniec ladowania. 21 Etapy zaBadunku danych do bazy zostaBy podzielone na osobne funkcjonalne cz[ci, co uBatwia ewentualne diagnozowanie nieprawidBowo[ci oraz dalszy rozwój tego oprogramowania. Ka|dy ze skryptów wykonujcych dziaBania na bazie PostgreSQL otrzymaB nazw zbudowan z pocztkowych dwóch cyfr oznaczajcych jego logiczn kolejno[ w wykonaniu, analogicznie jak to ma miejsce w przypadku skryptów startowych w systemach UNIX typu SysV 4.2 gdzie takie uporzdkowanie wystpuje oraz w systemach BSD w skryptach administracyjnych (daily, weekly, monthly itp.). Omówienie poszczególnych skryptów SQL zostaBo umieszczone w kolejnych rozdziaBach traktujcych o samej strukturze bazy danych. Wspomnie nale|y, i| aby wykorzystywa baz danych PostgreSQL, administrator bazy zaBo|yB odpowiednich u|ytkowników bazy z hasBami dostpu i uprawnieniami pozwalajcymi na czynno[ci administracyjne. GBównym plikiem konfiguracyjnym PostgreSQL regulujcym dostp okre[lonych u|ytkowników z okre[lonych hostów jest plik konfiguracyjny  pg_hba.conf . DokBadnie omawia to dokumentacja PostgreSQL (www.postgresql.org/idocs/index.php?client-authentication.html). Sposób autoryzacji (czy system wymaga hasBa czy te| nie) jest definiowany w tym pliku. Na jego koDcu przy domy[lnej konfiguracji znajduj si wpisy: local all trust host all 127.0.0.1 255.255.255.255 trust Oznaczaj one, |e dla poBczeD lokalnych (local) - czyli takich, gdzie Bczymy si nie korzystajc z socket ów tcpip i dla dowolnej bazy (all), system ma przyj reguB nie pytania o hasBo (trust) natomiast dla poBczeD zdalnych, ale tylko z maszyny o adresie 127.0.0.1 (czyli z tego samego hosta, ale przez sockety tcpip), bdzie obowizywa ta sama reguBa. Aby to zmieni nale|y zastpi ostatnie sBowo (trust) na "password" lub "crypt" (ró|ni si one metod przesyBania hasBa). PrzykBadowo zapis: host all 192.168.1.10 255.255.255.0 password Oznacza, |e osoby Bczce si z serwera o adresie 192.168.1.10 oraz z caBej klasy C (czyli w rzeczywisto[ci adres ip mo|e by typu 192.168.1.*) musz poda hasBo aby dosta si do dowolnej bazy. Chcc wymusi aby wzorcowy szablon bazy PostgreSQL byB tak|e chroniony mo|na dokona zapisu: host template1 192.168.1.10 255.255.255.0 password co oznacza, |e te same osoby bd mogBy teraz dosta si tylko do bazy template1 i bd musiaBy poda hasBo. Metod autoryzacji u|ytkowników jest wiele, midzy innymi tak|e na podstawie protokoBu ident. Przy pisaniu reguB dostpu nale|y pamita o kolejno[ci. Zawsze u|yta zostanie ta reguBa która jest pierwsza w pliku i pasuje do sytuacji (reguBki przeszukiwane s w kolejno[ci od pocztku do koDca pliku a| do znalezienia pierwszej 22 pasujcej i na tym si koDczy przeszukiwanie). Poni|szy zapis byBby bBdny, pozbawiony sensu poprzez swoj bBdn hierarchi: local all trust host all 127.0.0.1 255.255.255.255 trust local template1 password host template1 127.0.0.1 255.255.255.255 password Poprawnej konfiguracj tej access listy przedstawia przykBadowy zapis: local template1 password host template1 127.0.0.1 255.255.255.255 password local all trust host all 127.0.0.1 255.255.255.255 trust W przypadku konfiguracji rzeczywistej sklepu wpisy dopuszczajce ustalaj dostp do bazy sklepu nazwanej jako  emarket tylko i wyBcznie z serwera na którym dziaBa sklep oraz dla okre[lonego u|ytkownika z hasBem. Zapewnia to ju| zwikszony poziom bezpieczeDstwa poprzez odrzucenie przez silnik bazy danych poBczeD pochodzcych zarówno od u|ytkowników lokalnych serwera jak i zdalne próby nawizania poBczeD (cho to tak|e zabezpiecza zastosowany firewall). PostgreSQL zapewnia ponadto zabezpieczenia dostpu do tabel zgodnie ze standardem SQL92 (www.postgresql.org/idocs/index.php?sql.html). Na zasadzie przywilejów na konkretne dziaBania i operacje na krotkach, tabelach, indeksach, procedurach czy funkcjach. Mo|na tu bardzo precyzyjnie okre[la co, kto jak i kiedy mo|e uczyni ze zgromadzonymi danymi, czy mo|e tylko czyta nasze dane czy te| usuwa, poprawia, dodawa nowe itp. 23 RozdziaB IV  STRUKTU RA I ORGANIZACJA BAZY EMARKET SKRYPTY ADMINISTRACYJNE Chcc zautomatyzowa czynno[ci tworzenia i uruchomienia samej bazy, a tak|e jej zasilania danymi na potrzeby sklepu napisano skrypty powBoki wywoBujce okre[lone dziaBania w bazie danych. Proces zasilania danymi sterowany jest gBównym skryptem wywoBujcym poszczególne pod-skrypty odpowiedzialne za pewne fragmenty dziaBania poszczególnych zadaD zasilania w dane caBej bazy. Niektóre z nich uruchamiane s jednorazowo w momencie tworzenia bazy lub te| jej kasowania. Inne pozwalaj na wykonanie pewnych analiz (na obecnym etapie rozwoju aplikacji jedynie w minimalnym zakresie). Wikszo[ danych Badowana jest bez natychmiastowego indeksowania co znaczco przy[piesza caB operacj. Dopiero po zaBadowaniu danych do tabel nastpuje zaindeksowanie wszystkich wymaganych pól w konkretnych tabelach. Na samym koDcu wykonywana jest  odkurzenie bazy pozwalajca PostgreSQL owi na empiryczn i statystyczn optymalizacj wyszukiwania danych. Poni|sze zestawienie prezentuje i omawia wywoBania wszystkich skryptów. #!/bin/sh # skrypt 20-zaloztabele # echo Zalozenie tabel bazy emarket SQL... # KAT_SQL='/home/bazy/emarket/sql' SQL='/usr/local/pgsql/bin/psql -d emarket -q -f' echo echo cennik... $SQL $KAT_SQL/create/create_table_cennik.sql echo cenydew... $SQL $KAT_SQL/create/create_table_cenydew.sql echo dostawcy... $SQL $KAT_SQL/create/create_table_dostawcy.sql echo magazyn... $SQL $KAT_SQL/create/create_table_magazyn.sql echo odbiorcy... $SQL $KAT_SQL/create/create_table_odbiorcy.sql #echo informacje... $SQL $KAT_SQL/create/create_table_informacje.sql echo echo Koniec. Powy|szy pod-skrypt  20-zaloztabele odpowiedzialny jest za pocztkowe zaBo|enie niezbdnych tabel w bazie SQL. WywoBuje ju| bezpo[rednio, napisane w dialekcie jzyka SQL92 polecenia zakBadajce poszczególne tabele z polami okre[lonego typu. 24 #!/bin/sh # skrypt 20-zaladujtabele # echo Zaladowanie danych do tabel bazy emarket SQL... # KAT_SQL='/home/bazy/emarket/sql' SQL='/usr/local/pgsql/bin/psql -d emarket -q -f' echo echo cennik... $SQL $KAT_SQL/load/load_table_cennik.sql echo cenydew... $SQL $KAT_SQL/load/load_table_cenydew.sql #echo dostawcy... #$SQL $KAT_SQL/load/load_table_dostawcy.sql #echo odbiorcy... #$SQL $KAT_SQL/load/load_table_odbiorcy.sql echo magazyn... $SQL $KAT_SQL/load/load_table_magazyn.sql echo echo Przy okazji skorygujemy bledne dane... # pewne dane w zasilajacych zbiorach sa zduplikowane lub nie maja # wypelnionych wymaganych pol (zaszlosc historyczna) poprawiamy to tutaj SQL='/usr/local/pgsql/bin/psql -d emarket -q -c' $SQL "UPDATE magazyn SET data='19940505' where data=' ';" #$SQL "DELETE FROM cenydew where indeks='984001' and cenat='1036.07';" SQL='/usr/local/pgsql/bin/psql -d emarket -q -f' echo uniqmagazyn... $SQL $KAT_SQL/load/load_table_uniqmagazyn.sql echo Koniec. Powy|szy pod-skrypt  20-zaladujtabele wywoBuje skrypty SQL92 wczytujce i korygujce dane bezpo[rednio do tabel w bazie. Niektóre dane (np. odbiorcy i dostawcy) nie s wczytywane na obecnym etapie rozwoju sklepu internetowego a| do momentu gdy aplikacja zostanie rozbudowana o moduBy wspóBpracy z partnerami handlowymi (B2B), realizacj wymiany partnerskiej, dynamicznie konstruowane cenniki w zale|no[ci od podpisanych umów na upusty globalne itp. #!/bin/sh # Skrypt 40-zaladujkatalog # echo Zaladowanie danych do tabel bazy emarket SQL... # KAT_SQL='/home/bazy/emarket/sql' SQL='/usr/local/pgsql/bin/psql -d emarket -q -f' echo echo ladujemy dane do tabeli katalog... $SQL $KAT_SQL/load/load_table_katalog.sql echo indeksujemy tabele katalog... $SQL $KAT_SQL/create/create_index_katalog.sql echo echo Koniec. 25 Powy|szy pod-skrypt generuje dane do dodatkowo tworzonej tabeli zawierajcej wyfiltrowane dane z tabeli zawierajcej dane ze wszystkich magazynów. W aplikacji finansowo ksigowej firmy, ka|dy magazyn zawiera towary wspóBistniejce w innych magazynach. Ka|dy z magazynów posiada ten sam indeks dla towaru, zgodny z innymi indeksami w pozostaBych magazynach. Ka|dy z nich ma swój wBasny stan magazynowy (dyspozycyjny i ksigowy) oraz cen. Istnieje tak|e globalna tabela cen dewizowych przechowujca wspóln cen dla wszystkich magazynów. Idea dziaBania aplikacji magazynowej w firmie jest taka, i| gdy istnieje dla danego towaru cena w centralnym cenniku to wBa[nie ona ma przewag nad cen lokaln w danym magazynie, dlatego tutaj wBa[nie zdecydowano si na zagregowanie tych danych w jeden wspólny rekord bdcy podstaw do dalszego dziaBania sklepu. #!/bin/sh # skrypt 40-zalozindeksy echo Zalozenie indeksow bazy emarket SQL... # KAT_SQL='/home/bazy/emarket/sql' SQL='/usr/local/pgsql/bin/psql -d emarket -q -f' echo echo cennik... $SQL $KAT_SQL/create/create_index_cennik.sql echo cenydew... $SQL $KAT_SQL/create/create_index_cenydew.sql #echo dostawcy... #$SQL $KAT_SQL/create/create_index_dostawcy.sql #echo magazyn... #$SQL $KAT_SQL/create/create_index_magazyn.sql #echo odbiorcy... #$SQL $KAT_SQL/create/create_index_odbiorcy.sql echo uniqmagazyn... $SQL $KAT_SQL/create/create_index_uniqmagazyn.sql echo informacje... $SQL $KAT_SQL/create/create_index_informacje.sql echo echo Koniec. Powy|szy pod-skrypt indeksuje wszystkie potrzebne pola w tabelach. Wykonywane jest to dopiero po wczytaniu caBo[ci danych gdy| w ten sposób uniknito przebudowywania indeksów przy wczytywaniu danych do tabel i uzyskano znaczny wzrost szybko[ci caBej operacji importu danych. Silnik bazy danych w takim przypadku nie wykonuje blokad przy dodawaniu rekordów a i same dane s fizycznie na dysku nie pofragmentowane, co miaBo by miejsce, gdyby równocze[nie trwaBo przeplatanie wczytania rekordu i zaktualizowanie indeksu. Co prawda le|cy u podstaw systemu plików mechanizm dba o takie 26 rozmieszczenie plików, aby ulegaBy jak najmniejszej fragmentacji, jednak odbywa si to kosztem zwikszonego zapotrzebowania na zasoby systemu. Pamitajmy |e PostgreSQL przechowuje wszystkie obiekty bazy w osobnych plikach. #!/bin/sh # skrypt 45-optymalizuj echo Optymalizacja bazy emarket SQL... # echo /usr/local/pgsql/bin/vacuumdb --analyze emarket echo echo Koniec. Powy|szy pod-skrypt uruchamia mechanizmy analizy i optymalizacji wbudowane w silnik bazy danych. W przypadku bazy, w której nie s kasowane tabele z danymi ten mechanizm wpBywa na  uczenie si rozkBadu danych i wykorzystywanie metod stochastycznych dla przyspieszenia dostpu do danych i powinien by uruchamiany okresowo. W przypadku bazy eMarket nie ma on a| tak znaczcego wpBywu, gdy| dane s stale  mBode . #!/bin/sh # skrypt 50-statystyka echo Statystyka tabel bazy emarket SQL... # KAT_SQL='/home/bazy/emarket/sql' SQL='/usr/local/pgsql/bin/psql -d emarket -q -c' echo echo Zaladowane rekordy w tabelach: echo cennik...... `$SQL "SELECT count(*) FROM cennik;"` echo ceny_dew.... `$SQL "SELECT count(*) FROM cenydew;"` echo dostawcy.... `$SQL "SELECT count(*) FROM dostawcy;"` echo uniqmagazyn. `$SQL "SELECT count(*) FROM uniqmagazyn;"` echo odbiorcy.... `$SQL "SELECT count(*) FROM odbiorcy;"` echo katalog..... `$SQL "SELECT count(*) FROM katalog;"` echo informacje.. `$SQL "SELECT count(*) FROM informacje;"` echo echo Koniec. Powy|szy pod-skrypt zlicza ilo[ci krotek w poszczególnych tabelach po zaBadowaniu danych oraz je prezentuje co zostaje doBczone przy wczytywaniu danych do raportu kontrolnego przesyBanego administratorom. #!/bin/sh # skrypt 80-usunindeksy echo Skasowanie indeksow bazy emarket SQL... # KAT_SQL='/home/bazy/emarket/sql' SQL='/usr/local/pgsql/bin/psql -d emarket -q -f' $SQL $KAT_SQL/delete/drop_all_index.sql echo echo Koniec. 27 #!/bin/sh # skrypt 90-usuntabele echo Skasowanie tabel bazy emarket SQL... # KAT_SQL='/home/bazy/emarket/sql' SQL='/usr/local/pgsql/bin/psql -d emarket -q -f' $SQL $KAT_SQL/delete/drop_all_table.sql echo echo Koniec. Powy|sze dwa pod-skrypty usuwaj wszystkie tabele i indeksy z bazy eMarket. Wykonywane s przed zaBadowaniem nowych danych do tabel. Operacja skasowania caBych tabel wraz z indeksami jest nieporównywalnie szybsza ni| kasowanie zawarto[ci tabel a ponadto fizycznie usuwane s niepotrzebne ju| pliki z dysku serwera. #!/bin/sh # 95-czysctmp echo Usuwanie plikow zasilenia bazy SQL eMarket.... # # parametry poczatkowe: KAT_TMP='/home/bazy/emarket/tmp' rm $KAT_TMP/CENNIK.IN rm $KAT_TMP/CENY_DEW.IN rm $KAT_TMP/ODBIORCY.IN rm $KAT_TMP/DOSTAWCY.IN rm $KAT_TMP/MAGAZYN.IN echo Zbiorki zasilajace usuniete! echo Koniec. Powy|szy pod-skrypt ma na celu fizyczne usunicie niepotrzebnych zbiorów zasilajcych. Jest uruchamiany w tylko specyficznych przypadkach, bowiem zbiory te s kasowane przy przesyBaniu danych z serwera wewntrznego firmy. #!/bin/sh # 99-struktura echo Struktura bazy emarket SQL... # echo "\d cennik" | /usr/local/pgsql/bin/psql -d emarket 2>&1 echo "\d cenydew" | /usr/local/pgsql/bin/psql -d emarket 2>&1 echo "\d uniqmagazyn" | /usr/local/pgsql/bin/psql -d emarket 2>&1 echo "\d dostawcy" | /usr/local/pgsql/bin/psql -d emarket 2>&1 echo "\d odbiorcy" | /usr/local/pgsql/bin/psql -d emarket 2>&1 echo "\d katalog" | /usr/local/pgsql/bin/psql -d emarket 2>&1 echo "\d informacje" | /usr/local/pgsql/bin/psql -d emarket 2>&1 echo Koniec. Powy|szy pod-skrypt ma za zadanie wy[wietlenie struktury bazy danych eMarket. SBu|y wyBcznie celom administracyjnym np. przy rozbudowywaniu i modyfikowaniu tabel, pól czy 28 indeksów. Wyniki jego wykonania posBu| do dalszej prezentacji struktur tabel bazy w dalszej cz[ci pracy. SKRYPTY SQL Procedury operujce bezpo[rednio w bazie danych zostaBy zapisane w postaci plików skryptowych SQL92 wywoBywanych  na |danie . Wykonuj one czynno[ci tworzenia, usuwania, indeksowania danych przez silnik bazy danych. Automatyzuj dziaBania codziennej obsBugi bazy. Podzielone zostaBy tematycznie na kilka kategorii takich jak:  create  tworzenie tabel czy indeksów,  delete  kasowanie danych, tabel oraz indeksów,  check  kontrola i sprawdzanie bazy,  load  importowanie danych do tabel,  analyse  ró|nego rodzaju analizy danych i zestawienia. KATEGORIA SKRYPTÓW  CREATE Do tej kategorii zaliczaj si skrypty tworzce tabele oraz indeksy: create_table_odbiorcy.sql create_index_odbiorcy.sql create_table_dostawcy.sql create_index_dostawcy.sql create_table_magazyn.sql create_index_magazyn.sql create_table_informacje.sql create_index_informacje.sql create_table_cenydew.sql create_index_cenydew.sql create_table_cennik.sql create_index_cennik.sql dla tabel generowanych dynamicznie na podstawie danych: create_index_uniqmagazyn.sql create_index_katalog.sql -- create_table_odbiorcy.sql -- -- utworzenie tabeli [odbiorcy] zawierajacej kody i nazwy odbiorcow -- CREATE TABLE odbiorcy ( kod int4 NOT NULL, nazwa varchar(16), nazwa1 varchar(41), nazwa2 varchar(41), nazwa3 varchar(41), nazwa4 varchar(41), nip char(13) ); -- COMMIT; -- create_index_odbiorcy.sql -- -- utworzenie wymaganych indeksow dla tabeli [odbiorcy] -- CREATE INDEX odbiorcy_kod_idx ON odbiorcy (kod); CREATE INDEX odbiorcy_nazwa_idx ON odbiorcy (nazwa); CREATE INDEX odbiorcy_nazwa1_idx ON odbiorcy (nazwa1); CREATE INDEX odbiorcy_nazwa2_idx ON odbiorcy (nazwa2); -- COMMIT; 29 -- create_table_dostawcy.sql -- -- utworzenie tabeli [dostawcy] zawierajacej kod, nazwy i rach. banku dostawcow -- CREATE TABLE dostawcy ( kod int4 NOT NULL, nazwa varchar(16), nazwa1 varchar(41), nazwa2 varchar(41), nazwa3 varchar(41), nazwa4 varchar(41), bank1 varchar(41), bank2 varchar(41), bank3 varchar(41), nip char(13) ); -- COMMIT; -- create_index_dostawcy.sql -- -- utworzenie wymaganych indeksow dla tabeli [dostawcy] -- CREATE UNIQUE INDEX dostawcy_kod_idx ON dostawcy (kod); CREATE INDEX dostawcy_nazwa_idx ON dostawcy (nazwa); CREATE INDEX dostawcy_nazwa1_idx ON dostawcy (nazwa1); CREATE INDEX dostawcy_nazwa2_idx ON dostawcy (nazwa2); CREATE INDEX dostawcy_nip_idx ON dostawcy (nip); -- COMMIT; -- create_table_magazyn.sql -- -- utworzenie tabeli [magazyn] zawierajacej indeksy, ceny i stany towarow -- CREATE TABLE magazyn ( indeks int4 not null, data char(8), stan decimal(9,2) DEFAULT '0.00', standp decimal(9,2) DEFAULT '0.00' ); -- COMMIT; -- create_index_magazyn.sql -- -- utworzenie wymaganych indeksow dla tabeli [magazyn] -- CREATE INDEX magazyn_indeks_idx ON magazyn (indeks); -- COMMIT; -- create_table_informacje.sql -- -- utworzenie tabeli [informacje] zawierajacej indeksy i info o towarach -- CREATE TABLE informacje ( indeks int4 NOT NULL, podtyp int4 NOT NULL DEFAULT '0', idpromocja int4 NOT NULL DEFAULT '0', pokaz char(1) DEFAULT 'N', skrot varchar(200) DEFAULT '', tytul varchar(80) DEFAULT '', opis varchar(4000) DEFAULT '', link1 varchar(80) DEFAULT '', link2 varchar(80) DEFAULT '', flagi varchar(80) DEFAULT '' ); -- COMMIT; 30 -- create_index_informacje.sql -- -- utworzenie wymaganych indeksow dla tabeli [informacje] -- CREATE INDEX informacje_indeks_idx ON informacje (indeks); CREATE INDEX informacje_podtyp_idx ON informacje (podtyp); CREATE INDEX informacje_idpromocja_idx ON informacje (idpromocja); CREATE INDEX informacje_pokaz_idx ON informacje (pokaz); -- COMMIT; -- create_table_cenydew.sql -- -- utworzenie tabeli [ceny_dew] zawierajacej indeksy i ceny(dewizowe) towarow -- CREATE TABLE cenydew ( indeks int4 NOT NULL, cenar decimal(9,2) DEFAULT '0.00', wal char(3) DEFAULT 'ZLP' ); -- COMMIT; -- create_index_cenydew.sql -- -- utworzenie wymaganych indeksow dla tabeli [ceny_dew] -- CREATE UNIQUE INDEX cenydew_indeks_idx ON cenydew (indeks); -- COMMIT; -- create_table_cennik.sql -- -- utworzenie tabeli [cennik] zawierajacej indeksy i nazwy towarow -- CREATE TABLE cennik ( indeks int4 NOT NULL, nazwa varchar(34), kod_prod varchar(19), dost int4 NOT NULL, vat float4 DEFAULT '22' ); -- COMMIT; -- create_index_cennik.sql -- -- utworzenie wymaganych indeksow dla tabeli [cennik] -- CREATE UNIQUE INDEX cennik_indeks_idx on cennik (indeks); CREATE INDEX cennik_nazwa_idx on cennik (nazwa); CREATE INDEX cennik_kod_prod_idx on cennik (kod_prod); CREATE INDEX cennik_dost_idx on cennik (dost); -- COMMIT; -- create_index_uniqmagazyn.sql -- -- utworzenie wymaganych indeksow dla tabeli [uniqmagazyn] -- CREATE UNIQUE INDEX uniqmagazyn_indeks_idx ON uniqmagazyn (indeks); -- COMMIT; -- create_index_katalog.sql -- -- utworzenie wymaganych indeksow dla tabeli [katalog] -- CREATE UNIQUE INDEX katalog_indeks_idx ON katalog (indeks); CREATE INDEX katalog_nazwa_idx ON katalog (nazwa); 31 CREATE INDEX katalog_kodprod_idx ON katalog (kod_prod); CREATE INDEX katalog_data_idx ON katalog (data); -- COMMIT; KATEGORIA SKRYPTÓW  DELETE Do tej kategorii zaliczaj si skrypty kasujce tabele oraz indeksy: drop_all_table.sql drop_all_index.sql -- drop_all_table.sql -- -- usuniecie wszystkich tabel -- DROP TABLE cennik; DROP TABLE cenydew; DROP TABLE dostawcy; DROP TABLE odbiorcy; DROP TABLE magazyn; DROP TABLE uniqmagazyn; -- tabela informacje zostaje bo jest uzupelniana z zewnatrz -- DROP TABLE informacje; DROP TABLE katalog; -- COMMIT; -- drop_all_index.sql -- -- usuniecie wszystkich indexow -- DROP INDEX cennik_indeks_idx; DROP INDEX cennik_nazwa_idx; DROP INDEX cennik_kod_prod_idx; DROP INDEX cennik_dost_idx; DROP INDEX cenydew_indeks_idx; DROP INDEX dostawcy_kod_idx; DROP INDEX dostawcy_nazwa_idx; DROP INDEX dostawcy_nazwa1_idx; DROP INDEX dostawcy_nazwa2_idx; DROP INDEX dostawcy_nip_idx; DROP INDEX uniqmagazyn_indeks_idx; DROP INDEX odbiorcy_kod_idx; DROP INDEX odbiorcy_nazwa_idx; DROP INDEX odbiorcy_nazwa1_idx; DROP INDEX odbiorcy_nazwa2_idx; -- DROP INDEX informacje_indeks_idx; -- DROP INDEX informacje_podtyp_idx; -- DROP INDEX informacje_idpromocja_idx; -- DROP INDEX informacje_pokaz_idx; DROP INDEX katalog_indeks_idx; DROP INDEX katalog_nazwa_idx; DROP INDEX katalog_kodprod_idx; DROP INDEX katalog_data_idx; -- COMMIT; 32 KATEGORIA SKRYPTÓW  LOAD Do tej kategorii zaliczaj si skrypty importujce dane do tabel oraz generujce dane na bazie ju| istniejcych poprzez agregacj czy filtrowanie. Wczytywanie bazuje na specjalnej metodzie importu danych bezpo[rednio do tabeli w jednym przebiegu jak udostpnia backend PostgreSQL a. Taki sposób importu definitywnie góruje nad metodami tradycyjnymi, wykorzystujcymi skBadni  INSERT INTO . Przewaga w szybko[ci jest szczególnie widoczna przy  du|ych importach rzdu kilkadziesit tysicy rekordów i wicej. load_table_dostawcy.sql load_table_odbiorcy.sql load_table_cenydew.sql load_table_uniqmagazyn.sql load_table_cennik.sql load_table_katalog.sql load_table_magazyn.sql -- load_table_dostawcy.sql -- -- ladowanie danych do tabeli [dostawcy] -- COPY dostawcy FROM '/home/bazy/emarket/tmp/DOSTAWCY.IN' USING DELIMITERS '|'; -- COMMIT; -- load_table_odbiorcy.sql -- -- ladowanie danych do tabeli [odbiorcy] -- COPY odbiorcy FROM '/home/bazy/emarket/tmp/ODBIORCY.IN' USING DELIMITERS '|'; -- COMMIT; -- load_table_cenydew.sql -- -- ladowanie danych do tabeli [cenydew] -- COPY cenydew FROM '/home/bazy/emarket/tmp/CENY_DEW.IN' USING DELIMITERS '|'; -- COMMIT; -- load_table_uniqmagazyn.sql -- -- Agregacja z tabeli magazyn do tabeli [uniqmagazyn] bazy emarket SQL... -- SELECT indeks AS agr_indeks, max(data) AS ost_data, sum(stan) AS suma_stan, sum(standp) AS suma_standp INTO TEMP agrmagazyn FROM magazyn GROUP BY indeks; -- 33 -- SELECT DISTINCT agr_indeks, ost_data, suma_stan, suma_standp INTO TEMP tmpmagazyn FROM magazyn, agrmagazyn WHERE agr_indeks=magazyn.indeks and ost_data=magazyn.data ORDER BY agr_indeks; -- -- --DROP TABLE uniqmagazyn; SELECT agr_indeks::int4 AS indeks, date(ost_data) AS data, suma_stan::float4 AS stan, suma_standp::float4 AS standp INTO uniqmagazyn FROM tmpmagazyn ORDER BY 1; -- -- DROP TABLE magazyn; -- load_table_cennik.sql -- -- ladowanie danych do tabeli [cennik] -- COPY cennik FROM '/home/bazy/emarket/tmp/CENNIK.IN' USING DELIMITERS '|'; -- COMMIT; -- load_table_katalog.sql -- -- zlozenie danych z tabel i zaladowanie do ostatecznej prezentacyjnej tabeli [katalog] -- DROP TABLE katalog; SELECT cennik.indeks, cennik.nazwa, cennik.kod_prod, uniqmagazyn.data, cenydew.wal, cenydew.cenar AS netto, -- numeric_round(cenydew.cenar::float8 * (cennik.vat /100+1),2) AS brutto, round(cenydew.cenar::float8 * (cennik.vat /100+1),2) AS brutto, standp AS nastanie INTO katalog FROM cennik,uniqmagazyn, cenydew WHERE (cennik.indeks=uniqmagazyn.indeks) AND (cennik.indeks=cenydew.indeks) -- AND standp>=0 AND -- date_ge(uniqmagazyn.data,'1998-12-31') AND -- (cennik.nazwa like '%%%%') ORDER BY 3,2; -- load_table_magazyn.sql -- -- ladowanie danych do tabeli [cennik] -- COPY magazyn FROM '/home/bazy/emarket/tmp/MAGAZYN.IN' USING DELIMITERS '|'; -- COMMIT; 34 KATEGORIA SKRYPTÓW  CHECK Skrypty te wykonuj kontrol danych w tabelach Badowanych do bazy na obecno[ zduplikowanych identycznych rekordów. W wyniku zawieszenia si komputera na którym dziaBa aplikacja finansowo ksigowa indeksy NTX bazy danych DBF mog zosta uszkodzone, a wtedy mo|e doj[ do takiej sytuacji, |e aplikacja  nie[wiadoma dopisanej pozycji do bazy na innej koDcówce sieciowej mo|e zarejestrowa identyczn krotk. Skrypty te powstaBy gdy wynikBa taka wBa[nie sytuacja. Nastpstwem tego byBa konieczno[  rcznego , usuwania bBdnych rekordów z tabeli DBF oraz reindeksacja. duplicated_cenydew.sql duplicated_cennik.sql duplicated_dostawcy.sql duplicated_odbiorcy.sql -- duplicated_cenydew.sql -- -- Wyszukanie podwojnych indeksow w tabeli cenydew... -- SELECT indeks, count(indeks) AS ile FROM cenydew GROUP BY indeks HAVING count(indeks)>1; -- duplicated_cennik.sql -- -- Wyszukanie podwojnych indeksow w tabeli cennik... -- SELECT indeks, count(indeks) AS ile FROM cennik GROUP BY indeks HAVING count(indeks)>1; -- duplicated_dostawcy.sql -- -- Wyszukanie podwojnych identyfikatorow dostawcow... -- SELECT kod, count(kod) AS ile FROM dostawcy GROUP BY kod HAVING count(kod)>1; -- duplicated_odbiorcy.sql -- -- Wyszukanie podwojnych identyfikatorow odbiorcow... -- SELECT kod, count(kod) AS ile FROM odbiorcy GROUP BY kod HAVING count(kod)>1; KATEGORIA SKRYPTÓW  ANALYSIS W tej kategorii w pierwotnym zamierzeniu miaBy powsta skrypty wykonujce ró|ne analizy danych zebranych w tabelach, zarejestrowanych transakcjach i innych operacjach. Na obecnym stadium rozwoju sklepu internetowego zostaB opracowany jeden skrypt wybierajcy towar  niechodliwy z bazy danych. Skrypt wystpuje w dwóch wersjach a ich zadaniem jest bardziej przetestowanie mo|liwo[ci skBadania danych z wielu tabel ni| u|ytkowe wykorzystanie. W momencie gdy powstawaB, dostpna wersja bazy PostgreSQL nie miaBa 35 jeszcze zaimplementowanej obsBugi zBczeD klauzulami  JOIN i nale|y go traktowa jako  wprawk programistyczn, gdy| obecna wersja PostgreSQL zapewnia peBn obsBug zBczeD, lewo i prawostronnych a tak|e zaw|ajcych itp. -- niechodliwy.sql -- -- Towar na stanie niechodliwy -- SELECT *, float4(stan+standp)*float4(cenaz) AS wartosc FROM uniqmagazyn, cennik WHERE uniqmagazyn.indeks=cennik.indeks and (stan + standp)>0 and data<'1999-01-01' ORDER BY data; -- niechodliwy.sql -- -- Towar na stanie niechodliwy zlaczenie bez klauzuli JOIN -- SELECT uniqmagazyn.*, cennik.* FROM uniqmagazyn, cennik WHERE uniqmagazyn.indeks=cennik.indeks UNION ALL SELECT uniqmagazyn.*, null, null, null, null, null FROM uniqmagazyn WHERE NOT EXISTS ( SELECT * FROM cennik WHERE uniqmagazyn.indeks=cennik.indeks ); STRUKTURA BAZY Poni|sze zestawienie jest wynikiem dziaBania skryptu  99-struktura generujcego schematyczn i pogldow prezentacj struktury tabel i przynale|nych im indeksów w bazie danych eMarket. Listing ten prezentuje stan bazy po wykonaniu peBnego zaBadunku wszystkich tabel oraz wykonaniu skryptów aktualizujcych i czyszczcych. Table "cennik" Attribute | Type | Modifier -----------+-------------+-------------- indeks | integer | not null nazwa | varchar(34) | kod_prod | varchar(19) | dost | integer | not null vat | float4 | default '22' Indices: cennik_dost_idx, cennik_indeks_idx, cennik_kod_prod_idx, cennik_nazwa_idx Table "cenydew" Attribute | Type | Modifier -----------+--------------+---------------- indeks | integer | not null cenar | numeric(9,2) | default '0.00' wal | char(3) | default 'ZLP' Index: cenydew_indeks_idx 36 Table "uniqmagazyn" Attribute | Type | Modifier -----------+---------+---------- indeks | integer | data | date | stan | float4 | standp | float4 | Index: uniqmagazyn_indeks_idx Table "dostawcy" Attribute | Type | Modifier -----------+-------------+---------- kod | integer | not null nazwa | varchar(16) | nazwa1 | varchar(41) | nazwa2 | varchar(41) | nazwa3 | varchar(41) | nazwa4 | varchar(41) | bank1 | varchar(41) | bank2 | varchar(41) | bank3 | varchar(41) | nip | char(13) | Indices: dostawcy_kod_idx, dostawcy_nazwa1_idx, dostawcy_nazwa2_idx, dostawcy_nazwa_idx, dostawcy_nip_idx Table "odbiorcy" Attribute | Type | Modifier -----------+-------------+---------- kod | integer | not null nazwa | varchar(16) | nazwa1 | varchar(41) | nazwa2 | varchar(41) | nazwa3 | varchar(41) | nazwa4 | varchar(41) | nip | char(13) | Indices: odbiorcy_kod_idx, odbiorcy_nazwa1_idx, odbiorcy_nazwa2_idx, odbiorcy_nazwa_idx Table "katalog" Attribute | Type | Modifier -----------+----------------------+---------- indeks | integer | nazwa | varchar(34) | kod_prod | varchar(19) | data | date | wal | char(3) | netto | numeric(9,2) | brutto | numeric(65535,65531) | nastanie | float4 | Indices: katalog_data_idx, katalog_indeks_idx, katalog_kodprod_idx, katalog_nazwa_idx Table "informacje" Attribute | Type | Modifier ------------+---------------+---------------------- indeks | integer | not null podtyp | integer | not null default '0' idpromocja | integer | not null default '0' pokaz | char(1) | default 'N' skrot | varchar(200) | default '' tytul | varchar(80) | default '' opis | varchar(4000) | default '' link1 | varchar(80) | default '' link2 | varchar(80) | default '' flagi | varchar(80) | default '' Indices: informacje_idpromocja_idx, informacje_indeks_idx, informacje_podtyp_idx, informacje_pokaz_idx 37 RozdziaB V  WYSZUKI WARKA TOWARÓW KONCEPCJA DZIAAANIA Chcc udostpni potencjalnym klientom efektywny mechanizm wyszukiwania w bazie towarów, koniecznym staBo si skonstruowanie odpowiednich mechanizmów umo|liwiajcych pobranie od internauty interesujcej go frazy, przeszukanie bazy danych oraz zaprezentowanie znalezionych pozycji. Pewnym problemem wydaje si by tutaj konieczno[ poBczenia efektywno[ci mechanizmu wyszukujcego z mo|liwo[ciami silnika Rysunek 7  GBówna strona wyszukiwarki towarów. bazy danych. Wikszo[ obecnie istniejcych baz danych nie pozwala na wyszukiwanie peBno tekstowe przy wykorzystaniu indeksu, gdy szukana fraza zaczyna si znakiem wieloznacznym w zapytaniu typu  LIKE . Najnowsze komercyjne bazy danych takie jak ORACLE wspieraj ten mechanizm poprzez statyczne utworzenie specjalnych struktur indeksujcych peBnotekstowo caBe pola tabeli, jednak|e jedynie statycznie. Ka|dorazowe dopisanie krotki do tabeli wymusza ponowne peBne zaindeksowanie caBo[ci tabeli, co praktycznie wyklucza to zastosowanie w przypadku bazy, gdzie s modyfikowane lub dodawane kolejne rekordy. 38 PostgreSQL posiada bardzo zaawansowane metody i typy indeksów, jednak nie ma mo|liwo[ci ich u|ycia w przypadku peBno tekstowego wyszukiwania. Silnik bazy danych jest wtedy zmuszony do wykonania peBnego przej[cia po wszystkich krotkach tabeli (tzw. full scan), co drastycznie obni|a efektywno[ tego rozwizania. W obecnej fazie rozwoju aplikacji sklepu internetowego zdecydowano si na pewne rozwizania skutecznie eliminujce wykonywanie peBnych przej[ w tabelach. W gBównym oknie wyszukiwawczym jednak taki mechanizm musiaB tymczasowo pozosta ze wzgldu na konieczno[ zapewnienia peBnego wyszukiwania nawet kosztem zwikszonego obci|enia systemu i spowolnienia samego procesu. W module ofert przy przegldaniu gotowych zestawieD towarów zastosowano zmodyfikowany mechanizm gBównej wyszukiwarki w taki sposób aby nie u|ywa zapytaD zaczynajcych si znakiem wieloznacznym  % w klauzuli  LIKE , co spowodowaBo mo|liwo[ u|ycia przez motor bazy danych indeksów na przegldanych polach a tym samym wykonywanie caBo[ci zapytania w sposób bByskawiczny. Rysunek 8  Prezentacja wyników wyszukania towaru. Chcc rozwiza tzw. problem  full text search czyli peBnotekstowego wyszukiwania korzystajcego z indeksów (http://www.postgresql.org/idocs/index.php?indices.html) w przygotowaniu jest pewien model przechowywania nazw towarów w dodatkowej tabeli, ale w taki sposób, aby mo|liwym staBo si zaindeksowanie ka|dego wyrazu z nazwy towaru. 39 Opracowana koncepcja polega na podziale nazwy towarów na odrbne wyrazy a nastpnie na zapisanie ich do odrbnych pól w krotce. 40 Ka|de pole bdzie polem indeksowanym tak wic przy konstruowaniu zapytania mo|liwym stanie si wykorzystanie w mechanizmie wyszukiwarki odwoBania klauzulami  LIKE bez podawania na pocztku znaku wieloznacznego  % a zamian szukanej frazy na kilka klauzul typu  LIKE  towar%  co pozwoli na u|ycie indeksów jak w przypadku przeszukania w module ofert. Pole z nazw towaru i oznaczeniem producenta sumarycznie ma dBugo[ 34+19=53 znaki. ZakBadajc |e w skrajnym pesymistycznym przypadku nazwa towaru zBo|ona bdzie z pojedynczych liter rozdzielanych spacjami to otrzymujemy okoBo 27 pól Rysunek 9  Prezentacja wyszukiwania predefiniowanego rodzaju towarów. potrzebnych do rozbicia na wyrazy (53/2=26+1). Tak wic przyjmujemy, |e 30 pól jest liczb wystarczajca w zupeBno[ci do przechowania caBej nazwy towaru w rozbiciu na wyrazy. Spacje nie s przechowywane bowiem sBu| jako znak, wedBug którego dokonujemy rozbicia na cz[ci skBadowe. Do kolejnych pól rekordu wpisujemy kolejne wyrazy z nazwy towaru a sama tre[ zapytania wykonujcego wyszukanie z wykorzystaniem indeksów przyjmie wtedy przykBadow posta: SELECT * FROM subtowary WHERE pole1 LIKE  szukana_fraza% OR pole2 LIKE  szukana_fraza% OR .....; 41 ZakBadamy oczywi[cie |e szukana fraza jest pojedynczym wyrazem, a w przypadku, gdy jest to kilka wyrazów wykonujemy kilka takich zapytaD dla ka|dego z wyrazów, skBadanych nastpnie w jeden zestaw wyników. Powy|szy projekt rozwizania problemu peBnych przej[ po tabeli wydaje si by optymalnym do tego celu rozwizaniem i bdzie testowo zastosowany w aplikacji sklepu internetowego w najbli|szym czasie. KOD yRÓDAOWY WYSZUKIWARKI Mechanizm wyszukiwarki zostaB wbudowany w ró|ne strony serwisu internetowego firmy. W momencie gdy powstawaB, jzyk PHP nie posiadaB uniwersalnej klasy obiektów sBu|cych do odwoBania do bazy danych. Ka|dy typ bazy danych wymagaB u|ycia innego zestawu poleceD. Chcc maksymalnie uniezale|ni si od samej bazy zastosowano uniwersalne definicje funkcji odwoBujcych si do baz. Wykorzystano do tego celu bibliotek phpDB której autorami s J. Thong i C. Fonk (phpdb.linuxbox.com) pozwalajc na zamaskowanie metod odwoBaD do baz MySQL, MSQL, PostgreSQL, Microsoft SQL Server, Sybase na jednakowe funkcje, co pozwala na Batw wymian silnika bazy na inny bez konieczno[ci zmian w kodzie zródBowym. Obecnie rozwijana jest przez autorów jzyka PHP, klasa uniwersalnych funkcji, metod i obiektów pozwalajca na uniknicie problemów zwizanych z konieczno[ci przeróbek kodu w takich przypadkach. Projekt jest obecnie w bardzo wczesnej fazie rozwoju jednak|e fakt tworzenia go przez ekip tworzc PHP gwarantuje, |e wkrótce mo|liwym bdzie zastosowanie go w systemach produkcyjnych. Nosi on nazw  PEAR: the PHP Extension and Application Repository . Poni|szy listing prezentuje i omawia kod php wyszukiwarki. Niektóre linie zostaBy sztucznie podzielone na krótsze ze wzgldu na ich dBugo[, co oznaczono znakiem  \ (jednak|e on sam w kodzie oryginalnym nie mo|e wystpowa). Listing zawiera komentarze [wiadczce o zespoBowej pracy nad powstajcym kodem oraz podziaB zadaD na kod dostpu i obsBugi bazy danych oraz kod dynamicznego generowania strony na podstawie pobieranych z bazy danych rekordów. <?php // obsluga bazy wyszukiwarki, plik: db.php3 // parametry glowne: uzytkownik, haslo, nazwa bazy itp. include "inc/db.inc"; // zaimportowanie meta tagow include "inc/meta.inc"; // phpDB wrapper do baz danych, wkoncu to ma chodzic na wszystkim :) include "lib/phpDB.inc"; // data aktualizacji do ewentualnego wyswietlenia // okreslana dynamicznie jako data i czas modyfikacji pliku index.php3 $datam = filemtime('index.php3'); $filemodtime = date("j m Y h:i:s A", $datam); 42 $aktual = strftime ('%d.%m.%Y godzina %H:%M:%S', $datam); ?> <title>-x(AGD)x- .::EuroMarket - Video Tomex::. -x(RTV)x-</title> <script language="JavaScript"> function WinOpen(file) { window.open(file,'_blank','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes, \ resizable=no,width=600,height=400');} </script> </HEAD> <body> <? include "inc/menu.inc"; ?> <br> <div align="center"> <table width="760" cellpadding="0" cellspacing="0" border="0"> <tr><td width="200" align="center" valign="baseline"> <form action="db.php3" method="post"> <strong>Potrzebujesz czego[?</strong><BR> <input style="color: #1c36b3; background-color: #CCAC0C; font-size: 8pt; font-weight: 800;" type="Text" size="14" name="towar" style="width: 140px"> <br><br><input style="background-color: #1c36b3; color: #CCAC0C; font-size: 8pt; font-weight: 800;" type="Submit" value="Szukaj"> </form> </td> <td valign="top"> <strong><u>Mo|esz szuka korzystaj±c z symboli wieloznacznych: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</u></strong><br> <table cellpadding="0" cellspacing="0" border="0"> <tr><td width="250" valign="bottom"><B>*</B> -zastpuje dowolny cig znaków<BR> <B>?</B> -zastpuje jeden znak</td> <td valign="bottom">Na przykBad:<B>telewizor*philips</B> <br> Bez wzgldu na wielko[ znaków.</td></tr></table> <br> &nbsp;&nbsp;&nbsp;&nbsp; Je|eli chcesz zamówi wybrany produkt kliknij na ikonce <img src="gfx/wozek0.gif" alt="Zamow" border="0"> </td> </tr> </table> </div> <br> <?php // sprawdzamy czy akurat trwa ladowanie danych do bazy // nie jest to najlepszy sposób, trzeba potem zmienic na lepszy if ( ! file_exists("/home/bazy/tmp/emarket.tmp")) { //$towar z brany jest z tresci zapytania przegladarki trzeba go dobrze wyfiltrowac potem !!! //trzeba oprogramowac wybor *? jak w dosie //zastosowac regexpy do odfiltrowania niebezpiecznych znakow (sanity check) /* tymczasowo wylaczam ten komunikat msg-box if ($towar=="" or $towar==" "){ echo "<SCRIPT LANGUAGE=\"JavaScript\">\n"; echo "<!--\n"; echo "alert('Nie podales czego szukasz!')\n"; echo "history.back()\n"; echo "//-->\n"; echo "</SCRIPT>\n"; echo "<B>Nie podales czego szukasz!</B><BR>"; echo "<A HREF=\"$powrot\">Powrót</A>\n"; */ } //trzeba dorobic full_text_search do PostgreSQL bo inaczej nie posluguje sie tu indexami //gdy w zapytaniu jest: like %costam% to jet robiony full table scan // zduplikowanie zmiennej towar $nazwa_tow = $towar; //konwersja * i ? na % i _ dla SQL $towar=strtr($towar,"*?","%_"); 43 $towar="'%" . strtoupper($towar) ."%'"; // link powrotu echo "<table width=\"760\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\">"; echo "<tr><td align=\"left\" valign=\"baseline\">"; echo "<div align=\"left\">"; echo "Wyniki wyszukiwania sBowa &quot;<b>" . $nazwa_tow . "</b>&quot; :<br>"; echo "<B>Ceny detaliczne w zB, dla klientów indywidualnych.</B></div><br><br>"; echo "</td></tr></table>"; //echo "<FORM><INPUT TYPE=\"button\" VALUE=\"POWRÓT\" onClick=\"parent.location.href='http://www.vt.pl'\"></FORM>"; ?> <!-- Tabela wynikow wyszukiwania--> <?php // jednorazowe stale i trwale polaczenie z baza // presistent connections pozwalaja na urzymywanie przez Apache stalego polaczenia // z PostgreSQL co wyjatkowo przyspiesza dzialanie calosci $db=new phpDB(); $db->pconnect($db_host,$db_user,$db_pass,$db_name) or die("WystapiB bBd przy Bczeniu!<BR>\n "); // wersja zapytania po optymalizacji $sqlquery="SELECT * FROM katalog WHERE nastanie>=0 AND date_ge(data, '$datapoczatkowa') "; if ($towar=="'%%%'") { $selekcja="";} else {$selekcja="AND ((nazwa like $towar) OR (kod_prod like $towar))";}; $sqlquery= $sqlquery . $selekcja . "LIMIT $ilosc OFFSET $start"; //echo $sqlquery . ";<BR><BR>\n"; $result = $db->execute($sqlquery) or die("WystpiB bBd przy zapytaniu. <BR>\n"); $numrows=$result->getNumOfRows(); $numfields=$result->getNumOfFields(); ?> <TABLE WIDTH=760 BORDER=0 BGCOLOR="#b32f1c" cellpadding="0" cellspacing="0"> <TR> <TD HEIGHT="14"><B style="color: #FFF200;">lp</B></TD> <TD HEIGHT="14"><B style="color: #FFF200;"> zam.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nazwa towaru</B></TD> <TD HEIGHT="14"><B style="color: #FFF200;">data ceny</B></TD> <TD HEIGHT="14"><B style="color: #FFF200;">cena netto</B></TD> <TD HEIGHT="14"><B style="color: #FFF200;">cena brutto</B></TD> <TD HEIGHT="14"><B style="color: #FFF200;">dostpny</B></TD> <TD HEIGHT="14"><B style="color: #FFF200;">info</B></TD> </TR> <?php $row=0; $img=0; /* Sprawdzamy czy przegladara ma jave czyli ze sie zglasza sie jako Mozilla to jest naprawde proste i dobre i pewnie dodamy to do jakiego inc'luda na stale fakt ze jak Mozilla to nie zawsze jest java ale to na razie wystarczy, a i links dziala :) */ if (strpos($HTTP_USER_AGENT, "ozilla") >0) {$jestjava=TRUE;} else {$jestjava=FALSE;}; /* Poprawilem skladnie html'a bo sie rozlatywala zwlaszcza przy generowaniu tabeli, teraz powinno byc ok w kazdej przegladarce. Zmienilem troche wyglad stron, tak juz zostanie i pod ten styl bede wszystko zmienial */ // petla czytania kolejnych rekordow z bazy while(!$result->EOF) { // naprzemienne kolory wierszy $bgcolor= ($row % 2) ; if ($bgcolor<>0) { $bg=$bg1;} else { $bg=$bg2;}; $ind=$result->fields["indeks"]; 44 // jesli przegladara zgodna z Mozilla to zakladamy ze ma jave if ($jestjava){$wywolanie="JavaScript:WinOpen('towar.php?indeks=$ind')";} else {$wywolanie="towar.php?indeks=$ind";} if ($result->fields["nastanie"]==0) {$stan="-";} else {$stan="tak";}; if ($ind!=""){ // wyswieltamy naglowek i numer wiersza echo "<TR BGCOLOR=$bg><TD ALIGN=\"center\">"; echo ($row + $start + 1); echo "</TD>"; // podmiana obrazka do zamawiania - nie udalo mi sie zrobic ladnego przezroczystego gifa wiec PHP RuLeZ if ($img == 0 ) { echo "<TD>&nbsp;<a href=\"zakup.php3?towar=" . $result->fields["nazwa"] . "&netto=" . \ $result->fields["netto"] . "&brutto=" . $result->fields["brutto"] . "\"> \ <img name=\"wozek$row\" src=\"gfx/wozek00.gif\" alt=\"Zamawiam!\" border=\"0\"></a> \ <B>&nbsp;" . $result->fields["nazwa"]. "&nbsp;</b> </TD>"; $img = $img + 1; } else { echo "<TD valign=\"middle\">&nbsp;<a href=\"zakup.php3?towar=" . $result->fields["nazwa"] . \ "&netto=" . $result->fields["netto"] . "&brutto=" . $result->fields["brutto"] . "\"> \ <img name=\"wozek$row\" src=\"gfx/wozek0.gif\" alt=\"Zamawiam!\" border=\"0\"></a> \ <B>&nbsp;" . $result->fields["nazwa"]. "&nbsp;</b> </TD>"; $img = $img - 1; } echo "<TD><B>&nbsp;" . $result->fields["data"] . "&nbsp;</b></TD>"; echo "<TD ALIGN=\"right\">&nbsp;" . $result->fields["netto"] . "&nbsp;</TD>"; echo "<TD ALIGN=\"right\"><B>&nbsp;". $result->fields["brutto"] . "&nbsp;</b></TD>"; echo "<TD ALIGN=\"center\">&nbsp;". $stan . "&nbsp;</TD>"; if ($stan == "tak") { echo "<TD ALIGN=\"center\">&nbsp;<a href=\"$wywolanie\">info</a>&nbsp;</TD>";} else { echo "<TD ALIGN=\"center\">&nbsp;$stan&nbsp;</TD>";}; echo "</TR>"; }; // pobieramy nastepna krotke $result->nextRow(); $row++; } // koniec petli czytania rekordow //koniec tabeli echo "</TABLE>\n"; /* Te zagniezdzenia if trzeba poprzerabiac bo za duzo czasu tracimy na te warunki narazie zostawie tak ale pozniej to pozmieniam, za to nie wyswietla pustego wiersza tabeli z nr 1 oraz wyswietla info. Poprawnie zamyka tag tabeli. Pewnie jeszcze zawine w to naglowek tabeli, pozniej... */ if ($ind=="") { //nic nie znaleziono w bazie echo "<b style=\"color:#DB2614\">"; echo "Przepraszamy!<BR>Nie znaleziono tego towaru w bazie.<BR>"; echo "Prosz spróbowa ponownie oraz zmieni nazw szukanego towaru...<BR><BR></b>"; }; // zwalniamy pamiec i zamykamy polaczenie z baza // (teoretycznie bo przeciez uzywamy presistent connection ale na wszelki wypadek // trzeba po sobie posprzatac $result->close(); $db->close(); } //koniec warunku aktualizacji bazy else { // wlasnie trwa aktualizacja sql'a echo "<b style=\"color:#DB2614\">"; echo "Przepraszamy! <BR> WBa[nie trwa aktualizacja bazy danych.<BR>"; echo "Prosz spróbowa ponownie za chwil...<BR><BR></b>"; }; onClick=\"parent.location.href='http://www.vt.pl'\"></FORM>"; echo "<br>"; include "inc/stopka.inc"; ?> </body></html> 45 Struktura powy|szego skryptu wskazuje na wzajemne przeplatanie kodu PHP, JavaScript oraz czystego HTML'u. Mo|liwe jest tak|e wykonywanie wstawek w innych jzykach skryptowych jak np. Visual Basic Script. Najcz[ciej powtarzajce si fragmenty kodu zostaBy wyodrbnione do zewntrznych plików a nastpnie doBczane klauzul  include w ró|nych podprogramach w celu predefiniowania i ujednolicenia wygldu generowanych stron czy te| identycznego tworzenia meta-tagów itp. W caBo[ci generowanych stron kod opisu strony napisany jest zgodnie z obowizujcym standardem HTML przy zastosowaniu stylów. UBatwia to zachowanie jednakowego wygldu wszystkich generowanych stron. Poni|szy listing przedstawia gBówny plik definicji stylów. body { background-color : #DEBE09; margin-top : 0px; margin-right : 0px; margin-left : 0px; font-family : Verdana, Geneva, Arial, Helvetica, sans-serif; font-size : 8pt; color : #1e1164; text-align: center; } .tab { border-style: solid; border-width: 1px; border-top-width: 0px; border-bottom-width: 0px; } a { font-size: 8pt; color : #0a0eb6; font-family : Verdana, Geneva, Arial, Helvetica, sans-serif; text-decoration : none; } a:hover { font-size: 8pt; color : red; font-family : Verdana, Geneva, Arial, Helvetica, sans-serif; text-decoration : none; } td. { font-family : Arial, Helvetica, sans-serif; font-size : 8pt; color : #1e1164; font-family : Verdana, Geneva, Arial, Helvetica, sans-serif; } .m7 { font-size: 7px; color : #eac137; font-weight : 800; font-family : Verdana, Geneva, Arial, Helvetica, sans-serif; text-decoration : none; } .m { font-size: 10px; color : SlateGray; font-weight : 800; font-family : Verdana, Geneva, Arial, Helvetica, sans-serif; } 46 .cena { border-style: solid; border-width: 1px; border-color: black; border-left-widht: 1px; border-right-widht: 1px; border-top-widht: 1px; border-bottom-widht: 1px; text-align: center; font-size: 15px; color : Yellow; background-color: #b32f1c; font-weight : 900; font-family : Verdana, Geneva, Arial, Helvetica, sans-serif; } .cena2 { border-style: solid; border-width: 1px; border-color: black; border-left-widht: 1px; border-right-widht: 0px; border-top-widht: 1px; border-bottom-widht: 1px; text-align: center; font-size: 15px; color : black; background-color: #DEBE09; font-weight : 100; font-family : Verdana, Geneva, Arial, Helvetica, sans-serif; } .cena3 { border-style: solid; border-width: 1px; border-color: black; border-left-widht: 0px; border-right-widht: 1px; border-top-widht: 1px; border-bottom-widht: 1px; text-align: center; font-size: 15px; color : Yellow; background-color: navy; font-weight : 900; font-family : Verdana, Geneva, Arial, Helvetica, sans-serif; } .red { color: #ac0f0f; } Zastosowanie stylów pozwala na szybkie zmiany wygldu prezentowanych stron w przypadku  od[wie|ania serwisu internetowego za pomoc zmiany projektu graficznego. Plik z opisem styli jest przez przegldark wczytywany po napotkaniu odwoBania w tre[ci strony do dokumentu z definicjami u|ywanych styli. Poni|szy listing prezentuje gBówny plik generujcy wikszo[ stron serwisu. <? include "inc/meta.inc"; ?> <title>-x(AGD)x- .::EuroMarket - Video Tomex::. -x(RTV)x-</title> <script language="JavaScript"> function WinOpen(file) { window.open(file,'_blank','toolbar=no,location=no,directories=no,status=no,menubar=no, \ scrollbars=no,resizable=no,width=300,height=240');} </script> <script language="JavaScript"><!-- function chBr(br, ver) { if (!(chBr.arguments.length > 0)) return (navigator.appName + ', ' + navigator.appVersion); var Browser = br; var Version = (chBr.arguments.length > 1) ? ver : null; var BrowserFlag = (navigator.appName.toLowerCase() == Browser.toLowerCase()) ? true : false; 47 if (Version != null) { var VersionFlag = (navigator.appVersion.substring(0,1) == Version.substring(0,1)) ? true : false; } return (BrowserFlag || VersionFlag); } function openr(dokument) { window.open(dokument,'parent[oferta]'); } // --></script> </head> <body bgcolor="#DEBE09"> <br> <? # jezeli brak zapytania startuj tutaj if ($ID == '') { ?> <div align="center"> <table cellpadding="0" cellspacing="0" border="0"> <tr><td width="150" valign="top"> <? include "inc/targi.inc" ?> </TD><td valign="top"> <! Generowanie przyciskow metoda rollover --> <!-- <div align="right"><a class="fade" href="javascript:WinOpen('inc/s_help.html')">pomoc</a></div> --> </div> <table cellpadding="0" cellspacing="0" border="0"> <tr><td valign="top"> <div align="center"> <a href="?ID=05"><img src="gfx/logo_vt.gif" width="361" height="107" alt="" border="0"></a><br> </div> <a href="?ID=01" onmouseover="if ( (chBr('Netscape', '3') == true) || (chBr('Explorer', '4') == true) ) menu1.src='gfx/onas_1.gif'" onmouseout="if ( (chBr('Netscape', '3') == true) || (chBr('Explorer', '4') == true) ) menu1.src='gfx/onas_0.gif'"> <img name="menu1" src="gfx/onas_0.gif" alt="" border="0"></a></td></tr> <tr><td width="94" align="right"> <a href="?ID=02" onmouseover="if ( (chBr('Netscape', '3') == true) || (chBr('Explorer', '4') == true) ) menu2.src='gfx/szukaj_1.gif'" onmouseout="if ( (chBr('Netscape', '3') == true) || (chBr('Explorer', '4') == true) ) menu2.src='gfx/szukaj_0.gif'"> <img name="menu2" src="gfx/szukaj_0.gif" alt="" border="0"></a></td></tr> <tr><td width="108" align="right"> <a href="http://poczta.vt.pl" onmouseover="if ( (chBr('Netscape', '3') == true) || (chBr('Explorer', '4') == true) ) menu3.src='gfx/internet_1.gif'" onmouseout="if ( (chBr('Netscape', '3') == true) || (chBr('Explorer', '4') == true) ) menu3.src='gfx/internet_0.gif'"> <img name="menu3" src="gfx/internet_0.gif" alt="" border="0"></a></td></tr> <tr><td width="129" align="right"> <a href="?ID=04" onmouseover="if ( (chBr('Netscape', '3') == true) || (chBr('Explorer', '4') == true) ) menu4.src='gfx/partnerzy_1.gif'" onmouseout="if ( (chBr('Netscape', '3') == true) || (chBr('Explorer', '4') == true) ) menu4.src='gfx/partnerzy_0.gif'"> <img name="menu4" src="gfx/partnerzy_0.gif" alt="" border="0"></a></td></tr> <tr><td width="161" align="right"> <a href="?ID=05" onmouseover="if ( (chBr('Netscape', '3') == true) || (chBr('Explorer', '4') == true) ) menu5.src='gfx/promocje_1.gif'" onmouseout="if ( (chBr('Netscape', '3') == true) || (chBr('Explorer', '4') == true) ) menu5.src='gfx/promocje_0.gif'"> <img name="menu5" src="gfx/promocje_0.gif" alt="" border="0"></a></td></tr> <tr><td width="221" align="right"> <a href="oferta.php3" onmouseover="if ( (chBr('Netscape', '3') == true) || (chBr('Explorer', '4') == true) ) menu6.src='gfx/oferta_1.gif'" onmouseout="if ( (chBr('Netscape', '3') == true) || (chBr('Explorer', '4') == true) ) menu6.src='gfx/oferta_0.gif'"> <img name="menu6" src="gfx/oferta_0.gif" alt="" border="0"></a></td></tr> <tr><td width="290" align="right"> <a href="index.php3?ID=07" onmouseover="if ( (chBr('Netscape', '3') == true) || (chBr('Explorer', '4') == true) ) menu7.src='gfx/pkth_1.gif'" onmouseout="if ( (chBr('Netscape', '3') == true) || (chBr('Explorer', '4') == true) ) menu7.src='gfx/pkth_0.gif'"> <img name="menu7" src="gfx/pkth_0.gif" alt="" border="0"></a></td></tr> </table> 48 <div align="center"> <! wywolanie wyszukiwania --> <form action="db.php3" method="post"> <b>Szukasz czego[???</b><br> <input style="color: #1c36b3; background-color: #CCAC0C; font-size: 8pt; font-weight: 800;" type="Text" size="14" name="towar" style="width: 140px"> <input style="background-color: #1c36b3; color: #CCAC0C; font-size: 8pt; font-weight: 800;" type="Submit" value="Szukaj"> </form> </div> </td> <td valign="top"> <! Dodatkowe elementy promocyjne --> <? include "inc/targi2.inc"; ?> </td> </tr> </table> </div> <br> <? } # tutaj jezeli wyslane jest zapytanie inne niz null else { include "inc/menu.inc"; ?> <br> <table cellpadding="0" cellspacing="0" border="0" width="750"> <tr> <td align="center"> <? include "inc/$ID.inc"; ?> </td></tr> </table> <? include "inc/stopka.inc"; ?> <? } ?> </td></tr> </table> <br> </body> </html> Skrypt ten jest wywoBywany jako strona gBówna i od niego zaczyna dziaBanie caBo[ wyszukiwania oraz nawigowania po stronach serwisu. Przy konstruowaniu serwisu zbudowano moduB  oferta generujcy w predefiniowany sposób konkretne pozycje tematyczne posiadanych towarów. Poni|szy kod jest odpowiedzialny za obsBug i wy[wietlanie tych informacji. 49 <?php // obsluga bazy wyszukiwarki // parametry glowne include "inc/db.inc"; // licznik :> include "inc/counter.inc"; // meta include "inc/meta.inc"; // phpDB wrapper do baz danych, wkoncu to ma chodzic na wszystkim :) include "lib/phpDB.inc"; // aktualizacja $datam = filemtime('index.php3'); $filemodtime = date("j m Y h:i:s A", $datam); $aktual = strftime ('%d.%m.%Y godzina %H:%M:%S', $datam); ?> <script language="JavaScript"><!-- function chBr(br, ver) { if (!(chBr.arguments.length > 0)) return (navigator.appName + ', ' + navigator.appVersion); var Browser = br; var Version = (chBr.arguments.length > 1) ? ver : null; var BrowserFlag = (navigator.appName.toLowerCase() == Browser.toLowerCase()) ? true : false; if (Version != null) { var VersionFlag = (navigator.appVersion.substring(0,1) == Version.substring(0,1)) ? true : false; } return (BrowserFlag || VersionFlag); } function openr(dokument) { window.open(dokument,'parent[oferta]'); } // --></script> <title>-x(AGD)x- .::EuroMarket - Video Tomex::. -x(RTV)x-</title> <script language="JavaScript"> function WinOpen(file) { window.open(file,'_blank','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes,resi zable=no,width=600,height=400');} </script> </HEAD> <body> <? include "inc/menu.inc"; ?> <br> <div align="center"> <table width="760" cellpadding="0" cellspacing="0" border="0"> <tr> <td align="center" width="150" valign="top"> <table border="0" width="150" cellpadding="0" cellspacing="0"> <tr> <tr><td align="center" height="16" style="background-color: #b32f1c; color: yellow"><strong>Nasza Oferta</strong></td></tr> </tr> </table> <br> <table border="0"> <tr> <td align="center"> <a style="font-size: 7pt" href="oferta.php3?show=telewizory"> <img src="gfx/tv.gif" alt="" border="0"><br> telewizory </a> </td> </tr> <tr> <td align="center"> <a style="font-size: 7pt" href="oferta.php3?show=magnetofony"> 50 <img src="gfx/mag.gif" alt="" border="0"><br> magnetofony, radiomagnetofony </a> </td> </tr> <tr> <td align="center"> <a style="font-size: 7pt" href="oferta.php3?show=pralki"> <img src="gfx/pralka.gif" alt="" border="0"><br> pralki, zmywarki </a> </td> </tr> <tr> <td align="center"> <a style="font-size: 7pt" href="oferta.php3?show=lodowki"> <img src="gfx/lodowka.gif" alt="" border="0"><br> lodówki, zamra|arki </a> </td> </tr> <tr> <td align="center"> <a style="font-size: 7pt" href="oferta.php3?show=vhsdvd"> <img src="gfx/magnetowid.gif" alt="" border="0"><br> magnetowidy, odtwarzacze CD/DVD </a> </td> </tr> <tr> <td align="center"> <a style="font-size: 7pt" href="oferta.php3?show=kuchnie"> <img src="gfx/kuchnia.gif" alt="" border="0"><br> kuchnie </a> </td> </tr> <tr> <td align="center"> <a style="font-size: 7pt" href="oferta.php3?show=odkurzacze"> <br> odkurzacze </a> </td> </tr> </table> <br> <br> </td> <td width="610" valign="top" align="center"> <div align="center"> <table width="600" bgcolor="#e2b412" cellpadding="0" cellspacing="0" border="0"> <tr><td width="200" align="center" valign="baseline"> <form action="db.php3" method="post"> <strong>Potrzebujesz czego¶?</strong><BR> <input style="color: #1c36b3; background-color: #CCAC0C; font-size: 8pt; font-weight: 800;" type="Text" size="14" name="towar" style="width: 140px"> <br><br><input style="background-color: #1c36b3; color: #CCAC0C; font-size: 8pt; font-weight: 800;" type="Submit" value="Szukaj"> </form> </td> <td valign="top"> Mo|esz szuka korzystajc z symboli wieloznacznych:<br><br> <table cellpadding="0" cellspacing="0" border="0"> <tr><td width="250" valign="bottom"> <B>*</B> -zastpuje dowolny cig znaków<BR> <B>?</B> -zastpuje jeden znak</td> <td valign="bottom">Na przykBad:<B>telewizor*philips</B> <br> Bez wzgldu na wielko[ znaków.</td></tr></table> </td> </tr> </table> </div> 51 <br> <? // wyswietlamy konkretna _jedno_ lub _dwuwyrazowa_ kategorie // np. $pokaz='pralka ariston' if ($show == '') { include "inc/oferta.inc"; } else { if ($show == 'pralki' ) { include "inc/pralki.inc"; } if ($show == 'telewizory' ) { include "inc/tv.inc"; } if ($show == 'lodowki' ) { include "inc/lodowki.inc"; } if ($show == 'magnetofony' ) { include "inc/magnetofon.inc"; } if ($show == 'vhsdvd' ) { include "inc/vhsdvd.inc"; } if ($show == 'kuchnie' ) { include "inc/kuchnie.inc"; } if ($show == 'odkurzacze' ) { include "inc/odkurzacze.inc"; } } ?> <br> <br> <? include "inc/stopka.inc"; ?> </td></tr></table> </body></html> Podsumowaniem caBo[ci kodu jest fragment obsBugujcy przyjcie i zrealizowanie zamówienia. W obecnym stadium rozwoju sklepu jest to realizowane poprzez wysBanie przyjtych informacji poczt email do obsBugujcego pracownika. Trwaj prace nad skonstruowaniem wygodnego i sprawnego w dziaBaniu  koszyka obsBugujcego komplet czynno[ci zwizanych z realizacj zamówieD. Obecnie wykorzystywany formularz tak|e jest generowany dynamicznie przez skrypt napisany w PHP. Dane wprowadzane do formularza s sprawdzane. Testowane jest wypeBnienie wymaganych pól, niezbdnych do podjcia dalszych dziaBaD zwizanych z realizacja zamówienia. 52 53 Poni|szy rysunek przedstawia proces wprowadzania danych na stronie formularza, tu| po wybraniu odno[nika ukrytego pod postaci ikony koszyka sklepowego. Rysunek 10  Formularz realizacji zamówienia. CaBo[ realizowanych dziaBaD zwizanych ze zBo|eniem zamówienia wykonuje poni|szy kod. <? include "inc/meta.inc"; ?> <title>-x(AGD)x- .::EuroMarket - Video Tomex::. -x(RTV)x-</title> <script language="JavaScript"> function WinOpen(file) { window.open(file,'_blank','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resiz able=no,width=300,height=240'); } </script> <script language="JavaScript"><!-- function chBr(br, ver) { if (!(chBr.arguments.length > 0)) return (navigator.appName + ', ' + navigator.appVersion); var Browser = br; var Version = (chBr.arguments.length > 1) ? ver : null; var BrowserFlag = (navigator.appName.toLowerCase() == Browser.toLowerCase()) ? true : false; if (Version != null) { var VersionFlag = (navigator.appVersion.substring(0,1) == Version.substring(0,1)) ? true : false; } return (BrowserFlag || VersionFlag); } function openr(dokument) { 54 window.open(dokument,'parent[oferta]'); } // --></script> </head> <body> <? include "inc/menu.inc"; ?> <br> <div align="center"> <? if ( $wysylaj == 'tak' ) { $zamowienie = $towar + "\n" + $imie; $czas = date(H) . ":" . date(i) . ":" . date(s); mail("sklep@vt.pl", "Zamowienie - $towar", "Zamówienia dokonano z adresu: $REMOTE_ADDR -- godzina $czas\n\n Nowe zamowienie internetowe!\n\n Nazwa towaru: $towar\n Ilo[: $ilosc\n Cena brutto: $brutto\n Imi: $imie\n Nazwisko: $nazwisko\n Telefon: $telefon\n Ulica: $ulica\n Miejscowo[: $miejscowosc\n Województwo: $wojewodztwo\n Dochody: $dochody zB\n\n Dane firmy/instytucji:\n\n Nazwa firmy/instytucji: $nazwa_firmy\n NIP: $nip\n Regon: $regon\n\n Zamówienie nale|y zrealizowa w przeci±gu 24 godzin! :>" , "From: emarket@localhost"); ?> <br><br><br> <strong style="font-size: 15pt; font-weight: 900; color: ">Dzikujemy!!!</strong><br><br><br> <strong>Zamówienie zostaBo wysBane, w cigu 24 godzin skontaktujemy si w celu potwierdzenia zakupu.</strong> <br><br><br> <strong><a style="font-size:11pt" class="fade" href="http://vt.pl/index.php3?ID=05">Powrót do oferty</a></strong> <? } else { if ( $check == '' ) { ?> <table width="550" cellpadding="0" cellspacing="0" border="0"> <tr> <td align="center"> <strong style="font-size:14pt">Zamówienie: <strong style="color:#b32f1c"> <? echo $towar ?></strong></strong><br> <strong style="font-size:11pt">Cena netto: <strong style="color:#b32f1c"> <? echo $netto ?></strong></strong>&nbsp;&nbsp;&nbsp;<strong style="font-size:11pt"> Cena brutto: <strong style="color:#b32f1c"><? echo $brutto ?></strong></strong> <br><br> Przed wysBaniem zamówienia nale|y wypeBni poni|szy formularz. Po wysBaniu zamówienia w ci±gu 24 godzin skontaktujemy si z PaDstwem w celu potwierdzenia zamówienia. Pola, przy których znajduje si <strong style="color:#b32f1c">*</strong> s niezbdne i nale|y je wypeBni.<br> <br> <form action="zakup.php3?check=confirm" method="post"> <table cellpadding="4" cellspacing="4" border="0"> <tr> <td align="right"><strong>Towar<strong style="color:#b32f1c">*</strong></strong></td> <td align="left"><input disabled maxlength="40" type="Text" style="width:160" name="towar" value="<? echo $towar ?>"> </td> </tr> <tr> <td align="right"><strong>Ilo¶ (szt)<strong style="color:#b32f1c">*</strong></strong></td> <td align="left"><input maxlength="3" value="1" type="Text" style="width:30" name="ilosc"> </td> </tr> <tr> <td align="right"><strong>Imi<strong style="color:#b32f1c">*</strong></strong></td> <td align="left"><input maxlength="40" type="Text" style="width:160" name="imie"> </td> </tr> 55 <tr> <td align="right"><strong>Nazwisko<strong style="color:#b32f1c">*</strong></strong></td> <td align="left"><input maxlength="40" type="Text" style="width:160" name="nazwisko"> </td> </tr> <tr> <td align="right"><strong>Ulica/nr domu<strong style="color:#b32f1c">*</strong></strong></td> <td align="left"><input maxlength="40" type="Text" style="width:160" name="ulica"> </td> </tr> <tr> <td align="right"><strong>Miejscowo¶<strong style="color:#b32f1c">*</strong></strong></td> <td align="left"><input maxlength="40" type="Text" style="width:160" name="miejscowosc"> </td> </tr> <tr> <td align="right"><strong>Województwo</strong><strong style="color:#b32f1c">*</strong></td> <td align="left"> <select name="wojewodztwo" id="wojewodztwo" style="width: 150"> <option value="none">wybierz</option> <option value="zagranica">- zagranica -</option> <option value="doloslaskie">dolno[lskie</option> <option value="kujawsko-pomorskie">kujawsko-pomorskie</option> <option value="lubelskie">lubelskie</option> <option value="lubuskie">lubuskie</option> <option value="lodzkie">Bódzkie</option> <option value="malopolskie">maBopolskie</option> <option value="mazowieckie">mazowieckie</option> <option value="opolskie">opolskie</option> <option value="podkarpackie">podkarpackie</option> <option value="podlaskie">podlaskie</option> <option value="pomorskie">pomorskie</option> <option value="slaskie">[lskie</option> <option value="swietokrzyskie">[witokrzyskie</option> <option value="warmiDsko-mazurskie">warmiDsko-mazurskie</option> <option value="wielkopolskie">wielkopolskie</option> <option value="zachodniopomorskie">zachodniopomorskie</option> </select> </td> </tr> <tr> <td align="right"><strong>Telefon<strong style="color:#b32f1c">*</strong></strong></td> <td align="left"><input maxlength="40" type="Text" style="width:160" name="telefon"> </td> </tr> <tr> <td align="right"><strong>Dochody (zB)</strong></td> <td align="left"> <select name="dochody" id="dochody" style="width: 150"> <option value="none">wybierz</option> <option value="-700">&lt;&lt; 700</option> <option value="700-1400">700 - 1400</option> <option value="1400-2000">1400 - 2000</option> <option value="2000-3000">2000 - 3000</option> <option value="3000-">3000 &gt;&gt;</option> </select> </td> </tr> </table> </td></tr> </table> <br> Poni|sze dane nale|y wypeBni, je|eli produkt jest zamawiany przez firm lub instytucj. <table cellpadding="4" cellspacing="4" border="0"> <tr> <td align="right"><strong>Nazwa firmy<br>/instytucji</strong></td> <td align="left"><input maxlength="40" type="Text" style="width:160" name="nazwa_firmy"> </td> </tr> <tr> <td align="right"><strong>NIP</strong></td> <td align="left"><input maxlength="40" type="Text" style="width:160" name="nip"> </td> </tr> <tr> <td align="right"><strong>Regon</strong></td> <td align="left"><input maxlength="40" type="Text" style="width:160" name="regon"> </td> </tr> </table> <input type="Hidden" name="towar" value="<? echo $towar ?>"> </td> 56 <input type="Hidden" name="netto" value="<? echo $netto ?>"> </td> <input type="Hidden" name="brutto" value="<? echo $brutto ?>"> </td> <input type="Submit" value="Wy¶lij"> </form> <br><br> <? } if ( $check == 'confirm' ) { // Werykikacja; jezeli dane pole jest nie wypelnione zmienna $Zn przyjmuje // wartosc $Z(n-1) + 1 jezeli na koncu zmienna $Z =/= 0 wraca do formularza ?> <table cellpadding="2" cellspacing="2" border="0"> <tr> <td align="right"><strong>Towar</strong></td> <td align="left"><? echo $towar ?></td> </tr> <tr> <td align="right"><strong>Ilo[</strong></td> <td align="left"><? if ( $ilosc == '' ) { echo "<strong style=\"color:#b32f1c\">Nie wypeBniBe[ tego pola!</strong>"; $z1 = 1; } else { echo $ilosc; $z1 = 0; } ?> </td> </tr> <tr> <td align="right"><strong>Cena brutto</strong></td> <td align="left"><? echo $brutto;?> </td> </tr> <tr> <td align="right"><strong>Imi</strong></td> <td align="left"><? if ( $imie == '' ) { echo "<strong style=\"color:#b32f1c\">Nie wypeBniBe[ tego pola!</strong>"; $z2 = $z1 + 1; } else { echo $imie; $z2 = 0; } ?> </td> </tr> <tr> <td align="right"><strong>Nazwisko</strong></td> <td align="left"><? if ( $nazwisko == '' ) { echo "<strong style=\"color:#b32f1c\">Nie wypeBniBe[ tego pola!</strong>"; $z3 = $z2 + 1; } else { echo $nazwisko; $z3 = 0; } ?> </td> </tr> <tr> <td align="right"><strong>Ulica/nr domu</strong></td> <td align="left"><? if ( $ulica == '' ) { echo "<strong style=\"color:#b32f1c\">Nie wypeBniBe[ tego pola!</strong>"; $z4 = $z3 + 1; } else { echo $ulica; $z4 = 0; } ?> </td> </tr> <tr> <td align="right"><strong>Miejscowo[</strong></td> <td align="left"><? if ( $miejscowosc == '' ) { echo "<strong style=\"color:#b32f1c\">Nie wypeBniBe[ tego pola!</strong>"; 57 $z5 = $z4 + 1; } else { echo $miejscowosc; $z5 = 0; } ?> </td> </tr> <tr> <td align="right"><strong>Województwo</strong></td> <td align="left"><? if ( $wojewodztwo == '' ) { echo "<strong style=\"color:#b32f1c\">Nie wypeBniBe[ tego pola!</strong>"; $z6 = $z5 + 1; } else { echo $wojewodztwo; $z6 = 0; } ?> </td> </tr> <tr> <td align="right"><strong>Telefon</strong></td> <td align="left"><? if ( $telefon == '' ) { echo "<strong style=\"color:#b32f1c\">Nie wypeBniBe[ tego pola!</strong>"; $z7 = $z6 + 1; } else { echo $telefon; $z7 = 0; } ?> </td> </tr> <tr> <td align="right"><strong>Dochody (zB)</strong></td> <td align="left"><? if ( $dochody == '' ) { echo "<strong style=\"color:#b32f1c\">Nie wypeBniBe[ tego pola!</strong>"; $z8 = $z7 + 1; } else { echo $dochody . " zB"; $z8 = 0; } ?> </td> </tr> <tr> <td align="right"><strong>Nazwa firmy<br>/instytucji</strong></td> <td align="left"><? if ( $nazwa_firmy == '' ) { echo "brak"; } else { echo $nazwa_firmy; $z9 = 0; } ?></td> </tr> <tr> <td align="right"><strong>NIP</strong></td> <td align="left"><? if ( $nip == '' ) { echo "brak"; } else { echo $nip; $z10 = 0; } ?></td> </tr> <tr> <td align="right"><strong>Regon</strong></td> <td align="left"><? if ( $regon == '' ) { echo "brak"; } else { 58 echo $regon; $z10 = 0; } ?> </td> </tr> </table> <? // sprawdzam formularz $z = $z1 + $z2 + $z3 + $z4 + $z5 + $z6 + $z7 + $z8 + $z9 + $z10; // jezeli jest ok if ( $z == '0' ) { ?> <form action="zakup.php3?wysylaj=tak" method="post"> <input type="Hidden" name="towar" value="<? echo $towar ?>"> <input type="Hidden" name="ilosc" value="<? echo $ilosc ?>"> <input type="Hidden" name="brutto" value="<? echo $brutto ?>"> <input type="Hidden" name="imie" value="<? echo $imie ?>"> <input type="Hidden" name="nazwisko" value="<? echo $nazwisko ?>"> <input type="Hidden" name="ulica" value="<? echo $ulica ?>"> <input type="Hidden" name="miejscowosc" value="<? echo $miejscowosc ?>"> <input type="Hidden" name="wojewodztwo" value="<? echo $wojewodztwo ?>"> <input type="Hidden" name="telefon" value="<? echo $telefon ?>"> <input type="Hidden" name="dochody" value="<? echo $dochody ?>"> <input type="Hidden" name="nazwa_firmy" value="<? echo $nazwa_firmy ?>"> <input type="Hidden" name="nip" value="<? echo $nip ?>"> <input type="Hidden" name="regon" value="<? echo $regon ?>"> <input type="Submit" value="Zamawiam!"> </form> <? } else { ?> Wymagane pola nie zostaBy wypeBnione. Kliknij "Wstecz" aby to poprawi." <form action="javascript:history.back();"> <input type="Submit" value="&lt;&lt; Wstecz"> </form> <? } } else { exit; } } ?> <br> </div> </body> </html> 59 RozdziaB VI  KIERUNK I DALSZEJ ROZBUDOWY SKLEPU INTERNETOWEGO MODUA INFORMACJI DODATKOWYCH W trakcie realizacji projektu, w celu uatrakcyjnienia prezentowanych informacji, skonstruowano mechanizm przechowywania dodatkowych danych o towarach. Ma to na celu dostarczanie aktualnych danych technicznych oraz funkcjonalnych przegldajcym ofert internautom. Prezentowane wyniki wyszukiwania towarów uzupeBniono o odno[niki wywoBujce dodatkowe okno z prezentowanymi informacjami. Obecnie trwaj prace nad budow i udostpnieniem formularzy do rejestrowania tych informacji. Z zaBo|enia bd one wykorzystywane przez okre[lone dziaBy firmy do aktualizowania tych informacji oraz dostpne jedynie z wewntrz firmy. Informacje te obejmowa bd swoim zakresem dane szczegóBowe o towarze, odno[niki do dodatkowych informacji na stronach producentów sprztu a tak|e miniaturowe zdjcia towaru. Po klikniciu na miniaturowej fotografii produktu, system zaBaduje w osobnym oknie normalnej wielko[ci fotografi, rysunek, schemat a nawet film z przygotowan prezentacj. Poni|szy listing prezentuje kod realizujcy wygenerowanie okienka i wy[wietlenie tych informacji. <?php // obsluga info o towarze // parametry glowne include "inc/db.inc"; // meta include "inc/meta.inc"; // phpDB wrapper do baz danych, wkoncu to ma chodzic na wszystkim :) include "lib/phpDB.inc"; ?> <title>Opis towaru</title> </HEAD> <body> <br> <?php // czy mamy jave if (strpos($HTTP_USER_AGENT, "ozilla") >0) {$jestjava=TRUE;} else {$jestjava=FALSE;}; // sprawdzamy czy akurat trwa ladowanie danych do bazy // lamerskie, trzeba potem strugnac na lepsze if ( ! file_exists("/tmp/emarket.tmp")) { //$towar z brany jest z tresci zapytania przegladarki trzeba go dobrze wyfiltrowac potem !!! //trzeba oprogramowac wybor *? jak w dosie if ($indeks=="" or $indeks==" "){ echo "<SCRIPT LANGUAGE=\"JavaScript\">\n"; echo "<!--\n"; echo "alert('Nie poda¦e czego szukasz!')\n"; echo "history.back()\n"; echo "//-->\n"; echo "</SCRIPT>\n"; echo "<B>Nie poda¦e czego szukasz!</B><BR>"; echo "<A HREF=\"$powrot\">PowrÇt</A>\n"; exit;} 60 //jednorazowe stale i trwale polaczenie z baza $db=new phpDB(); $db->pconnect($db_host,$db_user,$db_pass,$db_name) or die("WystapiB bBd przy Bczeniu! <BR>\n "); // wersja zapytania po optymalizacji $sqlquery="SELECT * FROM informacje WHERE indeks=$indeks"; //echo $sqlquery . ";<BR><BR>\n"; $result = $db->execute($sqlquery) or die("WystpiB bBd przy zapytaniu. <BR>\n"); $numrows=$result->getNumOfRows(); $numfields=$result->getNumOfFields(); /* Wstepna struktura tabeli z informacjami  mo|e ulec zmianie w trakcie rozwoju modulu Table = informacje +----------------------------------+----------------------------------+-------+ | Field | Type | Length| +----------------------------------+----------------------------------+-------+ | indeks | int4 not null | 4 | | podtyp | int4 not null default '0' | 4 | | idpromocja | int4 not null default '0' | 4 | | pokaz | char() default 'N' | 1 | | skrot | varchar() default '' | 200 | | tytul | varchar() default '' | 80 | | opis | varchar() default '' | 4000 | | link1 | varchar() default '' | 80 | | link2 | varchar() default '' | 80 | | flagi | varchar() default '' | 80 | +----------------------------------+----------------------------------+-------+ */ if (strtoupper($result->fields["pokaz"])!="T") { echo "<div align=center><strong>Brak informacji dodatkowych o tym towarze.</strong></div>"; } else { echo "<div style=\"margin-left: 20px;\" align=left>"; echo "<div align=left><B>Informacje dodatkowe:</B></div><BR>\n"; echo "<TABLE cellpadding=0 cellspacing=0 border=0 width=550>\n"; echo "<TR>"; echo "<TD align=left valign=top height=1 width=100><B class=\"cena\">Nazwa:&nbsp;</B></TD>"; echo "<TD>" . $nazwa . "&nbsp;</TD>"; echo "</TR>\n"; echo "<TR>"; echo "<TD align=left valign=top height=1 width=100><B class=\"cena\">Tytul:&nbsp;</B></TD>"; echo "<TD valign=middle>" . $result->fields["tytul"] ."&nbsp;</TD>"; echo "</TR>\n"; echo "<TR>"; echo "<TD align=left valign=top height=1 width=100><B class=\"cena\">SkrÇt:&nbsp;</B></TD>"; echo "<TD valign=middle>" . $result->fields["skrot"] ."&nbsp;</TD>"; echo "</TR>\n"; echo "<TR>"; echo "<TD align=left valign=top height=1 width=100><B class=\"cena\">Opis:&nbsp;</B></TD>"; echo "<TD valign=middle>" . $result->fields["opis"] . "&nbsp;</TD>"; echo "</TR>\n"; echo "<TR>"; echo "<TD align=left valign=top height=1 width=100><B class=\"cena\">Link1:&nbsp;</B></TD>"; echo "<TD valign=middle>" . $result->fields["link1"] ."&nbsp;</TD>"; echo "</TR>\n"; echo "<TR>"; echo "<TD align=left valign=top height=1 width=100><B class=\"cena\">Link2:&nbsp;</B></TD>"; echo "<TD valign=middle>" . $result->fields["link2"] ."&nbsp;</TD>"; echo "</TR>\n"; echo "</TABLE>\n"; echo "</div>\n"; } //zwalniamy pamiec i zamykamy polaczenie z baza $result->close(); $db->close(); } //koniec warunku aktualizacji bazy else { // wlasnie trwa aktualizacja sql'a echo "<b style=\"color:#DB2614\">"; echo "Przepraszamy! <BR> WBa[nie trwa aktualizacja bazy danych.<BR>"; 61 echo "Prosz spróbowa ponownie za chwil...<BR><BR></b>"; }; echo "<br>\n"; if ($jestjava) { echo "<a href=\"javascript:window.close()\">zamknij...</a>\n";} else { echo "<a href=\"http://www.vt.pl/#szukaj\">powrÇt...</a>\n";}; ?> </body></html> KOSZYK NA TOWARY Chcc w sposób nowoczesny a zarazem wygodny udostpni klientom mo|liwo[ wirtualnego i swobodnego dodawania do koszyka i wyjmowania zamawianych towarów, opracowywany jest model wirtualnego koszyka na bazie mechanizmów utrzymywania sesji w PHP4. Zasad dziaBania tej metody jest utrzymywanie wirtualnej sesji staBego i trwaBego poBczenia, pomidzy aplikacj dziaBajc na serwerze a przegldark klienta. ProtokóB HTTP nie zostaB stworzony do tego celu i nie zapewnia trwaBego utrzymywania poBczenia. Po wysBaniu danych do przegldarki poBczenie jest zamykane przez serwer. Komplikuje to w znaczcym stopniu konstruowanie aplikacji wymagajcych trwaBo[ci nawizanych poBczeD. Wprowadzony mechanizm sesji pozwala na wysyBanie pewnych unikalnych danych do przegldarki a po ka|dej zmianie strony ich zwrotny odbiór. Pozwala to na jednoznaczne identyfikowanie klienta oraz dywersyfikacj zachowania aplikacji w zale|no[ci od kontekstu i u|ytkownika. Mechanizm sesji realizowany jest bdz przy u|yciu  ciasteczek (pliki  cookies ), bdz poprzez generowanie tzw.  dBugich adresów URL . PHP4 potrafi samoczynnie rozpozna czy przegldarka akceptuje przyjmowanie  cookies i w przypadku gdy to nie jest mo|liwe, przeBcza si na posBugiwanie dBugimi adresami. W celu utrzymywania takiej wirtualnej sesji konieczne jest otwarcie sesji i przekazywanie identyfikatora sesji pomidzy kolejnymi wywoBaniami stron aplikacji. Dane przypisane do sesji mog by przechowywane bdz w bazie danych SQL, bdz jako tymczasowe pliki na serwerze. Po zakoDczeniu sesji nale|y porzuci identyfikator sesji i usun przechowywane dane o sesji. Utrzymywanie sesji mo|na ustanowi na np. 30 minut w celu zachowania jeszcze przez pewien czas  trwaBo[ci zgromadzonych danych. Gdyby bowiem poBczenie z przegldark klienta mogBo by utracone na skutek bBdów sieci czy te| zawieszenia komputera itp. ponowne poBczenie z przegldarki z niewygasB sesj  natrafi na utrzymywan sesj po stronie serwera i pozwoli kontynuowa realizacj zakupów. Mechanizmy tu przedstawione s szczegóBowo opisywane w doskonaBej dokumentacji PHP4 (www.php.net/manual-lookup.php?pattern=session). 62 Podsumowanie Na podstawie do[wiadczeD zebranych podczas budowy aplikacji sklepu internetowego, mo|na z caB pewno[ci stwierdzi, i| na obecnym etapie rozwoju oprogramowania OpenSource jest mo|liwe szybkie i efektywne projektowanie oraz wdra|anie ró|nego rodzaju systemów i aplikacji sieciowych. Wysoka jako[ oprogramowania tworzonego przez spoBeczno[ internetow, gwarantuje zarówno dalszy efektywny rozwój tej idei darmowego tworzenia systemów, czy te| wrcz ustanawiania nowych standardów. Rozwój publicznie dostpnego oprogramowania umo|liwia samodzielne budowanie skomplikowanych serwisów internetowych, finansowych, naukowych czy rozrywkowych. Kod zródBowy jest powszechnie dostpny co doskonale wpBywa na szybko[ poprawiania znalezionych bBdów a tym samym na wysok jako[ tworzonych systemów. Dokumentacja tworzona na potrzeby rozwijanych narzdzi jest wysokiej jako[ci  zródBem niewyczerpanej wprost wiedzy. Projekt sklepu internetowego pocztkowo pomy[lany jako niewielki program promowania i sprzeda|y towarów, rozwija si szybko w kierunku caBego i skomplikowanego systemu, zapewniajcego nie tylko obsBug sprzeda|y online. Niejako  przy okazji powstaB caBy serwis internetowy firmy, rozwijane s moduBy realizowania zamówieD. W planach przewidziane jest skonstruowanie platformy wspóBpracy i wymiany towarowej pomidzy partnerami handlowymi. Korzystajc ze zbudowanego zaplecza informatycznego, wdro|ono systemy pocztowe, autoryzacji umów sprzeda|y ratalnej, natychmiastowej aktywacji telefonów PlusGSM i wiele innych. Zastosowane narzdzia pozwoliBy na znaczne oszczdno[ci i byBy ekonomicznie uzasadnionym rozwizaniem szczególnie polecanym dla firm sektora maBej i [redniej przedsibiorczo[ci. 63 Spis literatury [1] Fred Butzen, Dorothy Forbes,  Linux bazy danych Mikom 1999r [2] Hans Ladanyi,  SQL Ksiga eksperta Helion 2000r [3] W. Richard Stevens,  UNIX programowanie usBug sieciowych WNT 2000r [4] Vijay Ahuja,  BezpieczeDstwo w sieciach Mikom 1997r [5] Craig Hunt,  TCP/IP Administracja sieci READ ME 1998r [6] Æleen Frisch,  UNIX Administracja systemu READ ME 1997r [7] D. Brent Chapman, Elizabeth D. Zwicky,  Building Internet Firewalls O Reilly 1995r [8] S. Garfinkel, G. Spafford,  BezpieczeDstwo w UNIXie i Internecie READ ME 1997r [9] Bruce Momjian,  PostgreSQL Introduction and Concepts Addison-Wesley 2001r [10]  PHP Manual PHP Documentation Group 2001r [11]  FreeBSD Handbook The FreeBSD Documentation Project 2001r [12]  PostgreSQL Guide PostgreSQL Global Development Group 2001r 64 Streszczenie - Abstract Wy|sza SzkoBa Informatyki i Zarzdzania Rzeszów, 2001-07-12 WydziaB Administracyjno Informatyczny Streszczenie pracy dyplomowej licencjackiej Implementacja systemu sklepu internetowego na bazie oprogramowania OpenSource. Autor: BartBomiej Sibab Promotor: Dr in|. Janusz Zwierzowicz Implementacja projektu systemu sklepu internetowego przy wykorzystaniu narzdzi OpenSource. Zastosowano technologi generowania stron internetowych w oparciu o jzyk skryptowy PHP, JavaScript, HTML oraz style kaskadowe CSS. Dynamiczne pobieranie danych z bazy PostgreSQL umo|liwiBo zbudowanie efektywnego mechanizmu wyszukiwania i prezentowania towarów. University of Information Technology and Management Rzeszów, 2001-07-12 Faculty of Administration and Computer Sciences Diploma Thesis (BA) Abstract OpenSource based software implementation of internet shopping system. Author: BartBomiej Sibab Supervisor: Dr Eng. Janusz Zwierzowicz The purpose of this work was to implement Internet shopping system based on OpenSource software. Used technology allow dynamically produce HTML pages assembled with PHP, JavaScript and cascading style sheet (CSS) templates. Efficient database engine based on PostgreSQL and PHP persistent connections allows developing helpful search and presentation system. 65 Spis tre[ci WSTP ........................................................................................................................................................................ 2 CEL I ZAKRES PRACY ........................................................................................................................................... 3 ROZDZIAA I  ZAAO{ENIA WSTPNE, PRZEDSTAWIENIE METOD I NARZDZI................................ 4 UWARUNKOWANIA EKONOMICZNE........................................................................................................................... 4 PREZENTACJA BAZY SYSTEMOWEJ OPROGRAMOWANIA............................................................................................ 5 ROZDZIAA II  TEORIA I FUNKCJONOWANIE............................................................................................... 8 WYMAGANIA U{YTKOWNIKÓW ................................................................................................................................ 8 MARKETING I REKLAMA ........................................................................................................................................... 9 ZASADA DZIAAANIA................................................................................................................................................ 11 MODEL LOGICZNY I FUNKCJONALNY ...................................................................................................................... 12 ROZDZIAA III  PRZYGOTOWANIE DANYCH............................................................................................... 15 KONWERSJA DANYCH.............................................................................................................................................. 15 ARCHIWIZACJA I PRZESYAANIE DANYCH ................................................................................................................. 17 STRUKTURA KONWERTOWANYCH PLIKÓW ............................................................................................................. 18 KONWERSJA STRONY KODOWEJ.............................................................................................................................. 19 ZAAADOWANIE DANYCH DO BAZY POSTGRESQL ................................................................................................... 20 ROZDZIAA IV  STRUKTURA I ORGANIZACJA BAZY EMARKET .......................................................... 24 SKRYPTY ADMINISTRACYJNE.................................................................................................................................. 24 SKRYPTY SQL ........................................................................................................................................................ 29 Kategoria skryptów  create ........................................................................................................................... 29 Kategoria skryptów  delete ............................................................................................................................ 32 Kategoria skryptów  load .............................................................................................................................. 33 Kategoria skryptów  check ............................................................................................................................ 35 Kategoria skryptów  analysis ........................................................................................................................ 35 STRUKTURA BAZY .................................................................................................................................................. 36 ROZDZIAA V  WYSZUKIWARKA TOWARÓW ............................................................................................. 38 KONCEPCJA DZIAAANIA .......................................................................................................................................... 38 KOD yRÓDAOWY WYSZUKIWARKI........................................................................................................................... 42 ROZDZIAA VI  KIERUNKI DALSZEJ ROZBUDOWY SKLEPU INTERNETOWEGO ............................ 60 MODUA INFORMACJI DODATKOWYCH..................................................................................................................... 60 KOSZYK NA TOWARY.............................................................................................................................................. 62 PODSUMOWANIE .................................................................................................................................................. 63 SPIS LITERATURY................................................................................................................................................. 64 STRESZCZENIE - ABSTRACT............................................................................................................................. 65 SPIS TREZCI ............................................................................................................................................................ 66 66

Wyszukiwarka

Podobne podstrony:
praca dyplomowa serwer internetowy na linuxie
przykladowa praca dyplomowa dla grupy
Bezpieczeństwo systemňw komputerowych praca dyplomowa
7176525 Praca Dyplomowa Kontrukcje Drewniane
Jak napisac prace dyplomowa (praca dyplomowa, praca magisterska) (2)
Jak samodzielnie założyć sklep internetowy Witold Wrotek
praca dyplomowa inz
Sklep internetowy e 1oks
Budowa systemu ekspertowego (Praca dyplomowa)
Praca Dyplomowa Przegląd włókien naturalnych
Kreatywna praca dyplomowa Jak stworzyc fascynujacy tekst
Audyt wewnętrzny i kontrola finansowa (praca dyplomowa)

więcej podobnych podstron