\n\n
\n

To wszystko oczywiście tylko pobieżny przykład, ale jak widać wystarcza do działania, a dzięki swojej prostocie nie będzie trudno go rozbudować o taką funkcjonalność, jaka będzie potrzebna. Polecam chociażby zainteresowanie się klasą GMarker, dzięki której możemy wstawiać na naszą mapkę informacje o zaznaczonych punktach.

","publishedAt":"2009-06-05T06:12:41Z","view":"views/sites/display/blog.xhtml","url":null,"commentingEnabled":true,"category":{"name":"Blog","slug":"blog","view":"views/sites/list/blog.xhtml","siteView":"views/sites/display/blog.xhtml"},"tags":[{"name":"Web","slug":"web"},{"name":"JavaScript","slug":"javascript"},{"name":"Tutorial","slug":"tutorial"},{"name":"Google","slug":"google"}]},{"name":"Od podstaw: XML","slug":"od-podstaw-xml","content":"

XML

\n

XML to \"rozszerzalny język znaczników\" (ang. eXtensible Markup Language). Oznacza to, że jest to język uniwersalny przeznaczony do tworzenia języków oznaczeń - sam w sobie jest jedynie zbiorem zasad składni, definiuje pewne mechanizmy rządzące dokumentem, nie definiuje za to żadnych znaczników ani atrybutów. Innymi słowy XML określa jedynie format zapisu, a nie format samych danych. Robią to dopiero języki oparte na XML-u takie jak XHTML, RSS i wiele innych. Sam XML jest pochodnym SGML, a ten z kolei wywodzi się z GML. Nie będę ich tutaj omawiał, jednak ich idea jest podobna. Zostały one opracowane w celu przechowywania i współdzielenia dokumentów w jednolity sposób na przestrzeni lat. XML jest w gruncie rzeczy uproszczoną wersją SGML - ogranicza jego implementacje tylko do domyślnej składni, ujednolica wiele zagadnień (jak chociażby \"puste\" tagi). O XML-u pewnie obiło się wielu osobą o uszy, często jednak nie zdają sobie sprawy jak ważne są niektóre jego aspekty. Widać to chociażby w przypadku stron WWW tworzonych w tej technologii (korzystając z języka XHTML).

\n

Podstawowym błędem jaki popełnia wiele osób zaczynających pracę z XML-em to traktowanie go jak zwykłego tekstu. Owszem - dokumenty XML zazwyczaj można edytować w zwykłym edytorze tekstu, jako znaki specjalne wykorzystują znaki z zakresu ASCII (<, > i kilka innych), ale wszystkie te znaki mają określone znaczenia, struktura dokumentu jest określona. Ich znaczenie, oraz wzajemne relacje (chociażby samej struktury drzewa opisanej niżej) powodują, że nieraz nierozważne modyfikowanie zawartości dokumentu prowadzi do zapisania go z błędami.

\n

Struktura dokumentu

\n

Tak, jak już wspomniałem strukturą dokumentu XML jest drzewo. Każda dana w dokumencie stanowi węzeł drzewa. Korzeniem tego drzewa jest element (o tym czym są elementy za chwilę). Poniżej przedstawiam opis tylko najważniejszych typów węzłów w drzewie XML - jest ich więcej (na przykład sam dokument też jest rodzajem węzła, węzłem też są komentarze i prolog dokumentu). Opis ten ma na celu jedynie słowne wyjaśnienie podstawowych pojęć - technicznych specyfikacji i dokładnych standardów należy szukać na stronie grupy roboczej XML przy W3C.

\n

Elementy

\n

Podstawowym typem węzła jest element. Każdy dokument ma co najmniej jeden element, wspomniany korzeń. Elementy na pewno wszyscy dobrze znają jako używane w (X)HTML-u znaczniki (tagi). Grupują one pozostałe elementy jako swoją zawartość - elementy to jedyne węzły, które mogą mieć potomków (czyli węzły w drzewie \"podpięte\" pod nie).

\n

Element obejmuje wszystko od znacznika początkowego, do końcowego. Jest to jedna z różnic między SGML, a XML - ten pierwszy dopuszczał istnienie znaczników otwierających bez odpowiadających im znaczników końcowych (najprostszym przykładem jest element BR z języka HTML). Znacznik zapisuje się wstawiając jego nazwę między nawiasy trójkątne (<, >), a znacznik końcowy oznacza się dopisując do nazwy z przodu znak /.

\n

W przypadku XMLa puste znaczniki również muszą posiadać znacznik końcowy, dopuszczalna jest jednak skrócona forma zapisu. Następujące dwa fragmenty dokumentów są poprawnie zapisanymi elementami br w XHTML-u (a więc i XML-u):

\n
<br></br>
\n
<br/>
\n

Atrybuty

\n

Atrybuty opisują pewne właściwości elementów. Zapisuje się je w formie nazwa=\"wartość\" (zamiast cudzysłowów dopuszcza się stosowanie apostrofów). Jest to kolejna zmiana w stosunku do SGML - tam wartości można było zapisywać bez ograniczników (w przypadku gdy wartość nie zawierała białego znaku), a nawet bez wartości (na przykład atrybut selected w HTML). W XML każdy atrybut musi mieć wartość, tak więc aby zaznaczyć wybraną opcję w liście rozwijanej w XHTML należy napisać:

\n
<option value=\"foo\" selected=\"selected\">Wybrana</option>
\n

Tekst

\n

Najważniejszy w każdym dokumencie jest przekaz. W przypadku XML często chodzi o przekaz tekstowy. Wartość tekstowa danego elementu jest wpisywana między jego początkowy i końcowy znacznik. Istnieją dwa sposoby wprowadzania tekstu. Może on zostać zapisany bezpośrednio, trzeba wtedy jednak pamiętać, o użyciu encji (o tym za chwilę) w przypadku znaków specjalnych XML-a. Drugi sposób to użycie tak zwanej sekcji CDATA:

\n
<element><![CDATA[\n    <foo>\n]]></element>
\n

Tekst zapisany w sekcji CDATA nie zostaje przetworzony jako XML - w tym wypadku <foo> jest traktowane jako zwykły tekst, a nie element. W sekcji takiej jednak nie można (w żaden sposób) przechowywać ciągu ]]>, jeśli więc chcemy zapisać go musimy skorzystać z dwóch sekcji CDATA oddzielonych zwykłym tekstem:

\n
<element>\n<!--\nten element po przetworzeniu będzie miał następującą zawartość tekstową:\n\npierwszy fragment tekstu\n]]>\ndrugi fragment tekstu\n\n -->\n<![CDATA[\npierwszy fragment tekstu\n]]>]]&gt;<![CDATA[\ndrugi fragment tekstu\n]]>\n</element>
\n

Encje

\n

Ostatnim z najważniejszych typów węzłów są encje - ang. entity. Są to odwołania do wcześniej zdefiniowanych identyfikatorów. Odwołania takie zostają w czasie przetwarzania podmienione z wartościami danych identyfikatorów. Podstawowym zastosowaniem jest wstawianie do dokumentów znaków specjalnych. Istnieje pięć pre-definiowanych encji, które dają możliwość zapisania wszystkich znaków używanych przez XML jako specjalne:

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
&lt;<
&gt;>
&amp;&
&quot;"
&apos;'
\n

Pierwsze dwa znaki są używane jako ograniczniki znaczników, ampersand jest używany do rozpoczęcia zapisu encji (na przykład, żeby zapisać &amp; należy odwołać się podwójnie, przez &amp;amp;). Ostatnie dwa znaki są używane jako ograniczniki wartości atrybutów - tak na prawdę poza atrybutami nie trzeba ich zastępować i można pisać bezpośrednio; ponadto jeśli ogranicznikiem wartości danego atrybutu jest cudzysłów, to nie trzeba podmieniać apostrofów, tak więc poniższy zapis jest w pełni poprawny:

\n
name=\"&quot;rock'n'roll&quot;\"
\n

Oprócz tego XML daje też możliwość zapisania dowolnego znaku jako odwołanie do tablicy Unicode używając kodu danego znaku:

\n\n\n\n\n\n\n\n\n\n\n\n
&#DDD;W zapisie dziesiętnym.
&#xHHH;W zapisie szesnastkowym.
\n

Tak więc znak < (&lt;) możemy zapisać również jako &#60; lub jako &#x3C;.

\n

Document Object Model

\n

Sam XML określa fizyczną strukturę dokumentu, jednak w reprezentacji cyfrowej jest to pojęcie niezwykle ogólne. Dlatego aby ustandaryzować pracę z dokumentami XML z poziomu kodu programu stworzono interfejs programistyczny o nazwie Document Object Model - w skrócie DOM. Jest on powszechnie używany i zaimplementowany na chyba wszystkie ważniejsze platformy, a w przypadku środowisk do pracy w środowisku internetowym (PHP5, JavaScript, Java i wiele innych) praktycznie jest on standardem. API to określa metody dostępu do węzłów, ich modyfikacji, tworzenia i wiele innych operacji.

\n

Jeśli mamy zamiar wykorzystywać w naszym oprogramowaniu formaty oparte na XML-u to DOM jest podstawą. Korzystając z niego mamy pewność, że przetwarzamy dokument we właściwy sposób (oczywiście pomijając możliwość błędu w samej bibliotece naszego środowiska \";)\"), a ponadto ułatwi nam to ewentualną migrację do nowego środowiska, albo reprodukcję kodu - w każdym DOM zadziała w taki sam sposób i korzysta się z niego również w niemal taki sam sposób w każdej dostępnej implementacji (takie jest założenie ale oczywiście istnieją zazwyczaj drobne różnice w zależności od języka).

\n

xml:id

\n

Bardzo ważnym rozszerzeniem podstawowej standaryzacji XML jest xml:id. Najprościej rzecz ujmując określa ono zasady identyfikacji elementów w dokumencie. W skrócie, który jednak nie ujmuje nic ważnego z całości, xml:id określa typ atrybutu, który jest unikalny w skali dokumentu - czyli posługując się jego wartością jesteśmy w stanie znaleźć szukany element (nie ma drugiej takiej wartości). W większości języków opartych na XML-u używa się do tego celu atrybutu id, jednak tutaj należy zaznaczyć bardzo ważną sprawę - sam dokument xml:id nie określa nazwy atrybutu, a jedynie jego typ. Oznacza to, że język musi określić, który atrybut będzie w nim oznaczał identyfikator. Na przykład poniższy kod wypisze bar, a nie foo!:

\n
$dom = new DOMDocument();\n$dom->loadXML('<!DOCTYPE element [\n\n<!ELEMENT element (element*)>\n<!ATTLIST element\n    id      CDATA   #IMPLIED\n    name    ID      #IMPLIED\n>\n\n]>\n<element>\n    <element id=\"bar\" name=\"foo\" />\n    <element id=\"foo\" />\n</element>');\n\necho $dom->getElementById('foo')->getAttribute('id');
\n

Sekcji DOCTYPE nie będę na razie tłumaczył - definiuje ona dla naszego typu dokumentu znacznik element, który może zawierać dwa atrybuty: id i name. Jednak jako identyfikator podaje ten drugi. Co więcej - bez tej sekcji w dokumencie w ogóle nie będziemy mogli wyszukiwać elementów, gdyż id nie jest nawet domyślnie atrybutem typu xml:id - nie jest niż żaden atrybut. Dlatego właśnie ważne jest zrozumienie, czym XML sam w sobie jest dla dokumentu - jedynie formatem zapisu, a to my musimy sami zatroszczyć się o jego prawidłową (oczekiwaną przez nas) interpretację pod kątem zawartości.

\n

DOM

\n

Rozszerzenie xml:id ma również bardzo duże znaczenie w aspekcie korzystania z interfejsu DOM. Jak widać w powyższym przykładzie interfejs ten udostępnia metodę getElementById() - to właśnie dzięki niej możemy bez trudu odnaleźć element o podanym przez nas identyfikatorze.

\n

Przestrzenie nazw

\n

Kolejnym ważnym mechanizmem rozszerzającym podstawowe zasady funkcjonowania XML-a są przestrzenie nazw. Idea ta jest pewnie znana z wielu języków programowania i w przypadku XML-a pełni podobną rolę - grupowanie identyfikatorów z jednego języka w jego przestrzeni nazw. Tyle, że w przypadku XML-a jest to znacznie bardziej ważne - jak już wiele razy zaznaczałem pracując z XML-em praktycznie samodzielnie tworzymy własny język, dlatego ważne jest aby zgrupować wszystko to, co w nim definiujemy i odizolować od reszty. Mechanizm przestrzeni nazw jest nieco inny niż te znane z języków programowania jak chociażby C++ - tutaj przestrzenią nazw jest po prostu prefiks nazwy danego elementu, lub atrybutu. Użycie przestrzeni nazw nie ładuje nam jej, nie dołącza żadnej biblioteki - po prostu grupuje dany element, lub atrybut. Jest to nieco mylące, szczególnie na początku, ale należy pamiętać, że XML sam w sobie jest kompletnie statyczny - to język formatowania dokumentów, a nie język programowania, który określa wykonywanie czynności.

\n

Jeszcze bardziej pokręcony może się wydawać na początku sposób użycia tej techniki. Samą przestrzenią nazw jest URI, natomiast w dokumencie tworzy się dla niej lokalny identyfikator:

\n
<root xmlns:foo=\"http://localhost/\" foo:bar=\"test\" />
\n

W tym wypadku tworzymy w dokumencie identyfikator foo dla przestrzeni nazw http://localhost/. Tworzenie przestrzeni nazw w dokumencie odbywa się za pomocą atrybutu xmlns w formie xmlns:identyfikator. Możemy także użyć samego atrybutu xmlns, ma to miejsce chociażby w przypadku stron napisanych w XHTML-u:

\n
<html xmlns=\"http://www.w3.org/1999/xhtml\" />
\n

W ten sposób definiujemy domyślną przestrzeń nazw. Jednak co jeszcze bardziej mylące - dana przestrzeń nazw nie jest żadnym fizycznym adresem (może, ale nie musi) - może być to nie istniejący URI, co więcej - nawet nie musi być to realny URI, musi być jedynie poprawny składniowo (ale oczywiście zalecane jest, aby pod adresem wskazywanym przez przestrzeń nazw znajdywał się jakiś powiązany z nią zasób).

\n

Przestrzenie nazw w XML dają ogromne możliwości - pozwalają na zagnieżdżanie elementów z różnych formatów w jednym dokumencie. Jest to jedna z największych korzyści jakie płyną z XHTML, który tym właśnie się różni od HTML-a, że jest aplikacją XML. Można na przykład osadzić obraz SVG bezpośrednio wewnątrz dokumentu XHTML:

\n
<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:svg=\"http://www.w3.org/2000/svg\">\n    <head>\n        <title>Przykład osadzania dokumentów XML</title>\n    </head>\n    <body>\n        <h1>Grafika SVG osadzona bezpośrednio w dokumencie XHTML</h1>\n        <svg:svg version=\"1.1\" baseProfile=\"full\" width=\"300px\" height=\"200px\">\n            <svg:circle cx=\"150px\" cy=\"100px\" r=\"50px\" fill=\"#ff0000\" stroke=\"#000000\" stroke-width=\"5px\"/>\n        </svg:svg>\n    </body>\n</html>
\n

Aby obejrzeć rezultaty potrzebna będzie przeglądarka z obsługa formatu SVG (na przykład Opera), a plik należy zapisać z rozszerzeniem .xhtml. Przykład zaczerpnięty ze strony https://jwatt.org/svg/demos/xhtml-with-inline-svg.xhtml, nieco oczyszczony. Na ekranie powinno się pojawić czerwone koło z czarną obwódką.

\n

Walidacja

\n

Bardzo ważnym elementem przetwarzania dokumentów XML jest walidacja, czyli sprawdzanie ich poprawności. Sam fakt, iż dokument udało się załadować jako strukturę danych świadczy jedynie, że jest to poprawnie zapisany dokument XML. Ponieważ w XML-u sami decydujemy o tym jaką strukturę mają mieć dane zapisane w dokumencie, sam procesor XML (mechanizm ładujący i przetwarzający dokumenty) nie jest w stanie sprawdzić ich poprawności pod kątem semantycznym, zbadać ich zależności. Do tego celu należy stworzyć definicje typów danych zawartych w dokumentach.

\n

Sposobów na to jest kilka, ja przedstawię tutaj trzy najważniejsze. Nie będę ich zbyt szczegółowo omawiał, ponieważ każdy z nich to temat na wiele osobnych stron artykułów.

\n

DTD

\n

Pierwszym sposobem opisu jest DTD - Document Type Definition. Jest to natywny sposób opisu zawartości dokumentu wywodzący się jeszcze z SGML - jest on bardzo prosty i prymitywny, jednak przez to również ograniczony. To właśnie w DTD została zapisana definicja danych w przykładzie obrazującym działanie xml:id. DTD ma jednak kilka cech, które stawiają je ponad pozostałymi sposobami opisu XML:

\n\n

Jednak jak już wspomniałem DTD jest bardzo ograniczone i pozwala tylko na podstawowy zakres definiowania struktury dokumentu. Ponadto używa on składni SGML, co w przypadku osób chcących pracować z samym XML-em może stwarzać niepotrzebne zamieszanie.

\n

XML Schema

\n

Nowszą technologią jest XSD (XML Schema Definition). Daje ona ogromne możliwości, znacznie większe niż te z DTD. Ponadto definicja stworzona przy pomocy tego języka jest sama w sobie również dokumentem XML, więc jest to wygodniejsze rozwiązanie dla osób obeznanych z XML-em.

\n

Ma ono jednak swoje wady. Po pierwsze nie da się załączyć definicji XML Schema do dokumentu. Walidacja na podstawie takiego schematu odbywa się \"na życzenie\", czyli należy po załadowaniu w kodzie naszego dokumentu wskazać procesorowi XML dodatkowo nasz schemat. Poza tym jako iż jest to również język oparty na XML, to i tak posiada on swój własny DTD opisujący jego składnię.

\n

Relax NG

\n

Podobnym rozwiązaniem do XSD jest Relax NG. Poza tym, że różni się składnią, to sama idea jest bardzo podobna, więc posiada on pod względem technicznym podobne wady i zalety. Jedyną większą różnicą jest fakt, iż język ten posiada drugą składnię, która nie jest składnią XML (kompaktowa).

\n

XML a (X)HTML

\n

Jaka jest relacja między XML-em, a HTML-em? Otóż bezpośredniej nie ma w ogóle. HTML to język oparty na SGML-u. Pisanie w nim jest nieraz wygodniejsze niż pisanie w XML-u, jednak wiąże się to z wadami ze strony technicznej - niejednoznaczność i nie konsekwentność w strukturze dokumentu. Implementacją HTML-a, w sztywnych regułach XML-a jest XHTML - jest to pełnoprawna aplikacja XML, zatem korzystanie z niego ma wiele zalet (możliwość zagnieżdżania dowolnych innych aplikacji XML, oraz zagnieżdżania w innych aplikacjach XML), łatwe przetwarzanie (możliwość skorzystania z interfejsu DOM). Oczywiście trzeba pamiętać o zasadach przekształcania dokumentów HTML w XHTML.

\n

DOM a (X)HTML

\n

Nie ulega wątpliwości, że na co dzień w sieci formatem XML, który wymaga najwięcej przetwarzania jest właśnie XHTML. Strony internetowe zbudowane przy pomocy XHTML-a można przetwarzać standardowymi metodami udostępnianymi przez DOM. Jednak nie jest to zbyt wygodne - większość elementów posiada bardzo specyficzne własności. Dla języka XHTML stworzono dlatego specjalne rozszerzenie interfejsu DOM (jego implementacje działają zazwyczaj również z dokumentami HTML) - opisuje ono dodatkowe metody elementów definiowanych przez XHTML pozwalając na bardzo łatwe manipulowanie stronami chociażby przy tworzeniu aplikacji webowych w technologii AJAX.

\n

Technologie XML

\n

XML daje ogromne możliwości. Być może nawet nie wiesz jak szeroko jest on używany w dzisiejszym oprogramowaniu. Jego prostota i elastyczność sprawiają, że idealnie nadaje się na przykład jako format do protokołów sieciowych. Przedstawię tutaj tylko wybrane z różnych dziedzin przykładu użycia XML-a. Na co dzień jest on używany w przeróżnych celach i znajomość jego to praktycznie podstawa w dziedzinie przetwarzania danych.

\n

SVG

\n

Jest to format (którego użyłem w tym artykule jako przykład) grafiki wektorowej. Grafika wektorowa ma tę zaletę, że jest zapisywana w postaci matematycznej, dzięki temu można ją przeskalować do dowolnej wielkości bez utraty jakości ani informacji. SVG to otwarty standard, a dzięki temu, że jest oparty na XML-u można łatwo generować obrazy SVG w programach. Nadaje się bardzo dobrze do tworzenia wszelkiego rodzaju schematów i wykresów, gdzie dane powinno się dać łatwo zmienić, jednak można go z powodzeniem używać do dowolnego innego rodzaju grafik.

\n

SOAP

\n

SOAP to protokół typu RPC - Remote Procedure Call. Daje on możliwość przesyłania wywołań procedur przez sieć, oraz odbierania rezultatów takich zapytań. W rezultacie można tworzyć aplikacje korzystające z serwera za pośrednictwem wygodnego interfejsu programistycznego wyglądającego jak zwykłe wywołania biblioteczne. Przykładem jest chociażby opisywane przeze mnie Allegro WebAPI.

\n

Jabber

\n

Jabber to oparty na XML, uniwersalny i elastyczny protokół komunikacyjny. Wykorzystywany jest przede wszystkim w komunikatorach internetowych (dzięki obsłudze \"transportów\" daje możliwość korzystania także z innych sieci jako usług serwera). Korzystają z niego między innymi polskie AQQ, czy Tlen.

\n

ODF, OOXML

\n

Niewiele osób zdaje sobie sprawę, że obecnie większość popularnych formatów biurowych również korzysta z XML-a. OpenDocument (ODF) to format używany przez pakiet OpenOffice.org. Jest to oficjalny międzynarodowy standard ISO. Z kolei mało kto z korzystających na co dzień z najnowszej wersji MS Office wie, że Microsoft również do swoich dokumentów używa formatów opartych na XML-u. Format ten nazywa się OOXML i również jest standardem ISO.

\n

Bardzo prosto można się o tym przekonać, wystarczy zmienić rozszerzenie pliku któregokolwiek z tych formatów na .zip - pliki te są po prostu archiwami ZIP zawierającymi dokumenty XML.

\n

XML 1.1

\n

Opisywana przeze mnie tutaj wersja XML-a to 1.0. Istnieje również wersja 1.1. Na pierwszy rzut oka niewiele się zmieniło i ogólne zasady nadal są takie same. Jednak zmiana wersji niesie kilka zmian, które powodują, że nie każdy poprawny dokument XML 1.0 jest poprawnym dokumentem XML 1.1 i to sprawia, że nowa wersja nie zdobywa na razie popularności - tak na prawdę nie wnosi ona zbyt wiele, więc nie ma po co zmieniać wszystkiego i narażać się na niekompatybilność ze starszymi wersjami dokumentów.

\n

Podstawowa zmiana to filozofia dopuszczalnych nazw - w przypadki wersji 1.0 wszystko co nie było dozwolone było zakazane. W przypadku wersji 1.1 wszystko co nie jest zabronione jest dozwolone. Pozwala to na przykład na użycie wielu dodatkowych znaków Unicode. Oprócz tego zmieniła się filozofia dotycząca wielu znaków kontrolnych - wiele znaków, których nie można było używać poprzednio, teraz można używać w tekście za pomocą encji (jednak nadal nie można używać znaku #0, nawet jako encji). Jednak z drugiej strony wiele znaków kontrolnych, które można było używać bezpośrednio, teraz trzeba przekształcać na encje, co właśnie powoduje problemy.

\n

Ogólnie, jeśli nie potrzebujemy, to nie ma żadnej realnej potrzeby przenoszenia się na nowszą wersję - nie jest to żadna rewolucja, a jedynie zmiany wprowadzone (niestety) po czasie.

\n

Na koniec

\n

Podsumowując, jeśli mamy zamiar obsługiwać i przetwarzać dokumenty za pośrednictwem sieci, praktycznie na pewno zetkniemy się z XML-em. A jeśli już musimy z nim pracować to warto go dobrze znać. Brak podstawowej wiedzy na temat jego działania prowadzi często do wypaczonego podejścia, a XML nie jest wcale trudny, więc dobrze jest poświęcić chwil kilka na zgłębienie jego przynajmniej podstawowych mechanizmów.

","publishedAt":"2009-03-30T01:17:33Z","view":"views/sites/display/blog.xhtml","url":null,"commentingEnabled":true,"category":{"name":"Blog","slug":"blog","view":"views/sites/list/blog.xhtml","siteView":"views/sites/display/blog.xhtml"},"tags":[{"name":"Web","slug":"web"},{"name":"Technologie","slug":"technologie"},{"name":"Teksty","slug":"teksty"},{"name":"XML","slug":"xml"}]},{"name":"Chillout Development","slug":"chillout-development","content":"

Witamy w Chillout Development!

\n

Miło mi jest poinformować, że właśnie ruszyła inicjatywa Chillout Development. Jest to efekt mojej współpracy z cDStudio-web.com i Studio74.pl. Od teraz pod wspólnym szyldem będziemy realizować projekty zarówno na zewnątrz jak i własne.

\n

Wszechstronność

\n

Zapewniamy stworzenie strony od podstaw (zarówno technicznie jak i wizualnie), modyfikację już istniejących rozwiązań, hosting i pozycjonowanie jak i zarządzanie stroną. Ale Chillout Development to nie tylko strony internetowe. Oferujemy pełną obsługę informatyczną od software'u przez obsługę sieci aż po sprzęt techniczny i technologie mobilne.

\n

Zapraszmy do zapoznania się z naszą ofertą na stronie https://chilldev.pl/.

\n

Nowe szaty Wrzasq'a

\n

Aha, a nową szetę graficzną mojej strony przygotował Maciej Banaszek (cHeSteR).

","publishedAt":"2009-03-23T01:40:37Z","view":"views/sites/display/blog.xhtml","url":null,"commentingEnabled":true,"category":{"name":"Blog","slug":"blog","view":"views/sites/list/blog.xhtml","siteView":"views/sites/display/blog.xhtml"},"tags":[{"name":"Web","slug":"web"},{"name":"Praca","slug":"praca"},{"name":"Portfolio","slug":"portfolio"},{"name":"Chillout","slug":"chillout"},{"name":"PHP","slug":"php"},{"name":"Firma","slug":"firma"}]},{"name":"Od podstaw: Unicode i UTF-8","slug":"od-podstaw-unicode-i-utf-8","content":"

Odrobina historii

\n

W Internecie od niemal zawsze mają miejsce problemy z kodowaniem (zapisem znaków). Dziś praktycznie powszechnie korzysta się z Unicode (czy też po spolszczeniu - Unikod). Jednak nadal wiele osób, szczególnie nieobeznanych z nim nie ma zbytnio pojęcia czym on jest i dlaczego jest taki ważny. Przeważnie dotyczy to osób korzystających ze środowiska Microsoft Windows i żadnego innego, ponieważ nie zdają sobie oni nieraz sprawy z różnorodności pozostałych platform. Skąd jednak całe to zamieszanie? Zacznijmy od początku.

\n

Dawno temu, kiedy Internet nawet się jeszcze nikomu nie śnił w USA powstał standard ASCII - American Standard Code for Information Interchange. Jak sama nazwa wskazuje był to kod przewidziany głównie do użytku na terenie Stanów Zjednoczonych, a więc nie zawierała żadnych krzaczkowatych znaków. Z tego powodu ilość znaków potrzebnych do uwzględnienia była dość niewielka - do zapisania wszystkich wystarczało 7 bitów. Mimo iż wszystkie maszyny fizycznie pracowały na ośmiu, standard ten zamykał się w siedmiu - ósmy bit często był wykorzystywany jako bit parzystości w transmisji danych. Komputery jednak dotarły do krajów takich jak Polska, Niemcy, gdzie potrzebne było dodanie znaków diakrytycznych, czy też o zupełnie odmiennym piśmie jak cyrylica, czy alfabety z rodziny CJK (daleki wschód).

\n

Strony kodowe

\n

Nawet ósmy bit nie wystarczał do zakodowania wszystkich znaków. Utworzono zatem strony kodowe, organizacja ISO stworzyła standard ISO-8859, który opisuje kodowania znaków w różnych zestawach. Czym w ogóle jest takie kodowanie? Strona kodowa to tablica przyporządkowująca binarnym reprezentacjom znaki pisma (i nie tylko, bo oprócz nich są też znaki kontrolne, sterowania i inne, ale to w tej chwili mało istotne). W zależności od tego jaka strona kodowa jest używana, takie znaki będą użyte. Na przykład bajt o wartości 0xA3 w stronie kodowej ISO-8859-1 zostanie zamieniony na £ (znak funta), natomiast w stronie kodowej ISO-8859-2 na wielką polską literę Ł. Jednak wszystkie kodowania mają jedną wspólną część - pierwsze 128 znaków (te, które da się zapisać za 7 bitach) to podstawowe kodowanie ASCII.

\n

Oczywiście istnieje pewna korporacja, której żadne standardy nie są straszne. Świat byłby zbyt piękny, gdyby pod Windowsem obowiązywały standardy ISO - tam są jeszcze inne strony kodowe. Nie jest tragicznie - wszystkie one również bazują na standardzie ASCII. Poza tym różnice pomiędzy ISO, a CP (Windows) też nie są drastyczne, jednak fakt iż te same znaki koduje się innymi wartościami sprawia, że jest to duże utrudnienie. Przykładowo wartość 0xB1 w kodowaniu ISO-8859-2 odpowiada literze ą, podczas gdy w kodowaniu CP-1250 jest to znak ± (plus-minus, błąd pomiaru).

\n

Oprócz tego istnieją też kodowania dla języków azjatyckich takie jak Big5 i inne z rodziny GB. Jednak ze względu na zupełnie inną specyfikę tamtejszych języków działają one inaczej.

\n

Kodowania polskich znaków

\n

Do kodowania polskich znaków nadają się dwa wspomniane już wcześniej kodowania - ISO-8859-2 i CP-1250. Różnice między nimi nie są drastyczne - to bodajże kilkanaście znaków. Niestety jak na złość są to między innymi litery polskiego alfabetu: ś, Ś, ź, Ź, ą, Ą. Oczywiście standardem domyślnie jest standard ISO, jednak zgadnijcie, czy był on popularniejszy od kodowania Windows w czasach, kiedy Linux na desktopach brzmiał podejrzanie podobnie do wirus, o innych systemach nie wspominając (mówimy o sytuacji w Polsce).

\n

Problemy w Internecie

\n

Taka sytuacja (nie tylko dotycząca polskich znaków) w połączeniu z wymianą informacji na globalną skalę (Internet) doprowadziła do wielu problemów. Dane przesyłane przez sieć to po prostu strumienie bajtów. Kodowanie odpowiada jedynie za ich graficzną prezentację, nie zmienia w żaden sposób ich zawartości. Oznacza to, że kiedy jeden użytkownik wysyłał ciąg Śląsk korzystając z systemu Windows, to wysyłał de facto wartości (w zapisie szesnastkowym):

\n
8C 6C B9 73 6B
\n

Kiedy taki plik otworzyłby ktoś korzystający z innego systemu i domyślnie ustawionym kodowaniem ISO zobaczyłby szlacek w postacii Œlšsk. W większości protokołów służących do przesyłania informacji tekstowych w Internecie (takich jak HTTP, czy SMTP) istnieje możliwość wysyłania dodatkowych meta-danych (nagłówków) określających kodowanie przesyłanej zawartości. Problem jednak pozostaje w przypadku danych przesyłanych bez żadnego przetwarzania (chociażby w przypadku protokołu IRC - dane są tam przesyłane do rozmówców w formie takiej, w jakiej wysłał je użytkownik, więc jeśli 3 osoby będą miały różne kodowania, każda zobaczy znaki z poza podstawowej tablicy ASCII w inny sposób). Poza tym może się zdarzyć, że opisane kodowanie nie odpowiada temu, w jakim przesyłany jest dokument - na przykład gdy na stronie forum, na którym używane jest kodowanie ISO ktoś z premedytacją wpisze tekst kodowany w Windows (normalnie taka sytuacja nie będzie mieć miejsca, ponieważ domyślnie używane jest kodowanie strony).

\n

Unicode

\n

Problem dotyczy nie tylko Polski - chyba w każdym języku (oprócz angielskiego) istnieją znaki diakrytyczne (czyli właśnie te, które pisze się odmiennie, z różnymi akcentami jak ogonki, skreślenia, kropki, daszki…). Dlatego sytuacja przeszkadzała praktycznie wszystkim. Aby rozwiązać problem stworzono tablicę znaków jedną, wspólną dla wszystkich języków - zarówno łacińskich, jak i tych opartych o cyrylicę, pismo arabskie, hebrajskie, czy nawet języków takich jak chińskie, japońskie, czy koreańskie. Standard ten nazywa się właśnie Unicode. W odróżnieniu od poprzednio omawianych tablic znaków nie ogranicza on zapisu znaku do jednego bajta dzięki czemu do dyspozycji jest znacznie szersza przestrzeń wartości pozwalająca na pomieszczenie wszystkich znaków obecnie używanych alfabetów.

\n

Mało tego - obejmuje także wiele znaków graficznych, symbolik (układy scalone, elektryczne, wzory matematyczne) oraz znaków interpunkcyjnych, które były pomijane w normalnych kodowaniach. Jeśli próbowaliście na przykład kiedyś wstawić czy to w edytorze tekstu, czy na przykład na stronie internetowej znaki » musieliście go wstawić jako znak specjalny (w przypadku HTMLa można to osiągnąć wstawiając encję &raquo;). W przypadku Unicodu nie ma konieczności odwoływania się do encji, wystarczy wpisać ten znak (chociaż oczywiście nie zrobimy tego tak po prostu z klawiatury). Podobnie jest z wieloma innymi znakami - wszystkie poniższe symbole zostały zapisane jako znaki Unicode, bez korzystania z encji HTML (jeśli klikniecie podgląd źródła strony zauważycie, że są one widoczne w taki sam sposób):

\n
» « › ‹ … φ Ϣ Ж Я ▨ ✈ ✮ ❼ ➷
\n

Unicode, a UTF

\n

Wydawało by się, że już jest pięknie, że nie da się tego spieprzyć. Jednak pesymiści mogli śmiało obstawiać w totka. Jeśli ktoś słyszał o Unicodzie to z pewnością słyszał też o UTF. Jednak wielu ludzi uznaje te pojęcia za tożsame, co jest wielkim błędem. Otóż Unicode to tablica znaków - przypisuje znaki graficzne poszczególnym wartościom. Zastępuje wszystkie kodowania jedno-bajtowe. Warto też zaznaczyć, że pierwsze 128 znaków jest wciąż zgodne z tablicą ASCII. Jednak z jednego problemu narodził się inny - w przypadku Unicodu nie minął kłopot kodowania znaków. Tutaj co prawda mamy już jedną tablicę wartości - pozostaje jednak problem jak te znaki zapisywać w formie binarnej. Jednym z takich kodowań jest UTF - Unicode Transformation Format, innym z kolei jest GB18030 (kodowanie, które uwzględnia kompatybilność z kodowaniami języków azjatyckich), a istnieją i bardziej egzotyczne.

\n

Ogólnie szeroko używane jest przede wszystkim kodowanie UTF, jednak wcale nie na tym koniec rozbieżności. Otóż jest kilka wariantów tego kodowania, które definiują długość słowa - w UTF-8 jest to 8 bitów (1 bajt), w UTF-16 jest to 16 bitów (2 bajty), UTF-32 32 bity (4 bajty), a oprócz tego istnieje także (nie licząc wersji, które zostały porzucone i nie warto się nimi zajmować) UTF-7, który jest najczęściej używany do przesyłania maili i wykorzystuje tylko 7 bitów (czyli tablicę ASCII, a pozostałe znaki są kodowane w specjalny sposób). Jak to możliwe zatem, żeby używać 8-bitowego kodowania do zapisu znaku zajmującego więcej niż jeden bajt? Otóż znaki mogą się składać z więcej niż jedno słowo jeśli jest taka potrzeba. Zapisując znak z wykorzystaniem większej ilości słów postępuje się według następującego schematu - ilość jedynek (ustawionych bitów) z pierwszego bajtu oznacza ilość użytych słów; w każdym bajcie dane są przechowywane za pierwszym zerem. I tak na przykład litera ą, która ma w tablicy Unicode pozycję 261 (105 szesnastkowo, 100000101 binarnie) została by zapisana w taki sposób (pogrubione fragmenty to bity, które kodują znak):

\n
11000100 10000101
\n

Problemy techniczne

\n

Unicode i jego kodowania powodują wiele problemów natury technicznej. Jest to zupełnie inny sposób zapisu danych niż w przypadku starych kodowań jedno-bajtowych. Przede wszystkim ilość słów nie jest tutaj równa ilości znaków (może tak się zdarzyć jeżeli mamy dokument wykorzystujący jedynie znaki ASCII w kodowaniu UTF-8). Oznacza to, że od strony programistycznej należy używać bibliotek opracowanych do pracy z takimi kodowaniami znaków - zwykłe funkcje dostępne w wielu językach takie jak strpos(), substr(), strlen() i pokrewne nie będą działać poprawnie. Wspomniany znak ą zostałby odczytany jako łańcuch o długości 2 ponieważ zajmuje 2 bajty.

\n

Innym problemem jest BOM. Jest to znacznik zapisany na początku danych określający format danych. W przypadku kodowań o długości słowa większej niż 1 bajt możliwe jest kodowanie little-endian i big-endian. W przypadku kodowania UTF-8 nie ma takiej możliwości - słowo ma 1 bajt, a kolejność bajtów jest jednoznaczna. Jednak BOM istnieje też w tym przypadku, jest po prostu zawsze taki sam, a z tego powodu dla UTF-8 jest on nieobowiązkowy. Okazuje się jednak, że jest on niezwykle problematyczny. Istnieją programy, ktróre nie potrafią otworzyć plików zapisanych w formacie UTF-8 jeśli nie posiadają BOM'a. Inne z kolei nie potrafią poprawnie obsłużyć tego bloku. Najprostszy przykład - Notatnik i Apache z PHP. Kiedy otworzymy plik w Notatniku niezależnie czy posiadał on BOM, czy nie, to po zapisaniu program automatycznie doda go na początku pliku. Ale jeśli wrzucimy taki plik na swój serwer WWW to PHP odczyta nagłówek BOM jako zwykłe dane i wyśle do klienta. Szczególnie uciążliwe jest to w przypadku nagłówków (przekierowania, sesje, ciasteczka) - BOM jest w takim wypadku traktowany jako treść dokumentu i nie można po jego wysłaniu wysłać nagłówków HTTP, a ponieważ BOM znajduje się na samym początku pliku w rzeczywistości po prostu uniemożliwia pracę z sesją, ciasteczkami, cachem (w rozumieniu HTTP) i wszelkimi innymi aspektami wymagającymi użycia nagłówków HTTP.

\n

UTF-8

\n

Tak jak wspominałem najpopularniejsze kodowanie Unicode to UTF-8. Jest to spowodowane przede wszystkim tym, że długość słowa w nim wynosi 1 bajt, a co za tym idzie dokumenty zapisane znakami ASCII są dokładnie identyczne w przypadku tego kodowania, jak i wszystkich starych kodowań jedno-bajtowych. Również w przypadku znaków z poza ASCII wielkość takiego znaku w przypadku języków europejskich wzrasta jedynie do 2 bajtów. UTF-8 to domyślne kodowanie dokumentów XML i formatach opartych na nim (w tym XHTML).

\n

Problem natomiast pojawia się w przypadku alfabetów takich jak arabski, czy cyrylica - tutaj praktycznie każdy znak się rozrasta w wyniku czego dokumenty są dwa razy większe. Problemem jest też zmienna długość słowa (czego nie ma w przypadku kodowań UTF-32).

\n

Wybierz UTF-8

\n

Mimo tego, głównym celem samego Unicodu, który w zupełności spełnia jest ujednolicenie zapisu znaków. Problemem jest jedynie dobór kodowania. Jeśli nie używasz wyspecjalizowanych narzędzi narzucających dane kodowanie, jeśli nie jesteś ograniczony do 7 bitów (gdzie konieczne jest użycie UTF-7), jeśli nie masz ogromnych narzutów na operacje na łańcuchach (gdzie bardziej wydajnym może się okazać użycie bardziej obszernego kodowania UTF-16 lub UTF-32, zyskując tym pewność stałej długości znaku), jeśli piszesz głównie z użyciem alfabetu łacińskiego (niewielka ilość znaków diakrytycznych w tekście powoduje znikomy wzrost objętości), to kodowanie UTF-8 jest najodpowiedniejszym do zastosowań w nowoczesnych środowiskach, w którym ma zachodzić wymiana informacji. To odpowiedni wybór jeśli chcesz zminimalizować problemy związane z różnym kodowaniem znaków.

","publishedAt":"2009-03-05T17:50:03Z","view":"views/sites/display/blog.xhtml","url":null,"commentingEnabled":true,"category":{"name":"Blog","slug":"blog","view":"views/sites/list/blog.xhtml","siteView":"views/sites/display/blog.xhtml"},"tags":[{"name":"Web","slug":"web"},{"name":"Teksty","slug":"teksty"},{"name":"UTF","slug":"utf"},{"name":"Unicode","slug":"unicode"}]},{"name":"Konfiguracja serwisu z kontami FTP","slug":"konfiguracja-serwisu-z-kontami-ftp","content":"

Analiza przedwstępna

\n

Dość ciekawym zagadnieniem, jakie ostatnio musiałem poruszyć przy tworzeniu pewnego projektu jest udostępnianie użytkownikom sewrisu dodatkowych usług. Nie mam tutaj na myśli jakichś usług do wybrania na stronie, ale usług sieciowych. Konkretnie problematyka była taka, aby każdy użytkownik serwisu webowego miał dostęp do serwera FTP z własnym kontem. Serwis oczywiście miał swoją własną bazę MySQL z kontami użytkowników.

\n

Pierwsze dwa wyjścia jakie się nasuwają w takiej sytuacji to oczywiście skrajne albo obsłużenie serwera FTP (napisanie jakiegoś prostego daemona do tego celu), albo z kolei tworzenie automatycznie bliźniaczego konta w systemie (oczywiście obsługując wtedy rejestrację, usuwanie kont, zmianę hasła, zarządzanie kontem, …). Oczywiście obydwa te rozwiązania jako zbyt absurdalne nawet dla mnie \";)\" odłożyłem na później (jakby wszystko inne zawiodło). Zacząłem szukać możliwości jakiegoś sprzężenia istniejącej bazy danych strony internetowej z mechanizmem logowania usługi FTP. Na szczęście na serwerze stoi ProFTPd - jego slogan Highly configurable GPL-licensed FTP server software nie jest bezpodstawny.

\n

ProFTPd daje naprawdę duże możliwości konfiguracji i to we wszelkim zakresie, ale skupmy się na problemie. Daemon ten umożliwia uwierzytelnianie nie tylko bazujące na użytkownikach systemowych, ale również pochodzących z innych źródeł. Ponieważ bez sensu było by na przykład tworzenie pliku z wirtualnymi użytkownikami, lub inne pośrednie obejścia, godne rozważenia pozostały dwie opcje autoryzacji: PAM i SQL.

\n

Pierwsza z nich to uniwersalny, modułowy mechanizm logowania w systemach UNIXowych. Daje możliwość kontroli autoryzacji na wiele sposobów włączając w to możliwość tworzenia własnych modułów. I w sumie to by wystarczyło, gdyby nie fakt, że sam ProFTPd zawiera również moduł do pobierania danych logowania z bazy SQL (obsługiwane są MySQL i PostgreSQL) więc pośrednictwo PAM byłoby w tym wypadku zbędne i zapewne kłopotliwe.

\n

Struktura tabeli SQL

\n

Pierwszym problemem jaki napotkałem była struktura bazy danych. Moja była raczej dość normalna dla skryptów PHP:

\n
CREATE TABLE `groups` (\n    `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID grupy.',\n    `name` VARCHAR(255) NOT NULL COMMENT 'Nazwa grupy.',\n/* … */\n    PRIMARY KEY (`id`),\n    UNIQUE KEY (`name`)\n) ENGINE = InnoDB CHARSET = utf8 COMMENT 'Grupy użytkowników.';\n\nCREATE TABLE `users` (\n    `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID użytkownika.',\n    `idGroup` BIGINT UNSIGNED NOT NULL COMMENT 'Grupa użytkownika.',\n    `login` VARCHAR(255) NOT NULL COMMENT 'Login.',\n    `password` VARCHAR(40) NOT NULL COMMENT 'Hasło z SHA1.',\n/* … */\n    PRIMARY KEY (`id`),\n    CONSTRAINT `userIdGroup` FOREIGN KEY (`idGroup`) REFERENCES `groups` (`id`) ON UPDATE CASCADE,\n    UNIQUE KEY (`login`)\n) ENGINE = InnoDB CHARSET = utf8 COMMENT 'Użytkownicy systemu.';
\n

Sęk w tym, że mod_sql dla ProFTPd wymagał z goła odmiennej struktury:

\n
SQLUsersInfo:\n|- login (string)\n|- password (string)\n|- id (integer)\n|- idGroup (integer)\n|- path (string)\n`- shell (string)\n\nSQLGroupsInfo:\n|- name (string)\n|- id (integer)\n`- members (string)
\n

Tak więc powstały następujące problemy:

\n\n

Sprzężenie kont FTP z tabelą SQL i konfiguracja ProFTPd

\n

Tutaj pomocne, a wręcz niezbędne, stały się widoki oraz elementy języka PL/SQL. Poszczególne problemy omówię od końca, czyli od najkrótszego rozwiązania. Ostatni problem praktycznie zniknął, ponieważ taka jest idea widoków - udostępnić zestawy pól źródłowych jako pojedyncze encje wynikowe.

\n

W przypadku widoku grup jedynym niezwykłym polem będzie pole members ponieważ musi ono zawierać sklejenie wszystkich loginów wszystkich członków danej grupy. Zrobi to za nas funkcja GROUP_CONCAT():

\n
CREATE VIEW `ftpUsers`\nAS SELECT\n    `groups`.`id` AS `id`,\n    `groups`.`name` AS `name`,\n    GROUP_CONCAT(`users`.`login` SEPARATOR ',') AS `members`\nFROM\n    `groups`\nLEFT JOIN\n    `users`\nON\n    `users`.`idGroup` = `groups`.`id`\nGROUP BY\n    `groups`.`id`;
\n

Należy zwrócić uwagę, że sklejenie to sam przecinek! Bez żadnych spacji! W klauzuli WHERE zapytań wysyłanych przez ProFTPd jest %,name,% (oraz możliwośc znajdowania się na końcu, początku, oraz jako jedyna pozycja na liście), więc dodanie spacji spowoduje błąd.

\n

Nieco bardziej problematyczny jest widok generujący dla ProFTPd listę użytkowników. Pole shell ustawimy na NULL - nie potrzebujemy powłoki dla użytkowników FTP. Musimy jednak ustalić ścieżki katalogów użytkowników. Niech to będzie dajmy na to: /var/www/upload/users/$ID/, gdzie $ID to ID użytkownika w bazie danych.

\n

Jednak najbardziej problematyczne jest pole password. Otóż hasło można przekazywać na wiele różnych sposobów - \"czyste\" (czyli w formie niezmienionej), zaszyfrowane UNIXowym crypt'em, jako skrót wynikowy funkcji PASSWORD(), a także jako inny hasz obsługiwany przez OpenSSH. Ale tutaj jest problem. OpenSSH przyjmuje skróty w formie binarnej, zakodowanej Base64. W serwisie internetowym zazwyczaj hashe generuje się z poziomu PHP i zapisuje w formie heksadecymalnej, na przykład funkcją sha1() i taki skrót zapisuje się w bazie. Jak zatem z poziomu bazy danych przetworzyć hasło z formu szasnastkowej na binarne i jeszcze zakodować je w Base64? MySQL tego niestety nie obsługuje. Dlatego zostawmy to na koniec. Najpierw zakończmy już konfigurację ProFTPd. Pierwsze co jest nam potrzebne to widok na użytkowników:

\n
CREATE VIEW `ftpUsers`\nAS SELECT\n    `users`.`id` AS `id`,\n    `groups`.`id` AS `idGroup`,\n    CONCAT(`users`.`login`, '@domena') AS `login`,\n    CONCAT('{sha1}', BASE64_SHA1(`users`.`password`) ) AS `password`,\n    CONCAT('/var/www/upload/users/', `users`.`id`) AS `path`,\n    NULL AS `shell`\nFROM\n    `users`\nLEFT JOIN\n    `groups`\nON\n    `users`.`idGroup` = `groups`.`id`;
\n

Dzięki dodaniu do loginu części @domena konta zwykłych użytkowników systemu pozostaną bez konfliktu z kontami wirtualnych użytkowników serwisu WWW.

\n

Pewnie zauważyłeś dziwną funkcję BASE64_SHA1(), której na dodatek nie ma w żadnym manualu do MySQLa, a nawet google niewiele o niej wie. Nic dziwnego, ponieważ to właśnie sedno całego mechanizmu. Ale tak jak powiedziałem zostawię to na koniec. Przyjrzyjmy się jak dla takiej bazy skonfigurować ProFTPd. Po pierwsze musimy załadować moduł mod_sql dla MySQLa:

\n
LoadModule mod_sql_mysql.c
\n

W zależności od dystrybucji możemy mieć różnie rozmieszczone pliki konfiguracyjne, jednak w 99,9% głównym plikiem będzie /etc/proftpd/proftpd.conf i ewentualne dodatkowe pliki będa w nim wymienione. Następnym krokiem będzie konfiguracja samego logowania z uzyciem danych z bazy danych SQL:

\n
# ustawiamy silnik mod_sql\nSQLBackend mysql\n\n# te dwie linijki kolejno włączają mod_sql oraz ustawiają go jako źródło uwierzytelniania\nSQLEngine on\nSQLAuthenticate on\n\n# ustawiamy format haseł\nSQLAuthTypes OpenSSL\n\n# logowanie do bazy danych MySQL\nSQLConnectInfo dbname@dbhost dbuser\n\n# tutaj wpisujemy kolejno nazwy tabel/widoków oraz pól w widzialej poniżej kolejności\nSQLUserInfo ftpUsers login password id idGroup path shell\nSQLGroupInfo ftpGroups name id members\n\n# przydatne jeśli coś pójdzie nie tak\nSQLLogFile /var/log/proftpd/sql.log
\n

Teraz pozostaje już tylko pare szczegółów dotyczących działania samego daemona. Po pierwsze dobrze by było \"zamknąć\" wirtualnych użytkowników w ich katalogach domowych, a po drugie - jak pamiętamy ustawiliśmy na sztywno brak powłoki logowania dla użytkowników z systemu, a ProFTPd domyślnie to sprawdza. Poniższe dwie linijki załątwią te problemy:

\n
# ustawia katalog główny widziany z poziomu FTP na katalog domowy w systemie (taki chroot)\nDefaultRoot ~\n\n# nie wymaga, aby użytkownik posiadał poprawną powłokę logowania\nRequireValidShell off
\n

Przesyłanie hasła

\n

Ostatnim, ale za to największym problemem jest wspomniane kodowanie hasła. Po pierwsze należy je przekształcić z formy szesnastkowej na binarną, a po drugie zakodować w Base64, a MySQL nie udostępnia do tego funkcji. Udostępnia co prawda konwersję między poszczególnymi systemami liczbowymi, ale problemem jest wtedy kodowanie znaków - szczególnie w moim przypadku, gdzie jest to UTF-8 i reprezentacja binarna miała by się nijak do tego, co powinno się otrzymać.

\n

Kodowanie Base64 w języku SQL dla MySQLa oparłem na pliku znalezionym w Internecie, autorstwa niejakiego Iana Gullivera: base64.sql (nam potrzebne jest jedynie kodowanie). Problemem pozostawało przekształcanie z systemu szesnastkowego na binarną reprezentację bez uwzględniania kodowania (gdyż Unicode mógłby tutaj nieźle napsuć zapisując niektóre znaki binarnie). Mając już kodowanie Base64 łatwo było zmodyfikować tą funkcję tak, aby zamiast znaków, pobierała z wejściowego łańcucha wartości liczbowe i przekształcała je na odpowiadający kod znaku. W efekcie powstała taka oto funkcja (nadal potrzebna jest ze wskazanego pliku tabela base64_data):

\n
DROP FUNCTION IF EXISTS BASE64_SHA1;\nCREATE FUNCTION BASE64_SHA1 (input VARCHAR(40) )\n    RETURNS VARCHAR(28)\n    CONTAINS SQL\n    DETERMINISTIC\n    SQL SECURITY INVOKER\nBEGIN\n    DECLARE ret VARCHAR(28) DEFAULT '';\n    DECLARE done TINYINT DEFAULT 0;\n\n    IFinput IS NULL THEN\n        RETURN NULL;\n    END IF;\n\neach_block:\n    WHILE NOT done DO\n    BEGIN\n        DECLARE accum_value BIGINT UNSIGNED DEFAULT 0;\n        DECLARE in_count TINYINT DEFAULT 0;\n        DECLARE out_count TINYINT;\n\neach_input_char:\n        WHILE in_count < 3 DO BEGIN\n            DECLARE first_char INT;\n\n            IF LENGTH(input) = 0 THEN\n                SET done = 1;\n                SET accum_value = accum_value << (8 * (3 - in_count));\n                LEAVE each_input_char;\n            END IF;\n\n            SET first_char = CONV( SUBSTRING(input, 1, 2), 16, 10);\n            SET input = SUBSTRING(input, 3);\n\n            SET accum_value = (accum_value << 8) + first_char;\n\n            SET in_count = in_count + 1;\n        END; END WHILE;\n\n        -- We've now accumulated 24 bits; deaccumulate into base64 characters\n\n        -- We have to work from the left, so use the third byte position and shift left\n        CASE\n            WHEN in_count = 3 THEN SET out_count = 4;\n            WHEN in_count = 2 THEN SET out_count = 3;\n            WHEN in_count = 1 THEN SET out_count = 2;\n            ELSE RETURN ret;\n        END CASE;\n\n        WHILE out_count > 0 DO BEGIN\n            BEGIN\n                DECLARE out_char CONV(1);\n                DECLARE base64_getval CURSOR FOR SELECT c FROM base64_data WHERE val = (accum_value >> 18);\n\n                OPEN base64_getval;\n                FETCH base64_getval INTO out_char;\n                CLOSE base64_getval;\n\n                SET ret = CONCAT(ret,out_char);\n                SET out_count = out_count - 1;\n                SET accum_value = accum_value << 6 & 0xffffff;\n            END;\n        END; END WHILE;\n\n        CASE\n            WHEN in_count = 2 THEN SET ret = CONCAT(ret,'=');\n            WHEN in_count = 1 THEN SET ret = CONCAT(ret,'==');\n            ELSE BEGIN END;\n        END CASE;\n\n    END; END WHILE;\n\n    RETURN ret;\nEND;
\n

Viola! /etc/init.d/protfpd restart i możemy się na serwer FTP logować z użyciem danych z serwisu webowego napisanego w PHP i przechowującym dane użytkowników bazie MySQL na dodatek niekoniecznie fizycznie przystosowanej do współpracy z ProFTPd \":)\".

","publishedAt":"2009-03-02T01:14:20Z","view":"views/sites/display/blog.xhtml","url":null,"commentingEnabled":true,"category":{"name":"Blog","slug":"blog","view":"views/sites/list/blog.xhtml","siteView":"views/sites/display/blog.xhtml"},"tags":[{"name":"Web","slug":"web"},{"name":"MySQL","slug":"mysql"},{"name":"ProFTPd","slug":"proftpd"},{"name":"Tutorial","slug":"tutorial"}]},{"name":"CupSell.pl","slug":"cupsell-pl","content":"

CupSell.pl uruchomiony

\n

Po bardzo długim etapie tworzenia wreszcie w formie przystępnej dla użytkownika został uruchomiony system CupSell.pl. O historii tworzenia tego serwisu moglibyśmy napisać książkę, a gdybyśmy założyli kanał RSS na nowinki o rozwoju to wszystcy zostaliby zaspamowani wiadomościami. Burzliwie przebiegał ten proces - wystarczy wspomnieć, że zanim w projekt zaangażował się cHeSteR to przewinęło się conajmniej 3 (jeśli dobrze liczę) grafików, a sama praca nad serwisem zaczęła się już kilka lat temu (sic!). Ale w końcu powstał i chyba ma się dobrze \":)\". Oczywiście wciąż jest wiele do zrobienia, ale najprościej rzecz ujmując - działa!

\n

Czym jest kapsel?

\n

CupSell.pl to platforma sklepowa, która oferuje możliwość stowrzenia włąsnych nadruków na koszulki (w pierwotnej wersji, aczkolwiek asortyment obejmuje także bluzy, a nawet poduszki, czy pluszowe misie). Na stronie można zaprojektować koszulkę, a następnie stworzyć sklep, w krótym będzie się ją sprzedawać czerpiąc z tego zyski w postacii prowizji od sprzedaży. Oczywiście można też zamówić sobie dowolnie zaprojektowaną koszulkę zamiast dodawania jej do sklepu. System od strony technicznej w całości został zaprojektowany i wykonany przez mnie, szata graficzna i szablony to działka cDStudio, a właścicielem i pomysłodawcą jest Marcin Majzner.

\n

Gorąco zachęcam do skorzystania z serwisu \":)\". Koszulka z ciekawym bądź zabawnym nadrukiem to dobry pomysł na niecodzinny prezent, albo zwrócenie na siebie uwagi.

\n

Neverending story

\n

Oczywiście to nie koniec i prace ciągle trwają i mają na celu rozwuk \"kapsla\", ale serwis jest już w pełni dostępny i (mamy nadzieję) funkcjonalny.

","publishedAt":"2008-11-23T01:09:42Z","view":"views/sites/display/blog.xhtml","url":null,"commentingEnabled":true,"category":{"name":"Blog","slug":"blog","view":"views/sites/list/blog.xhtml","siteView":"views/sites/display/blog.xhtml"},"tags":[{"name":"Web","slug":"web"},{"name":"Praca","slug":"praca"},{"name":"Portfolio","slug":"portfolio"},{"name":"Koszulki","slug":"koszulki"},{"name":"PHP","slug":"php"}]}],"total":17,"current":1,"pageSize":10,"tag":{"name":"Web","slug":"web"}} }; require("moment/locale/pl"); //]]>
Rafał Wrzeszcz - Wrzasq.pl

Przegląd frameworków JavaScript: dojo

Wednesday, 10 June 2009, 03:51

JavaScript jest obowiązkowym elementem każdej nowoczesnej aplikacji webowej. Ja sam jestem w nim powiedzmy średnio-zaawansowany: tego co jest potrafię używać do czego potrzeba, ale poezji w nim nie stworzę. We własnych aplikacjach piszę kod dość łopatologicznie, natomiast kiedy tworzę coś, co musi zadziałać i to sprawnie, wykorzystuję framework, do którego akurat jest dostępne przystępne case study projektów podobnych do tego, co właśnie muszę wyposażyć w interfejs wygodniejszy niż czysty XHTML+CSS. Jednak z czasem stało się to niewygodne, bo zamiast przyzwyczajać się chociaż do jednego frameworka, za każdym razem zaczynałem pracę od nowa. Postanowiłem wstawić w swój silnik webowy jakiś konkretny framework. Postanowiłem przejrzeć 4 popularne frameworki - dojo, jQuery, MooTools i Prototype. Początkowo brałem też pod uwagę YUI, jednak po przejrzeniu dokumentacji i przykładów doszedłem do wniosku, że jest on nieadekwatny do moich potrzeb. To czego potrzebowałem nie jest tam wcale uproszczone (na przykład brak wsparcia dla przesyłania danych za pośrednictwem XHR wykorzystując JSON, a sam framework jest niewątpliwie stworzony z myślą o wysoce skalowalnych, dużych serwisach - ja JavaScript wykorzystuję na mniejszą skalę. Postanowiłem się więc podzielić swoimi spostrzeżeniami na temat wspomnianych bibliotek. Nie będą to tutoriale, ale moje subiektywne oceny, może pomogą komuś w podjęciu decyzji.

Tags: Web, Teksty, JavaScript, AJAX, DOM

» Komentarze

Mapy Google na swojej stronie

Friday, 05 June 2009, 06:12

Wielu z Was pewnie nieraz widziało na przeróżnych stronach zamieszczone mapki Google'a jako interaktywne wstawki. Ba, nawet pokazujące miejsce, o którym akurat strona traktuje. Umieszczenie takiej mapki na stronie wcale nie jest trudne, a wręcz banalnie proste - wszystko dzięki rozbudowanemu API udostępnionemu przez Google. Google Maps API począwszy od wersji 2 dostępne jest za pośrednictwem standardowego interfejsu JavaScript udostępnianego przez Google. Obecnie w wersji testowej jest już trzecia wersja API do map, jednak ja opiszę tutaj obecnie dostępną jako stabilną wersję drugą, zresztą nie sądzę, aby w podstawowych wywołaniach zaszły diametralne zmiany. Zanim jednak zaczniemy pracę musimy wygenerować sobie klucz dostępu. W tym cely musimy się udać na stronę rejestracji i podać URL strony, na której chcemy używać map. Tutaj od razu uwaga - wpisujemy taki adres, po jakim będą na stronę wchodzić użytkownicy. Google nie sprawdza IP, hosta, ani niczego innego związanego z połączeniem - jedynie URL jaki został wpisany w przeglądarce. Oznacza to, że jeśli mamy skrypt dostępny pod kilkoma domenami, to musimy wstawiać odpowiednie klucze dla każdej domeny. Z drugiej strony, nawet jeśli pracujemy na tymczasowej domenie, albo wręcz w testowym środowisku, nie będzie potem potrzeby zmiany klucza. Mając klucz możemy przejść do kwestii technicznych. Opiszę tutaj jedynie podstawy korzystania z Google Maps API, szczegółową dokumentację znajdziecie tutaj.

Tags: Web, JavaScript, Tutorial, Google

» Komentarze

Od podstaw: XML

Monday, 30 March 2009, 01:17

XML to "rozszerzalny język znaczników" (ang. eXtensible Markup Language). Oznacza to, że jest to język uniwersalny przeznaczony do tworzenia języków oznaczeń - sam w sobie jest jedynie zbiorem zasad składni, definiuje pewne mechanizmy rządzące dokumentem, nie definiuje za to żadnych znaczników ani atrybutów. Innymi słowy XML określa jedynie format zapisu, a nie format samych danych. Robią to dopiero języki oparte na XML-u takie jak XHTML, RSS i wiele innych. Sam XML jest pochodnym SGML, a ten z kolei wywodzi się z GML. Nie będę ich tutaj omawiał, jednak ich idea jest podobna. Zostały one opracowane w celu przechowywania i współdzielenia dokumentów w jednolity sposób na przestrzeni lat. XML jest w gruncie rzeczy uproszczoną wersją SGML - ogranicza jego implementacje tylko do domyślnej składni, ujednolica wiele zagadnień (jak chociażby "puste" tagi). O XML-u pewnie obiło się wielu osobą o uszy, często jednak nie zdają sobie sprawy jak ważne są niektóre jego aspekty. Widać to chociażby w przypadku stron WWW tworzonych w tej technologii (korzystając z języka XHTML).

Tags: Web, Technologie, Teksty, XML

» Komentarze

Chillout Development

Monday, 23 March 2009, 01:40

Miło mi jest poinformować, że właśnie ruszyła inicjatywa Chillout Development. Jest to efekt mojej współpracy z cDStudio-web.com i Studio74.pl. Od teraz pod wspólnym szyldem będziemy realizować projekty zarówno na zewnątrz jak i własne.

Tags: Web, Praca, Portfolio, Chillout, PHP, Firma

» Komentarze

Od podstaw: Unicode i UTF-8

Thursday, 05 March 2009, 17:50

W Internecie od niemal zawsze mają miejsce problemy z kodowaniem (zapisem znaków). Dziś praktycznie powszechnie korzysta się z Unicode (czy też po spolszczeniu - Unikod). Jednak nadal wiele osób, szczególnie nieobeznanych z nim nie ma zbytnio pojęcia czym on jest i dlaczego jest taki ważny. Przeważnie dotyczy to osób korzystających ze środowiska Microsoft Windows i żadnego innego, ponieważ nie zdają sobie oni nieraz sprawy z różnorodności pozostałych platform. Skąd jednak całe to zamieszanie? Zacznijmy od początku.

Tags: Web, Teksty, UTF, Unicode

» Komentarze

Konfiguracja serwisu z kontami FTP

Monday, 02 March 2009, 01:14

Dość ciekawym zagadnieniem, jakie ostatnio musiałem poruszyć przy tworzeniu pewnego projektu jest udostępnianie użytkownikom sewrisu dodatkowych usług. Nie mam tutaj na myśli jakichś usług do wybrania na stronie, ale usług sieciowych. Konkretnie problematyka była taka, aby każdy użytkownik serwisu webowego miał dostęp do serwera FTP z własnym kontem. Serwis oczywiście miał swoją własną bazę MySQL z kontami użytkowników.

Tags: Web, MySQL, ProFTPd, Tutorial

» Komentarze

CupSell.pl

Sunday, 23 November 2008, 01:09

Po bardzo długim etapie tworzenia wreszcie w formie przystępnej dla użytkownika został uruchomiony system CupSell.pl. O historii tworzenia tego serwisu moglibyśmy napisać książkę, a gdybyśmy założyli kanał RSS na nowinki o rozwoju to wszystcy zostaliby zaspamowani wiadomościami. Burzliwie przebiegał ten proces - wystarczy wspomnieć, że zanim w projekt zaangażował się cHeSteR to przewinęło się conajmniej 3 (jeśli dobrze liczę) grafików, a sama praca nad serwisem zaczęła się już kilka lat temu (sic!). Ale w końcu powstał i chyba ma się dobrze :). Oczywiście wciąż jest wiele do zrobienia, ale najprościej rzecz ujmując - działa!

Tags: Web, Praca, Portfolio, Koszulki, PHP

» Komentarze