Delphi i PHP

Transkrypt

Delphi i PHP
Technika
Delphi i PHP
Komunikacja
Pomiędzy Delphi i PHP można stworzyć własne aplikacje do komunikacji
pomiędzy tymi językami. Służy do tego metoda POST.
Dowiesz się...
Powinieneś wiedzieć...
• W jaki sposób odebrać dane ze skryptu.
• W jaki sposób wysłać dane do skryptu.
• Powinieneś znać podstawy języka i środowiska Delphi.
• Powinieneś znać podstawy języka PHP i HTML.
• Powinieneś znać podstawowe pojęcia związane z protokołem http.
Poziom trudności
S
posób komunikacji, opiera się na metodzie POST, która umożliwia wysyłanie
danych przy pomocy nagłówków HTTP.
Dane przesyłane tą metodą mają postać:
pole1=wartość&pole2=wartość2.
Tak więc: nazwa pola jest oddzielona od jego
wartości znakiem „=”, natomiast poszczególne
porcje danych oddziela znak „&”. Przykładowy
nagłówek z powyższymi informacjami wyglądałby więc tak, jak na Listingu 1.
Z Delphi do PHP
Zacznijmy projektować naszą aplikację, która
prześle dane do skryptu metodą POST . Uruchamiamy Delphi i z menu File wybieramy
New Application.
Po instalacji pakietu INDY w Delphi, przybędzie nam kilka nowych zakładek na palecie komponentów. Odszukajmy zakładkę Indy Clients i wybierzmy z niej komponent IdHTTP. To on umożliwi nam wysyłanie danych.
Umieścimy jeszcze następujące komponenty: 3x Edit, 4x Label, 1x Button, oraz 1x
Memo (wszystkie one znajdują się w zakładce Standard). Ich przykładowe rozmieszczenie, a także właściwości Caption jakie powin26
niśmy im nadać, zostały zaprezentowane na
Rysunku 1.
Po umieszczeniu wszystkich elementów,
kliknijmy tylko raz na komponent IdHTTP
i przejdźmy do Object Inspector’a, a następnie – odszukajmy listę Request. Po jej rozwinięciu ukaże się nam kilka atrybutów, interesować
nas będzie ten o nazwie ContentType. W to pole
musimy wpisać ciąg:
application/x-www-form-urlencoded.
Więcej o kodowaniu danych możemy przeczytać w ramce „Kodowanie danych”.
Pisanie kodu
Projektowanie aplikacji mamy już za sobą, czas
więc na napisanie kilku linijek kodu. Nasz program będzie miał za zadanie:
•
•
•
•
pobrać adres strony;
pobrać dwie zmienne do wysłania;
wysłać dane;
odebrać kod wynikowy.
Jego lista zadań jest krótka. Dzięki zastosowaniu komponentu IdHTTP, kod również będzie krótki. Kliknijmy dwa razy na Button’ie
i wpiszmy kod, który znajduje się na Listingu 2.
Przyjrzyjmy się linijce odpowiadającej za
utworzenie strumienia StreamIn, a szczególnie
fragmentowi:
(Format('text1=%s&text2=%s', [Edit2.Text,Ed
it3.Text])).
Jak pamiętamy, dane przesyłane metodą POST
mają postać:
pole1=wartość&pole2=wartość2.
Dlatego musimy je przesłać w taki sposób.
Nazwy pól: „text1” i „text2” są nazwami przykładowymi, które następnie zastosujemy
w skrypcie odbierającym dane. Należy pamiętać, że będą one różne dla każdej strony, która
odbiera pakiety z danymi.
Powyższa linijka tworzy ciąg powstały z połączenia tekstu w cudzysłowie, z tekstem wpisanym w Edit2 i Edit3. Owy ciąg jest następnie wysyłany do skryptu za pomocą funkcji
POST komponentu IdHTTP. Ostatnim krokiem będzie zapisanie i skompilowanie naszego projektu.
Gdy mamy już gotową aplikację, możemy stworzyć najprostszy plik PHP, który posłuży nam do jej testowania. Propozycja kodu znajduje się na Listingu 3. W skrypcie,
dla ułatwienia, zostały zastosowane zmienne o takich samych nazwach, jak w naszym
programie.
Po zapisaniu pliku PHP i umieszczeniu go
na serwerze, uruchamiamy naszą aplikację, podajemy odpowiednie parametry i naciskamy
przycisk POST. Pole tekstowe „Memo” podpisane jako „Kod wynikowy” zostanie automatycznie uzupełnione danymi zwróconymi przez
skrypt. Przedstawia to Rysunek 2.
Listing 1. Przykładowy nagłówek z danymi
wysłanymi metodą POST
POST /index.php HTTP/1.1
Host: www.domena.com
User-Agent: Mozilla/5.0
Content-Length: 28
Content-Type: application/x-www-formurlencoded
pole1=wartość&pole2=wartość2
06/2007
Delphi i PHP
Listing 2. Wysyłanie danych z aplikacji do skryptu metodą POST
procedure TForm1.Button1Click(Sender: TObject);
var
StreamIn,StreamOut: TStringStream;
begin
try
{Tworzymy strumień StreamIn zawierający łańcuch danych,
zostanie on potem wysłany do skryptu}
StreamIn := TStringStream.Create(Format('text1=%s&text2=%s', [Edit2.Text,Edit3.Text]
));
{Tworzymy pusty strumień
StreamOut. Będzie on odpowiedzialny
za odbiór kodu wynikowego skryptu}
StreamOut := TStringStream.Create('');
{Procedura POST komponentu IdHTTP i jej kolejne parametry:
Adres URL, strumień z danymi, strumień odbierający}
IdHTTP1.Post(Edit1.Text,StreamIn,StreamOut);
{Wyświetlamy kod wynikowy ze strumienia w Memo}
Memo1.Lines.Text:=StreamOut.DataString;
finally
{Zwalniamy strumienie}
StreamIn.Free;
StreamOut.Free;
end;
end;
Listing 3. Odbieranie danych z aplikacji wysłanych metodą POST
<?php
$text1=$_POST['text1'];
$text2=$_POST['text2'];
echo "Zmienna \"text1\" to: $text1\n"; //wyświetlamy zmienną „text1”
echo "Zmienna \"text2\" to: $text2\n"; //wyświetlamy zmienną „text2”
?>
Przykładowe zastosowanie
Przykładowym zastosowaniem powyższej
metody komunikacji może być program, który będzie uploadował wybrane obrazy z naszego dysku twardego na darmowy hosting
zdjęć ImageShack (dostępny pod adresem
www.imageshack.us). Zaczniemy od małego
rekonesansu, tak więc otwieramy ową stronę. Aby uniknąć żmudnej analizy kodu w
celu „wydobycia” szczegółów, skorzystajmy
z wtyczki do Firefox’a pod nazwą Web Developer (link znajduje się w ramce „W Sieci”). Posiada ona funkcję, która modyfikuje wyświetlaną stronę pokazując, na przykład, szczegóły formularzy. Zostało to pokazane na Rysunku 3.
Co na nim widzimy? Po pierwsze – formularz odwołuje się do strony głównej ImageShack.us (fragment form action=””), po
drugie- format kodowania danych to multipart/
form-data (fragment enctype=””), i wreszcie po
trzecie- pole, z którego pobierana jest ścieżka do wysyłanego pliku (input name="fileupload”). Posiadając te informacje możemy rozpocząć projektowanie aplikacji.
Przykładowa aplikacja
Zacznijmy od stworzenia nowego projektu. Potrzebne nam będą komponenty: 1x
Edit, 1x Memo, 1x button, a także komponent
IdHTTP.
Podobnie jak ostatnio – kliknijmy raz na
komponent IdHTTP i przejdźmy do Object
Inspector’a , a następnie – odszukajmy listę Request. Po jej rozwinięciu ukaże nam się
kilka atrybutów; interesować nas będzie ten
o nazwie ContentType. W to pole musimy wpisać ciąg:
multipart/form-data.
Rysunek 3. Wtyczka Web Developer wyświetlająca szczegóły formularza na stronie ImageShack.us
Teraz, kliknijmy dwa razy na komponent Button, i w edytorze kodu wpiszmy fragment
z Listingu 4. Jak widać została tam zawarta
zmienna MyData typu TIdMultiPartFormDataStream. Jest to specyficzny typ strumienia
Rysunek 1. Przykładowe rozmieszczenie komponentów. Z lewej strony – komponenty ze standardowymi
właściwościami Caption, natomiast z prawej – komponenty posiadające zmodyfikowaną tę właściwość
Rysunek 2. Gotowa aplikacja wysyłająca dane do
skryptu
www.phpsolmag.org
27
Technika
z danymi, którego implementacja konieczna
jest do wysłania danych, zakodowanych w formacie multipart/form-data. Aby z niego skorzystać, konieczne jest dodanie do sekcji Uses modułu IdMultipartFormData. Jest on dołączony
do pakietu INDY. Po kompilacji projektu należy w pole Edit wpisać ścieżkę obrazu, który chcemy uploadować, a następnie nacisnąć
przycisk Button.
Zachęcam do przejrzenia kodów źródłowych, które zostały dołączone do płyty. Do
aplikacji dodałem również parser, który pobiera z kodu wynikowego linki do naszego
obrazu, ale to temat na inny artykuł. Przykład działania aplikacji pokazany jest na Rysunku 4.
Z PHP do Delphi...
Teraz nadszedł czas na napisanie programu,
który będzie umożliwiał odbieranie zmiennych wysyłanych przez skrypt.
Stworzymy nową aplikację i na formie
umieścimy komponenty: 2x Label, 1x Edit
oraz 2x Memo (wszystkie one znajdują się w
zakładce Standard). Ostatnio użyliśmy komponentu, który był klientem protokołu HTTP.
Pisząc tę aplikację, będziemy musieli stworzyć serwer HTTP. Odszukajmy więc zakładkę Indy Servers i wybierzmy z niej komponent
IdHTTPServer. Ich przykładowe rozmieszczenie, a także właściwości Caption jakie powinniśmy im nadać, zostały zaprezentowane na
Rysunku 5.
Pisanie kodu
Przyszedł czas na oprogramowanie naszej aplikacji. Zacznijmy od aktywacji serwera- klikamy
na formie i odszukujemy właściwość OnCreate na zakładce Events w oknie Object Inspector
i wpisujemy tam fragment kodu z Listingu 5.
podpisanego jako:
{Procedura OnCreate}.
Deaktywacja serwera odbywać się będzie podczas zamykania programu, więc w zdarzenie
Listing 4. Wysyłanie danych z aplikacji do strony ImageShack
procedure TForm1.Button1Click(Sender: TObject);
var
MyData: TIdMultiPartFormDataStream;
begin
{tworzymy specyficzny strumień z danymi}
MyData:=TIdMultiPartFormDataStream.Create;
try
{kolejny krok to dodanie do strumienia, metodą AddFile, kolejno:
nazwy pola (fileupload),ścieżki pliku, a także typu zawartości
pakietu z danymi(file)}
MyData.AddFile('fileupload',Edit1.Text,'file');
{kod wynikowy zostanie wyświetlony w Memo1}
Memo1.Lines.Text:=IdHTTP1.Post('http://imageshack.us/',MyData);
finally
{Zwalniamy strumień}
MyData.Free;
end;
end;
Listing 5. Aktywacja i deaktywacja serwera IdHTTPServer1
{Procedura OnCreate}
procedure TForm1.FormCreate(Sender: TObject);
OnClose naszej formy, wpiszemy ponownie
kod z Listingu 5. który tym razem jest opisany jako:
{Procedura OnClose}.
Główne zdarzenia zostały już napisane, czas
teraz na kod, który umożliwi odbieranie danych. Klikamy na komponent IdHTTPServer1
i przechodzimy do Object Inspector. Odszukujemy Event podpisany jako OnCommandGet i wpisujemy kod z Listingu 6.
Aplikacja jest już gotowa, możemy ją zapisać i skompilować. Podobnie jak wcześniej,
stworzymy jeszcze plik PHP, z tym, że teraz to on będzie wysyłał dane do serwera.
W tym celu posłużymy się najprostszym formularzem, którego propozycja kodu znajduje się na Listingu 7. Pamiętajmy, że nasz program działa na porcie 8008 (aby uniknąć kolizji z innymi aplikacjami), więc będziemy
odwoływać się do niego w następujący sposób http://AdresIP:NumerPortu, czyli http://
localhost:8008.
Teraz musimy jeszcze uruchomić nasz program i wypełnić pola formularza, a następnie
go zatwierdzić. Wynik działania aplikacji, która
odebrała parametry i zwróciła wynik do przeglądarki znajduje się na Rysunku 6.
Przykładowe zastosowanie
Powyższy sposób komunikacji może być wykorzystany- np. do zdalnej administracji komputerem poprzez stronę WWW.
Wg definicji serwera aplikacji jest to „program działający na zdalnej maszynie obsługujący żądania kierowane do aplikacji, do której
dostęp zapewnia. Użytkownik łączy się za pośrednictwem przeglądarki internetowej, kieruje żądanie do wybranej aplikacji, a całość operacji odbywa się po stronie komputera należącego do organizacji, która udostępnia daną
aplikację.”(pl.wikipedia.org).Zastanówmy się najpierw nad ogólną koncepcją naszej aplikacji – zarówno klienta jak i serwera. Klient –
w tym przypadku strona WWW – powinien
zawierać pola: „Login” oraz „Hasło”, aby naszego zdalnego systemu nie mogły przechwycić
begin
{Ustawiamy numer portu dla serwera}
IdHTTPServer1.DefaultPort := 8008;
{aktywujemy serwer}
IdHTTPServer1.Active:=True;
end;
{- - -}
{procedura OnClose}
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
{dezaktywujemy serwer}
IdHTTPServer1.Active:=False;
end;
{- - -}
28
Kodowanie danych
Jeżeli chcemy wysłać dane do serwera zawierające elementy formularza, to muszą
one wcześniej zostać zakodowane. Kodowanie application/x-www-form-urlencoded
jest kodowaniem domyślnym, które przeglądarka wysyła do skryptu; używamy go
do wysyłania małych ilości informacji. Nie
sprawdza się ono jednak podczas wysyłania dużych ilości danych binarnych lub rozległego tekstu. Do tego celu należy użyć kodowania multipart/form-data.
Niezależnie od tego, na jakie kodowanie się zdecydujemy, musimy pamiętać o jego implementacji w naszym programie.
06/2007
Delphi i PHP
niepowołane osoby, a także kilka opcji wyboru, które będą reprezentowały możliwe do wykonania funkcje przez zdalny system. Po wybraniu opcji „Wyślij”, skrypt wyśle parametry
do aplikacji – serwera.
Serwer natomiast, po odbiorze porcji danych, powinien mieć możliwość ich walidacji, w tym danych użytkownika (jego nazwy oraz hasła), który chce skorzystać z jego
usług, a także oczywiście mieć możliwość wykonania żądanego polecenia. Po jego wykonaniu serwer powinien zwrócić wynik, następnie wszystkie operacje powinny być zapisywane w logach.
Listing 6. Odbieranie danych przez aplikację
procedure TForm1.IdHTTPServer1CommandGet(AThread: TIdPeerThread;
ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
StrResult: String;
begin
{w Memo zostaną umieszczone żądania (request server)}
Memo1.Lines.Add(ARequestInfo.Document);
{tworzymy kod wynikowy dla przeglądarki}
StrResult := '<h1>Testowa strona serwera.</h1>'
+'<b>Odebrane dane:</b>'
{ARequestInfo.Host zawiera informacje o hoście użytkownika...}
+ '<p>Host: ' + ARequestInfo.Host + '</p>'
{...natomiast ARequestInfo.UnparsedParams wyświetla parametry
przekazane do naszego serwera}
+ '<p>Parametry: ' + ARequestInfo.UnparsedParams + '</p>';
{wyświetlamy w przeglądarce stworzony łańcuch}
AResponseInfo.ContentText := StrResult;
{do Edit1 dodajemy parametry przekazane do serwera}
Edit1.Text:=ARequestInfo.UnparsedParams;
end;
Listing 7. Formularz wysyłający zmienne metodą POST do aplikacji
<html>
<!--implementacja formularza: odwołuje się on do „http://localhost:8008” i przesyła
dane metodą „POST”-->
<form action="http://localhost:8008" method="post">
<label for="login">Login: </label>
<br />
Rysunek 4. Gotowa aplikacja wysyłająca
obrazy na hosting ImageShack.us i parsująca kod
wynikowy
<input name="login" type="text">
<br />
<label for="password">Password: </label>
<br />
<input name="password" type="password">
<br />
<input value="GO!" type="submit">
</form>
</html>
Rysunek 5. Przykładowe rozmieszczenie
komponentów. Z góry: komponenty
ze standardowymi właściwościami Caption,
natomiast u dołu: komponenty posiadające
zmodyfikowaną tą właściwość
Listing 8. Przykładowa aplikacja klienta
<html>
<form action="http://localhost:8008" method="post">
<label for="login"><b>Login</b></label>
<br />
<input name="login" type="text" value="" style="width: 300px" />
<br />
<label for="pass"><b>Hasło</b></label>
<br />
<input name="pass" type="text" value="" style="width: 300px" />
<br />
<label><b>Polecenie</b></label>
Rysunek 6. Gotowa aplikacja odbierająca dane
od skryptu
<br />
<input type="radio" name="opcje" value="shutdown" checked/>Wyłącz zdalny komputer
<br />
<input type="radio" name="opcje" value="message"/>Wyślij wiadomość:
<br />
<textarea name="wiadomość" style="width: 300px; height: 150px"></textarea>
<br />
<input type="submit" name="submit" value="Wyślij">
</form>
</html>
Rysunek 7. Zarządzanie komputerem z poziomu
przeglądarki
www.phpsolmag.org
29
Technika
Listing 9. Odbieranie danych przez aplikację i wykonywanie żądanych poleceń
procedure TForm1.IdHTTPServer1CommandGet(AThread: TIdPeerThread;
ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
W Sieci
•
StrResult: String;
•
•
begin
•
login,pass,autoryzacja: boolean;
http://www.codegear.com/downloads/
free/delphi
http://www.indyproject.org/
https://addons.mozilla.org/pl/firefox/
addon/60
http://www.4programmers.net
{w Memo zostaną umieszczone żądania (request server)}
Memo1.Lines.Add(ARequestInfo.Document);
{do logów dodajemy parametry przekazane do serwera}
Memo1.Lines.Add('Odebrane parametry:');
Memo1.Lines.Add(ARequestInfo.Params.Text);
{walidacja danych:}
{czy login (parametr 0) jest poprawny?}
if ARequestInfo.Params[0]='login=admin'
then login:=True else login:=False;
{czy hasło (parametr 1) jest poprawne?}
if ARequestInfo.Params[1]='pass=password'
then pass:=True else pass:=False;
{identyfikacja}
if (login and pass) then autoryzacja:=True
else autoryzacja:=False;
{wypisujemy kod wynikowy}
StrResult := '<b>Odebrane dane:</b>'
+ '<p>Autoryzacja loginu: ' + BoolToStr(login,True) + '</p>'
+ '<p>Autoryzacja hasła: ' + BoolToStr(pass,True) + '</p>'
+ '<p>Wykonanie polecenia: ' + BoolToStr(autoryzacja,True) + '</p>';
AResponseInfo.ContentText := StrResult;
{zwracamy informację do przeglądarki}
AResponseInfo.WriteContent;
{sprawdzenie polecenia}
if ((ARequestInfo.Params[2]='opcje=message') and autoryzacja)
then
ShowMessage(StringReplace(ARequestInfo.Params[3],'wiadomość=','',[]))
else
if ((ARequestInfo.Params[2]='opcje=shutdown') and autoryzacja)
then
{wywołanie cmd.exe z parametrem shutdown- zamykamy system}
ShellExecute(Handle,'open','cmd.exe','/c shutdown /s','C:',SW_HIDE)
else
end;
30
Projekt klienta
Projekt serwera
Pierwszym krokiem będzie stworzenie strony WWW, której funkcją będzie wysyłanie pakietów z danymi do naszej aplikacji. Opierać
się ona będzie na prostym formularzu, którego kod został zaprezentowany na Listingu 8.
Podobnie jak poprzednio, będziemy korzystać
z portu numer 8008. Jeżeli zamierzamy korzystać z aplikacji, z innego komputera niż localhost, niekiedy wymagane będzie odblokowanie
tego portu na firewall’u.
Przyjrzyjmy się Listingowi 8. Jak widać, zostały w nim zawarte planowane pola: Login oraz
Hasło, a także pola typu „Radio”, które reprezentują możliwe do wykonania zadania. Dla
przykładu umieściłem dwa: możliwość wyłączenia zdalnego komputera, a także opcję wyświetlenia na nim wiadomości. Skoro ten etap
mamy już za sobą możemy przejść do projektowania serwera.
Projekt serwera w dużej mierze opierać będzie się na aplikacji zaprezentowanej na początku obecnego rozdziału. Śmiało możemy
otworzyć tamten projekt i zacząć go modyfikować.
Zacznijmy od usunięcia Label-u podpisanego jako „Odebrane parametry”, a także
komponentu Edit1. Nie będą one nam już
potrzebne.
Następnie, tak jak poprzednio, klikamy na
komponent IdHTTPServer1 i przechodzimy do
Object Inspector’a. Odszukujemy Event podpisany jako OnCommandGet i wpisujemy kod
z Listingu 9. Pozostałe procedury projektu pozostawiamy bez zmian.
Procedura OnCommandGet, którą przed
chwilą wpisaliśmy, zawiera przykładowe polecenie zamykające system- w tym wypadku posłużyliśmy się funkcją ShellExecute, tak
więc do sekcji Uses musimy dodać moduł
ShellAPI.
Sam kod nie jest trudny do zrozumienia, został on oczywiście opatrzony komentarzami,
dlatego zachęcam do jego przejrzenia. Przyjrzyjmy się fragmentowi odpowiedzialnemu za
walidację danych.
Zmienna ARequestInfo.Params[index] zawiera kolejne parametry, do których możemy odwoływać się po ich indeksie. Nasz skrypt, który
pisaliśmy wcześniej, wysyła kolejno porcje danych: login, będący parametrem zerowym, hasło, będące parametrem pierwszym, i tak dalej. Ważna jest kolejność, jaką zachowujemy.
Wysyłając najpierw hasło, a dopiero potem login do serwera- automatycznie zmieniamy ich
indeksy, co powoduje, że dane nie przechodzą
walidacji.
Możemy oczywiście skorzystać na przykład z
instrukcji for...to i sprawdzać po kolei wszystkie
odebrane skrypty, jednakże, przy tak małej ilości danych nie jest to konieczne.
Wynik działania
Proces tworzenia aplikacji, zarówno serwera jak i klienta, mamy już za sobą. Teraz nadszedł czas na przyjrzenie się rezultatom ich
działania.
Tak więc: uruchamiamy nasze aplikacje- serwer i stronę z formularzem. Wypełniamy podane pola (niekoniecznie poprawnie, aby zobaczyć, czy wszystko działa tak jak należy) i wysyłamy dane. Przykład działania aplikacji pokazany jest na Rysunku 7.
Podsumowanie
Mój niewielki artykuł opisuje tylko wierzchołek góry lodowej, jaką jest pakiet INDY.
Dla jego potrzeb wykorzystałem zaledwie
dwa komponenty z ponad ich stuelementowej kolekcji. Pamiętaj, że „teoria śni, praktyka uczy”. W momencie, gdy sam stworzysz
i przeanalizujesz aplikacje, zmodyfikujesz
ich kody i prześledzisz działanie, będziesz
mógł w pełni zrozumieć zagadnienia, które
nimi kierują.
ARTUR CHUDZIK
Autor w wolnych chwilach zajmuje się programowaniem, a także administracją portalem WebHat.pl, którego jest założycielem. Obecnie uczy się
w drugiej klasie 1LO w Łańcucie.
Kontakt z autorem: [email protected]
06/2007

Podobne dokumenty