Komunikacja PHP i C Sharp

Ostatnio musiałem napisać aplikację w której aplikacja .Net współpracuje z aplikacją napisaną w PHP za pośrednictwem gołego http.

Sprawa nie jest szczególnie złożona jednak jak się później okazało nie jest taka prosta jak myślałem. Fragmenty kodu zawarte w Blogu pochodzą z przykładowego programu dostępnego do pobrania na końcu postu.

To co było proste:

Komunikacja PHP z dowolną inną platformą odbywa się za pomocą protokołu HTTP który jest ogólnie dobrze opisany np. tutaj. Dodatkowo w większości platform istnieją dedykowane biblioteki obsługujące w mniejszym lub większym stopniu komunikację przez http, a biblioteka standardowa .Net nie jest pod tym względem wyjątkiem(tfu!).

Komunikację za pomocą http ułatwiają przynajmniej dwie klasy HttpWebRequest i WebClient. Klasa WebClient ma w moim mniemaniu znacznie bardziej intuicyjny interfejs i to jej będę się starał używać.

Wywołanie GET:

Wywołanie GET jest odwołaniem się do strony www równoważnym z wpisaniem adresu w przeglądarce internetowej, parametry do serwera wysyła się dopisując po adresie strony znak zapytania i wartości tych parametrów w formacie parametr1=wartosc1&parametr2=wartosc2&parametr3=wartosc3. Ograniczeniem tej metody jest fakt iż długość adresu strony wraz z wartościami parametrów nie może przekraczać 256znaków.

Metody tej nie powinno się także stosować na stronach w celu przekazywania danych wrażliwych (jak np. login i hasło użytkownika).

Do zbudowania łańcucha połączeniowego można użyć klasy UriBuilder, jest to klasa która na podstawie fragmentów adresu potrafi złożyć pełną ścieżkę do pliku/katalogu także na serwerze www.

Klasą która się przydaje jest także HttpUtility posiadająca metodę UrlEncode zwalniającą programistę z wstawiania odpowiednich znaków ucieczki w wysyłanym zapytaniu do serwera, niestety klasa ta znajduje się w przestrzeni nazw System.Web w bibliotece o tej samej nazwie, biblioteka ta zaś nie znajduje się w Wersji Client Profile platformy .Net. Tak więc jeżeli klasy tej chcemy użyć w projekcie Windows Forms lub WPF musimy dokonać następujących zmian w projekcie:

1) Zapisanie wszystkich niezapisanych plików.

2) W Solution Explorze klikamy prawym przyciskiem myszy na projekt i wybieramy Properties

3) W zakładce Application znajdujemy Combobox Target platform i wybieramy w nim .Net Framework 4.0

4) Zapisujemy wszysto i zamykamy właściwości projektu

5) Klikamy prawym przyciskiem w katalog refereces w projekcie i wybieramy AddReference

6) Przechodzimy na zakładkę .Net i wybieramy System.Web

7) Zatwierdzamy dialog i możemy używać klasy System.Web.HttpUtility

Najprostszy kod pobierający treść strony www może wyglądać tak.

WebClient client = new WebClient();
// Przy niektórych serwerach aplikacja powinna się przedstawić 
//client.Headers.Add("user-agent", "PHP and dotNet");

UriBuilder queryBuilder = new UriBuilder(tbServer.Text + "helloGet.php");
queryBuilder.Query = string.Format("name={0}", HttpUtility.UrlEncode(tbName.Text));

string result = client.DownloadString(queryBuilder.Uri);
MessageBox.Show(this, result);

plik helloGet.php zawiera chyba najprostrzą możliwą obsługę zapytania GET:

<?php
echo 'Witaj '.$_GET['name'];
?>

Pobranie plików z serwera:

Zadanie trochę mniej związane z PHP, aczkolwiek pojawiające się w pracy z http to pobranie pliku z serwera http. Tutaj klasa WebClient oferuje dwie możliwości.

Metoda DownloadFile podaje się adres pliku i nazwę pliku nic prostszego

using (SaveFileDialog sfd = new SaveFileDialog())
{
    sfd.Filter = "Pliki jpeg|*.jpg";
    if (sfd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
    {
        WebClient client = new WebClient();
        client.DownloadFile("http://www.programy.witraze-plocin.pl/wp-content/uploads/2010/04/cycki226jo5.jpg", sfd.FileName);
    }
}

Metoda DownloadData zwraca tablicę bajtów składających się na plik metoda może być przydatna gdy pobrane dane chcemy tylko obrobić bez zapisywania ich na dysku. Np. wyświetlić obrazek w pictureBoxie.

WebClient client = new WebClient();
byte[] buffer = client.DownloadData("http://www.programy.witraze-plocin.pl/wp-content/uploads/2010/04/cycki226jo5.jpg");

MemoryStream stream = new MemoryStream(buffer);

// Kwestie techniczne
if (pbCycki.Image != null)
{
    Image oldImage = pbCycki.Image;
    pbCycki.Image = null;
    oldImage.Dispose();
}

pbCycki.Image = Image.FromStream(stream);

Wadą tej metody jest spore zajęcie pamięci ponieważ cały plik jest wgrywany do RAMu, dodatkowo aplikacja musi pobrać cały plik i dopiero wtedy go obrobić. Przypadkiem gdy żadna z powyższych metod nie zastosowania jest pobranie dużego pliku z serwera i zapisanie go do strumienia nie będącego plikiem(np. wysłać portem COM do jakiegoś urządzenia). W tym przypadku należy wykorzystać metodę WebRequest.

private void FromHttpToStream(Stream outStream, string url)
{
    WebClient client = new WebClient();
    client.OpenRead(url).CopyTo(outStream);
}

Wywołanie POST:

Wysłanie zapytania POST do serwera http przy pomocy klasy HttpClient jest dosyć niskopoziomowe. Ponieważ należy wykonać następujące kroki:

1) Dodać do nagłówka wiadomości informację o rodzaju przesyłanej treści "content-type: application/x-www-form-urlencoded"

2) Sformatować treść wysyłanej wiadomości przy UrlEncode

3) Zakodować informację przy pomocy kodowania ASCII i wysłać na serwer.

4) Rozkodować przesłaną wiadomość przy pomocy kodowania użytego na stronie.

WebClient client = new WebClient();
// Przy niektórych serwerach aplikacja powinna się przedstawić 
//client.Headers.Add("user-agent", "PHP and dotNet");

client.Headers.Add("Content-Type", "application/x-www-form-urlencoded");

byte[] buffer = Encoding.ASCII.GetBytes(string.Format("name={0}", HttpUtility.UrlEncode(tbName.Text)));
buffer = client.UploadData(tbServer.Text + "helloPost.php", "POST", buffer);
string result = Encoding.UTF8.GetString(buffer, 0, buffer.Length);
MessageBox.Show(this, result);

Upload plików:

Upload plików też jest dość prosty klasa WebClient posiada metodę UploadFile, która jako parametry pobiera nazwę wysyłanego pliku i adres pliku do którego wysyłana jest zawartość pliku.

using (OpenFileDialog ofd = new OpenFileDialog())
{
    ofd.Filter = "Pliki jpeg|*jpg";
    if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
    {
        WebClient client = new WebClient();
        client.UploadFile(tbServer.Text + "uploadFile.php", ofd.FileName);
    }
}

Po stronie serwera wysyłany plik jest opisany w tabeli $_FILES w polu 'file' obsługa pliku. Przykładowa obsługa może wyglądać następująco:

<?php
$tempFile = $_FILES['file']['tmp_name'];
copy($tempFile, 'uploaded.jpg');
unlink($tempFile);
?>

Pliki z kodem przykładowego programu są do pobrania tutaj.

3 odpowiedzi do “Komunikacja PHP i C Sharp”

  1. hej,

    można by też „cycki” wysłać z php do c#(.net) przez wcf (soap). Smiga ładnie i szybko a obsługa w php dość wysokopoziomowa:
    $client = new SoapClient(’http://serwer.pl/soap/Service1.svc?wsdl’);
    $obj->value=”pamela”;
    print_r($client->GetCycki($obj));

    gdzie GetCycki to metoda z kontraktu wcf

    pozdrawiam

  2. O SOAP'ie (dokladnie nuSoapie) napiszę nie długo jednak będę opisywał komunikację javaME >-< PHP i SOAP.

Możliwość komentowania jest wyłączona.