Podręcznik:Architektura MediaWiki
Od samego początku MediaWiki zostało stworzone specjalnie jako oprogramowanie dla Wikipedii. Deweloperzy pracowali nad ułatwieniem ponownego wykorzystania tego oprogramowania przez użytkowników zewnętrznych, ale wpływ i jednostronność Wikipedii kształtowały architekturę MediaWiki w całej historii.
Wikipedia jest jedną z dziesięciu największych stron internetowych na świecie, obecnie ma około 400 milionów unikatowych odwiedzających miesięcznie. Uzyskuje ponad 100 000 wywołań na sekundę. Wikipedia nie jest wspierana komercyjnie przez reklamy; jest całkowicie wspierana przez organizację non-profit, Fundację Wikimedia, która opiera się na darowiznach jako podstawowym modelu finansowania. Oznacza to, że MediaWiki musi nie tylko prowadzić stronę internetową z pierwszej dziesiątki, ale także robić to przy skromnym budżecie. Aby sprostać tym wymaganiom, MediaWiki kładzie silny nacisk na wydajność, buforowanie i optymalizację. Kosztowne funkcje, których nie można włączyć w Wikipedii, są wycifywane lub wyłączane za pomocą zmiennej konfiguracyjnej; Istnieje nieskończona równowaga między wydajnością a funkcjonalościami.
Wpływ Wikipedii na architekturę MediaWiki nie ogranicza się do wydajności. W przeciwieństwie do ogólnych CMS-ów, MediaWiki zostało pierwotnie napisane w bardzo konkretnym celu: wspierania społeczności, która tworzy i opiekuje się swobodnie współużywalną wiedzą na otwartej platformie. Oznacza to na przykład, że MediaWiki nie zawiera standardowych funkcji dostępnych w korporacyjnych CMS-ach (takich jak łatwy przepływ pracy publikacji czy listy dostępu ACL), ale oferuje różnorodne narzędzia do radzenia sobie ze spamem i wandalizmem.
Od samego początku potrzeby i działania stale rozwijającej się społeczności uczestników Wikipedii wpłynęły na rozwój MediaWiki - i odwrotnie! Architektura MediaWiki była wielokrotnie inspirowana przez inicjatywy rozpoczęte lub wyproszone przez społeczność, takie jak utworzenie Wikimedia Commons lub funkcja Oflagowanych Wersji. Programiści dokonali poważnych zmian w architekturze, takich jak preprocesor MediaWiki 1.12, ponieważ sposób, w jaki Wikipedyści korzystali z MediaWiki, wymagał tego.
MediaWiki zyskało również solidną bazę użytkowników zewnętrznych dzięki temu, że jest oprogramowaniem open-source. Zewnętrzni użytkownicy wiedzą, że tak długo tak popularna strona internetowa jak Wikipedia korzysta z MediaWiki, oprogramowanie będzie utrzymywane i ulepszane. MediaWiki dotychczas koncentrowała się na witrynach Wikimedia, ale postanowiono uczynić ją bardziej ogólną i lepiej odpowiadać potrzebom użytkowników stron trzecich. Na przykład, MediaWiki jest dostarczane z doskonałym instalatorem internetowym, dzięki czemu proces instalacji jest znacznie mniej bolesny niż wtedy, gdy wszystko musiało być wykonane za pomocą wiersza poleceń, a oprogramowanie zawierało zakodowane na stałe ścieżki dla Wikipedii.
Mimo to, MediaWiki jest i pozostaje oprogramowaniem Wikipedii, co widać w całej jej historii i architekturze.
Baza kodu i najlepsze praktyki MediaWiki
Warstwa użytkownika | przeglądarka internetowa | ||
---|---|---|---|
Warstwa sieciowa | Varnish | ||
Serwer WWW Apache | |||
Warstwa logiczna | Skrypty PHP MediaWiki | ||
PHP | |||
Warstwa danych | System plików | Baza danych MySQL (program i zawartość) | System buforowania |
PHP
PHP został wybrany jako framework dla oprogramowania Wikipedii "Phase II" w 2001 roku; Od tego czasu MediaWiki rozrosła się organicznie i wciąż ewoluuje. Większość programistów MediaWiki to wolontariusze wnoszący swój wkład w swoim wolnym czasie, a we wczesnych latach było ich bardzo niewielu. Z perspektywy czasu niektóre decyzje lub pominięcia w projektowaniu oprogramowania mogą wydawać się błędne, ale trudno krytykować założycieli za to, że nie zaimplementowali jakiejś abstrakcji, która teraz okazuje się krytyczna, gdy początkowa baza kodu była tak mała, a czas potrzebny na jej opracowanie - tak krótki.
Na przykład, MediaWiki używa nazw klas bez prefiksu, co może powodować konflikty, gdy programiści PHP core i PECL dodają nowe klasy.
W konsekwencji, klasa MediaWiki Namespace
musiała zostać przemianowana na MWNamespace
, aby była kompatybilna z PHP 5.3.
Konsekwentne używanie prefiksu dla wszystkich klas (np. "MW
") ułatwiłoby osadzanie MediaWiki w innej aplikacji lub bibliotece.
Poleganie na PHP prawdopodobnie nie było najlepszym wyborem pod względem wydajności, ponieważ nie skorzystało ono z ulepszeń, które otrzymały niektóre inne dynamiczne języki. Użycie języka Java byłoby znacznie lepsze pod względem wydajności i uproszczonego skalowania zadań konserwacji back-endu. Z drugiej strony PHP cieszy się dużą popularnością, co ułatwia rekrutację nowych programistów.
Nawet jeśli MediaWiki nadal zawiera "brzydki" przestarzały kod, na przestrzeni lat wprowadzono wiele ulepszeń, a nowe elementy architektury zostały wprowadzone do MediaWiki w całej jej historii.
Należą do nich klasy Parser
, SpecialPage
i Database
, klasa Image
i hierarchia klas FileRepo
, hierarchia ResourceLoader
i Action
.
MediaWiki zaczynało bez żadnej z tych rzeczy, ale wszystkie z nich obsługują funkcje, które istnieją od samego początku.
Wielu programistów jest zainteresowanych przede wszystkim rozwojem funkcjonalności, a architektura często pozostaje w tyle - tylko po to, by później nadrobić zaległości, kiedy koszt pracy w niedopasowanej architekturze staje się widoczny.
Ponieważ MediaWiki jest oprogramowaniem obsługującym sławne witryny internetowe, takie jak Wikipedia - główni programiści i recenzenci kodu narzucili surowe zasady bezpieczeństwa.
Aby ułatwić pisanie bezpiecznego kodu, MediaWiki daje programistom wrappery na temat wyszukiwania HTML i danych, aby poradzić sobie z ucieczką.
Aby zdezyfekować dane wejściowe użytkownika, używa się klasy WebRequest
, która analizuje dane przekazane w adresie URL lub za pośrednictwem formularza POSTed.
Usuwa ukośniki z "magicznymi cudzysłowami", usuwa niedozwolone znaki wejściowe i normalizuje sekwencje napisów Unicode.
Cross-site request forgery (CSRF) jest unikane za pomocą tokenów, a cross-site scripting (XSS) poprzez walidację danych wejściowych i ucieczki danych wyjściowych, zwykle za pomocą funkcji htmlspecialchars()
PHP.
MediaWiki zapewnia (i wykorzystuje) również dezyfekcję HTML przy pomocy klasy Sanitizer
oraz funkcje bazy danych, które zapobiegają wstrzyknięciu SQL.
Konfiguracja
MediaWiki oferuje setki ustawień konfiguracji, przechowywanych w globalnych zmiennych PHP.
Ich domyślna wartość jest ustawiona na DefaultSettings.php
, a administrator systemu może je odwrócić poprzez edycję LocalSettings.php
.
MediaWiki było zbyt uzależnione od zmiennych globalnych, w tym w zakresie konfiguracji i przetwarzania kontekstu.
Zmienne globalne powodują poważne konsekwencje bezpieczeństwa z funkcją PHP register_globals
(której MediaWiki nie potrzebuje od wersji 1.2).
System ten ogranicza również potencjalne abstrakcje konfiguracji i utrudnia optymalizację procesu uruchamiania.
Co więcej, przestrzeń nazw konfiguracji jest współdzielona ze zmiennymi używanymi do rejestracji i kontekstu obiektu, co prowadzi do potencjalnych konfliktów.
Z punktu widzenia użytkownika, globalne zmienne konfiguracji sprawiły, że MediaWiki wydawało się trudne do konfigurowania i utrzymania.
Rozwój MediaWiki to historia powolnego przenoszenia kontekstu ze zmiennych globalnych do obiektów.
Przechowywanie kontekstu przetwarzania w zmiennych składowych obiektu pozwala na bardziej elastyczne ponowne wykorzystanie tych obiektów.
Baza danych i przechowywanie tekstu
MediaWiki korzysta z zaplecza relacyjnej bazy danych od czasu oprogramowania Fazy II. Domyślnym (i najlepiej obsługiwanym) systemem DBMS dla MediaWiki jest MySQL, z którego korzystają wszystkie strony Wikimedia. Jednak inne systemy DBMS (takie jak PostgreSQL, Oracle i SQLite) mają implementacje obsługiwane przez społeczność. Sysadmin może wybrać DBMS podczas instalacji MediaWiki, a MediaWiki zapewnia zarówno abstrakcję bazy danych, jak i warstwę abstrakcji zapytania, która ułatwia dostęp do bazy danych dla deweloperów.
bieżący układ zawiera dziesiątki tabel.
Wiele z nich dotyczy treści wiki (np. page
, revision
, category
, recentchanges
).
Inne tabele - między innymi- obejmują dane dotyczące użytkowników (user
, user_groups
), plików multimedialnych (image
, filearchive
), pamięci podręcznej (objectcache
, l10n_cache
, querycache
) i narzędzi wewnętrznych (job
dla kolejki zadań).
Indeksy i tabele podsumowujące są szeroko stosowane w MediaWiki, ponieważ zapytania SQL, które skanują ogromną liczbę wierszy, mogą być kosztowne (zwłaszcza na stronach Wikimedia).
Zapytania nieindeksowane są zwykle odradzane.
Baza danych przeszła dziesiątki zmian schematu na przestrzeni lat, z których najbardziej godną uwagi było rozdzielenie przechowywania tekstu i śledzenia wersji w MediaWiki 1.5.
W modelu 1.4 treść była przechowywana w dwóch ważnych tabelach, cur
(zawierających tekst i metadane aktualnej rewizji strony) i old
(zawieranie poprzednich rewizji); usunięte strony były przechowywane w archive
.
Po wprowadzeniu zmian poprzednio bieżąca poprawka została skopiowana do tabeli old
, a nowa edycja została zapisana do cur
.
Kiedy strona została przemianowana, tytuł strony musiał zostać zaktualizowany w metadatach wszystkich old
wersji zmian, co mogłoby być długą operacją.
Gdy strona była usuwana, jej wpisy w tabelach cur
i old
musiały zostać skopiowane do tabeli archive
przed usunięciem; Oznaczało to przeniesienie tekstu wszystkich poprawek - które mogły być bardzo duże - a tym samym czasochłonne.
W modelu 1.5 metadane wersji i tekst wersji zostały podzielone: tabele cur
i old
zostały zastąpione przez page
(metadane stron), revision
(metadane dla wszystkich wersji, starych lub bieżących) i text
(tekst wszystkich wersji, starych, bieżących lub usuniętych).
Teraz, gdy wprowadzana jest edycja, metadane poprawki nie muszą być kopiowane miedzy tabelami. Wystarczy wstawić nowy wpis i zaktualizować wskaźnik page_latest
.
Ponadto, metadane wersji nie zawierają już tytułu strony, a jedynie jej identyfikator: eliminuje to potrzebę zmiany nazw wszystkich wersji, gdy nazwa strony jest zmieniana.
Tabela revision
przechowuje metadane dla każdej wersji, ale nie ich tekst; zamiast tego zawierają identyfikator tekstowy wskazujący tabelę text
, która zawiera rzeczywisty tekst.
Gdy strona zostanie usunięta, tekst wszystkich wersji strony pozostaje na niej i nie trzeba go przenosić do innej tabeli.
Tabela text
składa się z mapowania identyfikatorów na tekstowe obiekty blob; Pole Flags wskazuje, czy tekstowy obiekt blob jest spakowany metodą Gzip (w celu zaoszczędzenia miejsca), czy też tekstowy obiekt blob jest tylko wskaźnikiem do zewnętrznego magazynu tekstu.
Strony Wikimedia korzystają z zewnętrznego klastra pamięci masowej wspieranego przez MySQL, z polami binarnymi typu blob zawierającymi kilkadziesiąt wersji.
Pierwsza wersja obiektu blob jest przechowywana w całości, a kolejne wersje tej samej strony są przechowywane jako różnice względem poprzedniej wersji; Obiekty blob są następnie spakowane w gzip.
Ponieważ wersje są pogrupowane wg stron, to zwykle są podobne - więc różnice są stosunkowo małe i gzip działa dobrze.
Współczynnik kompresji osiągnięty na witrynach Wikimedia jest bliski 98%.
MediaWiki ma również wbudowaną obsługę równoważenia obciążenia, dodaną już w 2004 roku w MediaWiki 1.2 (kiedy Wikipedia otrzymała swój drugi serwer - w tamtych czasach była to wielka sprawa). Load balancer (kod PHP MediaWiki, który decyduje, z którym serwerem się połączyć) jest teraz krytyczną częścią infrastruktury Wikimedia, co wyjaśnia jego wpływ na niektóre decyzje algorytmów w kodzie. Administrator systemu może określić w konfiguracji MediaWiki, że istnieje jeden główny serwer bazy danych i dowolna liczba podrzędnych serwerów baz danych; Do każdego serwera można przypisać wagę. Load balancer wyśle wszystkie zapisy do mastera i zrównoważy odczyty zgodnie z wagami. Śledzi również opóźnienie replikacji każdego urządzenia podrzędnego. Jeśli opóźnienie replikacji urządzenia podrzędnego przekroczy 30 sekund, nie otrzyma ono żadnych zapytań odczytu, które pozwoliłyby mu nadrobić zaległości; jeśli wszystkie urządzenia podrzędne są opóźnione o więcej niż 30 sekund, MediaWiki automatycznie przełączy się w tryb tylko do odczytu.
"Zabezpieczenie chronologii" MediaWiki zapewnia, że opóźnienie replikacji nigdy nie spowoduje, że użytkownik zobaczy stronę, która twierdzi, że akcja, którą właśnie wykonał, jeszcze się nie wydarzyła. Odbywa się to poprzez zapisanie pozycji wzorca w sesji użytkownika, jeśli wysłane przez niego żądanie spowodowało zapytanie zapisu. Następnym razem, gdy użytkownik zażąda odczytu, moduł równoważenia obciążenia odczytuje tę pozycję z sesji i próbuje wybrać urządzenie podrzędne, które dogoniło tę pozycję replikacji, aby obsłużyć żądanie. Jeśli żaden z nich nie jest dostępny, zaczeka, aż będzie. Inni użytkownicy mogą postrzegać akcję jako jeszcze nie dokonaną, ale chronologia pozostaje spójna dla każdego użytkownika.
Zapytania, buforowanie i dostarczanie
Przepływ pracy wykonywania żądania internetowego
index.php
jest głównym punktem dostępowym dla MediaWiki i obsługuje większość żądań przetwarzanych przez serwery aplikacji (tj. żądań, które nie były obsługiwane przez infrastrukturę buforowania; patrz niżej).
Kod wykonywany od index.php
przeprowadza kontrole bezpieczeństwa, ładuje domyślne ustawienia konfiguracji od includes/DefaultSettings.php
, odgaduje konfigurację z includes/Setup.php
, a następnie aplikuje ustawienia witryny zawarte w LocalSettings.php
.
Następnie tworzy instancję obiektu o wartości MediaWiki
($mediawiki
) i tworzy obiekt Title
($wgTitle
) w zależności od tytułu i parametrów akcji z zapytania.
index.php
może przyjmować różne parametry akcji w żądaniu adresu URL; Domyślna akcja to view
, która pokazuje zwykły widok zawartości artykułu.
Na przykład, żądanie https://en.wikipedia.org/w/index.php?title=Apple&action=view
wyświetla treść artykułu "Apple" w angielskiej Wikipedii[1].
Inne częste działania to edit
(aby otworzyć artykuł do edycji), submit
(aby wyświetlić podgląd lub zapisać artykuł), history
(aby wyświetlić historię artykułu) i watch
(aby dodać artykuł do listy obserwowanych użytkownika).
Działania administracyjne obejmują delete
(w celu usunięcia artykułu) i protect
(w celu zablokowania edycji artykułu).
MediaWiki::performRequest()
jest następnie wywoływany w celu obsłużenia większości żądań adresu URL.
Sprawdza, czy nie ma złych tytułów, ograniczeń odczytu, lokalnych przekierowań interwiki i pętli przekierowań, a także określa, czy zapytanie dotyczy normalnej czy specjalnej strony.
Normalne zapytania stron są przekazywane do MediaWiki::initializeArticle()
, aby utworzyć obiekt Article
dla strony ($wgArticle
), a następnie do MediaWiki::performAction()
, który obsługuje "standardowe" akcje.
Po zakończeniu akcji MediaWiki::doPostOutputShutdown()
finalizuje żądanie, zatwierdzając transakcje bazy danych, wyprowadzając kod HTML i uruchamiając odroczone aktualizacje za pośrednictwem kolejki zadań.
MediaWiki::restInPeace()
zatwierdza odroczone aktualizacje i bezpiecznie zamyka zadanie.
Jeśli żądana strona jest stroną specjalną (tj. nie jest to zwykła strona wiki, ale specjalna strona związana z oprogramowaniem, taka jak Statistics
), wywoływane jest SpecialPageFactory::executePath
zamiast initializeArticle()
; następnie wywoływany jest odpowiedni skrypt PHP.
Strony specjalne mogą robić różnego rodzaju magiczne rzeczy, a każda z nich ma określony cel, zwykle niezależnie od pojedynczego artykułu lub jego treści.
Specjalne strony zawierają między innymi różnego rodzaju raporty (ostatnie zmiany, logi, strony bez kategorii) i narzędzia do administrowania wiki (m.in. blokady użytkowników, zmiany uprawnień użytkowników).
Ich przepływ pracy zależy od ich funkcji.
Wiele funkcji zawiera kod profilowania, który umożliwia śledzenie przepływu pracy wykonywania w celu debugowania - jeśli profilowanie jest włączone.
Profilowanie odbywa się przez wywołanie funkcji wfProfileIn
i wfProfileOut
w celu odpowiedniego rozpoczęcia i zakończenia profilowania funkcji; Obie funkcje przyjmują nazwę funkcji jako parametr.
Na stronach Wikimedia profilowanie jest ograniczone dla pewnej części wszystkich żądań - aby zachować wydajność.
MediaWiki wysyła pakiety UDP na centralny serwer, który zbiera je i produkuje dane profilowe.
Montaż strony niebuforowanej
Podczas przeglądania strony kod HTML może zostać pobrany z pamięci podręcznej (patrz poniżej); Jeśli nie, najpierw rozwijane są szablony, funkcje parsera i zmienne. Daje to wikikod rozwinięty, wynik pośredni, który można zobaczyć za pomocą Special:ExpandTemplates, i zależy on od:
- wikikodu;
- szablonów bezpośrednio lub pośrednio odnoszących się do nich;
- Funkcji parsera powoływanych bezpośrednio lub pośrednio;
- Wartości zmiennych odnoszących się bezpośrednio lub pośrednio.
W nastęnym kroku ten rozszerzony wikikod jest konwertowany na kod HTML; Jest on wysyłany do użytkownika i zawiera odwołania do plików CSS, JavaScript i plików obrazów. Użytkownik może zobaczyć ten pośredni wynik, stosując opcję "wyświetl źródło" przeglądarki. Kod HTML danej strony zależy od:
- rozwiniętego wikitekstu;
- trybu, takiego jak przeglądanie lub edycja (patrz poniżej);
- istnienia stron wewnętrznie powiązanych (zwróci widok lub edycję linka);
- skórka i inne preferencje użytkownika;
- nazwę użytkownika;
- statusu użytkownika (więcej linków, jeśli jest administratorem itp.);
- przestrzeń nazw (określa link do strony dyskusji lub, w przypadku strony dyskusji, do danej strony);
- czy strona jest obserwowana przez użytkownika (podaje link obserwuj lub przestań obserwować);
- czy strona dyskusji użytkownika była ostatnio edytowana (wyświetla komunikat).
Na koniec przeglądarka renderuje kod HTML przy użyciu plików, do których się odwołuje. Wynik, który użytkownik widzi na ekranie, zależy od:
- kod HTML;
- plików, o których mowa w kodzie HTML, takich jak obrazy osadzone, pliku CSS z serwera i pliki JavaScript;
- przeglądarki i ustawień przeglądarki, w tym ewentualnie lokalnego pliku CSS, oraz rozdzielczości ekranu.
Jeśli JavaScript reaguje na zdarzenie, takie jak kliknięcie myszą, strona na ekranie zależy również od tych zdarzeń. Dotyczy to na przykład tabeli sortowalnej.
Gdy użytkownik wybierze zakładkę edytuj, wysyłany jest do niego sam wikikod, obejmujący całą stronę lub tylko jedną sekcję. Gdy użytkownik naciśnie Pokaż podgląd, jego nowa wersja wikikodu jest wysyłana na serwer, który wysyła odpowiednią nową wersję kodu HTML, która jest ponownie renderowana i wyświetlana powyżej lub poniżej nowej wersji wikikodu użytkownika (którą serwer również zwrócił). Po możliwie większej liczbie zmian i podglądów, użytkownik naciska Zapisz stronę, wysyłając "ostateczną" wersję użytkownika na serwer, który teraz rejestruje edycję i wysyła HTML nowej wersji (ponownie). W niektórych przypadkach automatyczna konwersja wikitekstu również ma miejsce na tym etapie.
Buforowanie
Samo MediaWiki zostało ulepszone pod kątem wydajności, ponieważ odgrywa centralną rolę na stronach Wikimedia, ale jest również częścią większego ekosystemu operacyjnego, który wpłynął na jej architekturę. Infrastruktura buforowania Wikimedia nałożyła ograniczenia na MediaWiki; Programiści obeszli te problemy, nie próbując kształtować szeroko zoptymalizowanej infrastruktury buforowania Wikimedia wokół MediaWiki, ale raczej czyniąc MediaWiki bardziej elastycznym, aby mogło działać w ramach tej infrastruktury, bez uszczerbku dla wydajności i potrzeb buforowania.
Na stronach Wikimedia większość zapytań jest obsługiwana przez serwery proxy buforowania wstecznego (Squids) i nigdy nie dociera do serwerów aplikacji MediaWiki. Squids zawierają statyczne wersje całych renderowanych stron, dostarczane do prostych odczytów użytkownikom, którzy nie są zalogowani w witrynie. MediaWiki natywnie obsługuje Squid oraz Varnish i integruje się z tą warstwą buforowania, na przykład powiadamiając je o konieczności usunięcia strony z pamięci podręcznej, gdy ta została zmieniona. W przypadku zalogowanych użytkowników oraz innych zapytań, które nie mogą być obsłużone przez Squids, Squid przekazuje żądania do serwera WWW (Apache).
Drugi poziom buforowania ma miejsce, gdy MediaWiki renderuje i składa stronę z wielu obiektów, z których wiele może być buforowanych, aby zminimalizować przyszłe wywołania. Do takich obiektów należą interfejs strony (pasek boczny, menu, tekst interfejsu użytkownika) oraz właściwa zawartość, przetworzona z wikikodu. Pamięć podręczna obiektów przechowywanych w pamięci jest dostępna w MediaWiki od wczesnej wersji 1.1 (2003) i jest szczególnie ważna, aby uniknąć ponownego analizowania długich i złożonych stron.
Dane sesji logowania mogą być również przechowywane w memcached, co pozwala sesjom działać w sposób przezroczysty na wielu serwerach front-end w konfiguracji równoważenia obciążenia (Wikimedia w dużym stopniu polega na równoważeniu obciążenia, używając LVS razem z PyBal).
Od wersji 1.16, MediaWiki używa dedykowanego bufora obiektów dla zlokalizowanego językowo tekstu interfejsu użytkownika; Zostało to dodane po zauważeniu, że duża część obiektów buforowanych w memcached składała się z komunikatów interfejsu użytkownika zlokalizowanych w języku użytkownika. System opiera się na szybkim pobieraniu pojedynczych wiadomości z baz danych stałych (CDB), czyli plików z parami klucz-wartość. W typowym przypadku CDB minimalizują obciążenie pamięci i czas uruchamiania; Są one również używane w pamięci podręcznej interwiki.
Ostatnia warstwa buforowania składa się z pamięci podręcznej kodu operacyjnego PHP (ang. opcode), zwykle włączanej w celu przyspieszenia aplikacji PHP. Kompilacja może być długotrwałym procesem; Aby uniknąć kompilowania skryptów PHP do kodu pośredniego za każdym razem, gdy są wywoływane, akcelerator PHP może być użyty do przechowywania skompilowanego kodu operacji i wykonywania go bezpośrednio bez kompilowania. MediaWiki będzie "po prostu działać" z wieloma akceleratorami, takimi jak APC - akcelerator PHP.
Ze względu na swoje dopasowanie specjalnie do Wikimedii, MediaWiki jest optymalizowane dla tej kompletnej, wielowarstwowej, rozproszonej infrastruktury pamięci pamięci zapasowej. Niemniej jednak natywnie obsługuje również alternatywne konfiguracje dla mniejszych witryn. Na przykład oferuje opcjonalny uproszczony system buforowania plików, który przechowuje postacie wyjśiowe w pełni przetworzonych stron, tak jak robi to Squid. Ponadto, warstwa buforowania abstrakcyjnych obiektów MediaWiki pozwala na przechowywanie obiektów w pamięci podręcznej w kilku miejscach, w tym w systemie plików, bazie danych lub pamięci podręcznej opcode.
Podobnie jak wiele innych aplikacji internetowych, interfejs MediaWiki stał się z biegiem lat bardziej interaktywny i responsywny, głównie dzięki użyciu JavaScript. Działania na rzecz użyteczności zainicjowane w 2008 r., a także zaawansowana obsługa multimediów (np. edycja plików wideo online) wymagały dedykowanej poprawy wydajności front-endu.
Aby zoptymalizować dostarczanie zasobów JavaScript i CSS, opracowano moduł ResourceLoader. Została zapoczątkowany w 2009 roku, ukończony w roku 2011 i jest podstawową funkcją MediaWiki od wersji 1.17. ResourceLoader działa poprzez ładowanie zasobów JS i CSS na żądanie, skracając w ten sposób czas ładowania i parsowania nieużywanych funkcji, na przykład w starszych przeglądarkach. Minimalizuje również kod, grupuje zasoby w celu zapisywania żądań i może osadzać obrazy jako identyfikatory URI.
Języki
Kontekst i uzasadnienie
Najistotniejszą cześcią skutecznego przyczyniania się i rozpowszechniania wolnej wiedzy dla wszystkich jest dostarczanie jej w jak największej liczbie języków. Wikipedia jest dostępna w ponad 280 językach, a artykuły encyklopedii w języku angielskim stanowią mniej niż 20% wszystkich artykułów. Ponieważ Wikipedia i jej siostrzane strony istnieją w tak wielu językach, ważne jest nie tylko dostarczanie treści w języku ojczystym czytelników, ale także zapewnienie dopasowanego jezykowo interfejsu oraz skutecznych narzędzi do wprowadzania i konwersji treści, aby uczestnicy mogli bezproblemowo dopisywać wkład.
Z tego powodu, lokalizacja i internacjonalizacja (l10n i i18n) są centralnym komponentem MediaWiki. System i18n jest wszechobecny i wpływa na wiele części oprogramowania; Jest również jednym z najbardziej elastycznych i bogatych w funkcje. Wygoda tłumacza jest zwykle ceniona bardziej niż wygoda programisty - jednak uważa się, że jest to akceptowalny koszt.
MediaWiki jest obecnie zlokalizowane w ponad 350 językach, w tym w językach nie związanych z łacińskim oraz z zapisem od prawej do lewej (RTL), o różnym stopniu kompletności. Interfejs i zawartość mogą być w różnych językach i mogą mieć mieszaną kierunkowość pisma.
Język treści
MediaWiki pierwotnie używało kodowania według języka, co prowadziło do wielu problemów; Na przykład w tytułach stron nie można było używać obcych skryptów. Zamiast tego przyjęto UTF-8. Wsparcie dla zestawów znaków innych niż UTF-8 zostało porzucone w 2005 roku, wraz z dużą zmianą schematu bazy danych w MediaWiki 1.5; Treść musi być teraz zakodowana w UTF-8.
Znaki niedostępne na klawiaturze edytora mogą być dostosowywane i wstawiane za pomocą Edittools
w interfejsie MediaWiki, komunikatu wyświetlanego pod oknem edycji; jego wersja JavaScript automatycznie wstawia kliknięty znak do okna edycji.
Rozszerzenie WikiEditor dla MediaWiki, opracowane w ramach prac w zakresie poprawy użyteczności, łączy specjalne znaki z paskiem narzędzi edycji.
Inne rozszerzenie, zwane UniversalLanguageSelector , zapewnia dodatkowe metody wejścia i funkcje mapowania kluczowych znaków poza ASCII.
Niedawne i przyszłe ulepszenia obejmują lepszą obsługę tekstu pisanego od prawej do lewej, tekst dwukierunkowy (tekst LTR i RTL na tej samej stronie) oraz UniversalLanguageSelector .
Język interfejsu użytkownika
Komunikaty interfejsu są przechowywane w tablicach PHP w parach klucz-wartość od czasu stworzenia oprogramowania Phase III.
Każdy komunikat jest identyfikowany za pomocą unikalnego klucza, który ma przypisane różne wartości w różnych językach.
Klucze są określane przez deweloperów, którzy są zachęcani do używania prefiksów dla rozszerzeń; Na przykład, klucze wiadomości dla rozszerzenia UploadWizard będą zaczynać się od mwe-upwiz-
, gdzie mwe
oznacza MediaWiki extension.
Komunikaty MediaWiki mogą zawierać parametry dostarczone przez oprogramowanie, które często wpływają na gramatykę wiadomości. Aby zapewnić obsługę praktycznie każdego możliwego języka, system lokalizacji MediaWiki został z czasem ulepszony i złożony, aby dostosować się do ich specyficznych cech i wyjątków - często uważanych za kuriozum przez użytkowników języka angielskiego.
Na przykład przymiotniki są niezmiennąmi słowami w języku angielskim, ale języki takie jak francuski wymagają zgodności przymiotników z rzeczownikami.
If the user profile has gender preferences set, the {{GENDER:}}
switch can be used in interface messages to appropriately address them (more info).
Other switches include {{PLURAL:}}
, for "simple" plurals and languages like Arabic with dual, trial or paucal numbers, and {{GRAMMAR:}}
, providing grammatical transformation functions for languages like Finnish whose grammatical cases cause alterations or inflections.
The gender distinction can also be used in gender-dependent user namespace names, so that the title and URL of the page refers to the user correctly.
Standard MediaWiki namespaces' gender variants are defined via $namespaceGenderAliases
in each language's MessagesXx.php, while $wgExtraGenderNamespaces can be used for wiki-specific namespaces.
As of r107559, 13 languages use this feature by default:
- Arabic
- Czech
- German
- Lower Sorbian
- Spanish
- Galician
- Hebrew
- Upper Sorbian
- Polish
- Brazilian Portuguese
- Portuguese
- Russian
- Saterland Frisian
Localising messages
Localised interface messages for MediaWiki reside in MessagesXx.php
files, where Xx
is the ISO-639 code of the language (e.g. MessagesFr.php
for French); default messages are in English and stored in MessagesEn.php
.
MediaWiki extensions use a similar system, or host all localised messages in an [Extension-name].i18n.php
file.
Along with translations, Message files also include language-dependent information such as date formats.
Contributing translations used to be done by submitting PHP patches for the MessagesXx.php
files.
In December 2003, MediaWiki 1.1 introduced "database messages", a subset of wiki pages in the MediaWiki namespace containing interface messages.
The content of the wiki page MediaWiki:[Message-key]
is the message's text, and overrides its value in the PHP file.
Localised versions of the message are at MediaWiki:[Message-key]/[language-code]
, e.g. MediaWiki:Rollbacklink/de
.
This feature has allowed power users to translate (and customise) interface messages locally on their wiki, but the process doesn't update i18n files shipping with MediaWiki.
In 2006, Niklas Laxström created a special, heavily hacked MediaWiki website (now hosted at translatewiki.net
) where translators can easily localise interface messages in all languages, simply by editing a wiki page.
The MessagesXx.php
files are then updated in the MediaWiki code repository, where they can be automatically fetched by any wiki.
On Wikimedia sites, database messages are now only used for customisation, and not for localisation any more.
MediaWiki extensions and some related programs, such as bots, are also localised at translatewiki.net.
To help translators understand the context and meaning of an interface message, it is considered a good practice in MediaWiki to provide documentation for every message.
This documentation is stored is a special Message file, with the qqq
language code, which doesn't correspond to a real language.
The documentation for each message is then displayed in the translation interface on translatewiki.net.
Another helpful tool is the qqx
language code: when used with the &uselang
parameter to display a wiki page (e.g. en.wikipedia.org/wiki/Special:RecentChanges?uselang=qqx
), MediaWiki will display the message keys instead of their values in the user interface; this is very useful to identify which message to translate or change.
Registered users can set their own interface language in their preferences, in which case it overrides the site's default interface language.
MediaWiki also supports fallback languages: if a message isn't available in the chosen language, it will be displayed in the closest possible language, and not necessarily in English. For example, the fallback language for Breton is French.
Users
Users are represented in the code using instances from the User
class, which encapsulates all of the user-specific settings (user id, name, rights, password, email address, etc.).
Client classes use accessors to access these fields; they do all the work of determining whether the user is logged in, and whether the requested option can be satisfied from cookies or whether a database query is needed.
Most of the settings needed for rendering normal pages are set in the cookie to minimise use of the database.
MediaWiki provides a very granular permissions system, with basically a user permission for every possible action. For example, to perform the "Rollback" action (i.e. to "quickly rollback the edits of the last user who edited a particular page"), a user needs the rollback
permission, included by default in MediaWiki's sysop
user group.
But it can also be added to other user groups, or have a dedicated user group only providing this permission (this is the case on the English Wikipedia, with the Rollbackers
group). Customisation of user rights is done by editing the $wgGroupPermissions
array in LocalSettings.php
; for instance, $wgGroupPermissions['user']['movefile'] = true;
allows all registered users to rename files.
A user can belong to several groups, and inherits the highest rights associated with each of them.
However, MediaWiki's user permissions system was really designed with Wikipedia in mind, i.e. a site whose content is accessible to all, and only certain actions are restricted to some users. MediaWiki lacks a unified, pervasive permissions concept; it doesn't provide traditional CMS features like restricting read or write access by namespace, category, etc. A few MediaWiki extensions provide such features to some extent.
Content
Content structure
The concept of namespaces was used in the UseModWiki era of Wikipedia, where talk pages were at the title "[article name]/Talk".
Namespaces were formally introduced in Magnus Manske's first "PHP script".
They were reimplemented a few times over the years, but have kept the same function: to separate different kinds of content.
They consist of a prefix, separated from the page title by a colon (e.g. Talk:
or File:
and Template:
); the main content namespace has no prefix.
Wikipedia users quickly adopted them, and they provided the community with different spaces to evolve.
Namespaces have proven to be an important feature of MediaWiki, as they create the necessary preconditions for a wiki's community and set up meta-level discussions, community processes, portals, user profiles, etc.
The default configuration for MediaWiki's main content namespace is to be flat (no subpages), because it's how Wikipedia works, but it is trivial to enable them.
They are enabled in other namespaces (e.g. User:
, where people can for instance work on draft articles) and display breadcrumbs.
Namespaces separate content by type; within a same namespace, pages can be organised by topic using categories, a pseudo-hierarchical organisation scheme introduced in MediaWiki 1.3.
Content processing: MediaWiki markup language & Parser
The user-generated content stored by MediaWiki isn't in HTML, but in a markup language specific to MediaWiki, sometimes called "wikitext". It allows users to make formatting changes (e.g. bold, italic using quotes), add links (using square brackets), include templates, insert context-dependent content (like a date or signature), and make an incredible number of other magical things happen.
To display a page, this content needs to be parsed, assembled from all the external or dynamic pieces it calls, and converted to proper HTML. The parser is one of the most essential parts of MediaWiki, which also makes it difficult to change or improve. Because hundreds of millions of wiki pages worldwide depend on the parser to continue outputting HTML the way it always has, it has to remain extremely stable.
The markup language wasn't formally spec'd from the beginning; it started based on UseModWiki's markup, then morphed and evolved as needs have demanded. For example, the usage of a ThreadMode format for discussions made Magnus Manske implement the 3 or 4 tildes (~~~~) as a shortcut to sign one's posts in unstructured text. Tildes were chosen as it resembled his father's hand-written signature.[2]
In the absence of a formal specification, the MediaWiki markup language has become a complex and idiosyncratic language, basically only compatible with MediaWiki's parser; it can't be represented as a formal grammar using BNF, EBNF or ANTLR syntaxes. The current parser's specification is jokingly referred to as "whatever the parser spits out from wikitext, plus a few hundred test cases".
There have been many attempts at alternative parsers, but none has succeeded so far. In 2004, an experimental tokeniser was written by Jens Frank to parse wikitext, and enabled on Wikipedia; it had to be disabled three days later, because of the poor performance of PHP array memory allocations. Since then, most of the parsing has been done with a huge pile of regular expressions, and a ton of helper functions. The wiki markup, and all the special cases the parser needs to support, have also become considerably more complex, making future attempts even more difficult.
A notable improvement was Tim Starling's preprocessor rewrite in MediaWiki 1.12, whose main motivation was to improve the parsing performance on pages with complex templates.
The preprocessor converts wikitext to an XML DOM tree representing parts of the document (template invocations, parser functions, tag hooks, section headings, and a few other structures), but can skip "dead branches" in template expansion, such as unfollowed #switch
cases and unused defaults for template arguments.
The parser then iterates through the DOM structure and converts its content to HTML.
Recent work on a visual editor for MediaWiki has made it necessary to improve the parsing process (and make it faster), so work has resumed on the parser and intermediate layers between MediaWiki markup and final HTML (see Future, below).
Magic words and templates
MediaWiki offers "Magic words" that modify the general behaviour of the page or include dynamic content into it.
They consist of: behaviour switches like __NOTOC__
(to hide the automatic table of content) or __NOINDEX__
(to tell search engines not to index the page); variables like {{CURRENTTIME}}
or {{SITENAME}}
; and parser functions, i.e. magic words that can take parameters, like {{lc:[string]}}
(to output [string]
in lowercase).
Constructs like {{GENDER:}}
, {{PLURAL:}}
and {{GRAMMAR:}}
, used to localise the UI, are parser functions.
The most common way to include content from other pages in a MediaWiki page is to use templates. Templates were really intended to be used to include the same content on different pages, e.g. navigation panels or maintenance banners on Wikipedia articles; having the ability to create partial page layouts and reuse them in thousands of articles with central maintenance made a huge impact on sites like Wikipedia.
However, templates have also been used (and abused) by users for a completely different purpose. MediaWiki 1.3 made it possible for templates to take parameters that change their output; the ability to add a default parameter (introduced in MediaWiki 1.6) enabled the construction of a functional programming language implemented on top of PHP, which was ultimately one of the most costly features in terms of performance.
Tim Starling then developed additional parser functions (the ParserFunctions extension), as a stopgap measure against insane constructs created by Wikipedia users with templates.
This set of functions included logical structures like #if
and #switch
, and other functions like #expr
(to evaluate mathematical expressions) and #time
(for time formatting).
Soon enough, Wikipedia users started to create even more complex templates using the new functions, which considerably degraded the parsing performance on template-heavy pages. The new preprocessor introduced in MediaWiki 1.12 (a major architectural change) was implemented to partly remedy this issue. Later, MediaWiki developers discussed the possibility of using an actual scripting language to improve performance. Extension:Scribunto was added in February of 2013.
Media files
Users upload files through the Special:Upload
page; administrators can configure the allowed file types through an extension whitelist.
Once uploaded, files are stored in a folder on the file system, and thumbnails in a dedicated thumb
directory.
Because of Wikimedia's educational mission, MediaWiki supports file types that may be uncommon in other web applications or CMSes, like SVG vector images, and multipage PDFs & DjVus. They are rendered as PNG files, and can be thumbnailed and displayed inline, as are more common image files like GIFs, JPGs and PNGs.
When a file is uploaded, it is assigned a File:
page containing information entered by the uploader; this is free text, which usually includes copyright information (author, license) and items describing or classifying the content of the file (description, location, date, categories, etc.).
While private wikis may not care much about this information, on media libraries like Wikimedia Commons they are critical to organise the collection and ensure the legality of sharing these files.
It has been argued that most of these metadata should, in fact, be stored in a queryable structure like a database table.
This would considerably facilitate search, but also attribution and reuse by third parties — for example, through the API.
Most Wikimedia sites also allow "local" uploads to each wiki, but the community tries to store freely-licensed media files in Wikimedia's free media library, Wikimedia Commons. Any Wikimedia site can display a file hosted on Commons as if it were hosted locally. This custom avoids having to upload a file to every wiki to use it there.
As a consequence, MediaWiki natively supports foreign media repositories, i.e., the ability to access media files hosted on another wiki through its API and the ForeignAPIRepo
system.
Since version 1.16, any MediaWiki website can easily use files from Wikimedia Commons through the InstantCommons
feature.
When using a foreign repository, thumbnails are stored locally to save bandwidth.
However, it is not (yet) possible to upload to a foreign media repository from another wiki.
Customising and extending MediaWiki
Levels
MediaWiki's architecture provides different ways to customise and extend the software. This can be done at different levels of access:
- System administrators can install extensions and skins, and configure the wiki's separate helper programs (e.g. for image thumbnailing and TeX rendering) and global settings (see Configuration above).
- Wiki sysops (sometimes called "administrators" too) can edit site-wide gadgets, JavaScript and CSS settings.
- Any registered user can customise their own experience and interface using their preferences (for existing settings, skins and gadgets) or make their own modifications (using their personal JS and CSS pages). External programs can also communicate with MediaWiki through its machine API, if it's enabled, basically making any feature and data accessible to the user.
JavaScript and CSS
MediaWiki can read and apply site-wide or skin-wide JavaScript and CSS using custom wiki pages; these pages are in the MediaWiki:
namespace, and thus can only be edited by sysops; for example, JavaScript modifications from MediaWiki:Common.js
apply to all skins, CSS from MediaWiki:Common.css
applies to all skins, but MediaWiki:Vector.css
only applies to users with the Vector skin.
Users can do the same types of changes, which will only apply to their own interface, by editing subpages of their user page (e.g. User:[Username]/common.js
for JavaScript on all skins, User:[Username]/common.css
for CSS on all skins, or User:[Username]/vector.css
for CSS modifications that only apply to the Vector skin).
If the Gadgets extension is installed, sysops can also edit gadgets, i.e. snippets of JavaScript code providing features that can be turned on and off by users in their preferences. Upcoming developments on gadgets will make it possible to share gadgets across wikis, thus avoiding duplication.
This set of tools has had a huge impact and greatly increased the democratisation of MediaWiki's software development. Individual users are empowered to add features for themselves; power users can share them with others, both informally and through globally-configurable sysop-controlled systems. This framework is ideal for small, self-contained modifications, and presents a lower barrier of entry than heavier code modifications done through hooks and extensions.
Extensions and skins
When JavaScript and CSS modifications are not enough, MediaWiki provides a system of hooks that let third-party developers run custom PHP code before, after, or instead of MediaWiki code for particular events. MediaWiki extensions use hooks to plug into the code.
Before hooks existed in MediaWiki, adding custom PHP code meant modifying the core code, which was neither easy nor recommended. The first hooks were proposed and added in 2004 by Evan Prodromou; many more have been added over the years when needed. Using hooks, it is even possible to extend MediaWiki's wiki markup with additional capabilities, using tag extensions.
The extension system isn't perfect: extension registration is based on code execution at startup, rather than cacheable data, which limits abstraction and optimisation and hurts MediaWiki's performance. But overall, the extension architecture is now a fairly flexible infrastructure that has helped make specialised code more modular, keeping the core software from expanding (too) much, and making it easier for third-party users to build custom functionality on top of MediaWiki.
Conversely, it's very difficult to write a new skin for MediaWiki without reinventing the wheel.
In MediaWiki, skins are PHP classes each extending the parent Skin
class; they contain functions that gather the information needed to generate the HTML.
The long-lived "MonoBook" skin was difficult to customise because it contained a lot of browser-specific CSS to support old browsers; editing the template or CSS required many subsequent changes to reflect the change for all browsers and platforms.
The other main access point for MediaWiki, besides index.php
, is api.php
, used to access its machine-readable query API (Application Programming Interface).
Wikipedia users originally created "bots" that worked by screen scraping the HTML content served by MediaWiki; this method was very unreliable and broke many times.
To improve this situation, developers introduced a read-only interface (located at query.php
), which then evolved into a full-fledged read and write machine API providing direct, high-level access to the data contained in the MediaWiki database.
Client programs can use the API to login, get data, and post changes. The API supports thin web-based JavaScript clients and end-user applications. Almost anything that can be done via the web interface can basically be done through the API. Client libraries implementing the MediaWiki API are available in many languages, including Python and .NET.
Layers, domains, and patterns
MediaWiki can be divided into around 12 technical layers , with each layer calling classes and code in the layer beneath it but not above it. Examples include the installer layer , entry point layer , wiring layer , and API layer . Code spanning all the layers can be grouped into around 21 domain modules , with examples including the navigation domain (skins), user management domain (create, rename, login), and internationalisation domain . Many software design patterns are used in MediaWiki, including the factory pattern , handler pattern , and command pattern .
Future
What started as a summer project done by a single volunteer PHP developer has grown into MediaWiki, a mature, stable wiki engine powering a top-ten website with a ridiculously small operational infrastructure. This has been made possible by constant optimisation for performance, iterative architectural changes and a team of awesome developers.
The evolution of web technologies, and the growth of Wikipedia, call for ongoing improvements and new features, some of which require major changes to MediaWiki's architecture. This is, for example, the case for the ongoing visual editor project, which has prompted renewed work on the parser and on the wiki markup language, the DOM and final HTML conversion.
MediaWiki is a tool that is used for varied purposes. Within Wikimedia projects, for instance, it's used to create and curate an encyclopedia (Wikipedia), to power a huge media library (Wikimedia Commons) or to transcribe scanned reference texts (Wikisource); and so on. In other contexts, MediaWiki is used as a corporate CMS, or as a data repository, sometimes combined with a semantic framework. These specialised uses that weren't planned for will probably continue to drive constant adjustments to the software's internal structure. As such, MediaWiki's architecture is very much alive, just like the immense community of users it supports.
Notes and references
- ↑ Żądania wyświetlenia są zwykle upiększane za pomocą ponownego nadpisywania adresów URL, w tym przykładzie na
w:Apple
. - ↑ https://twitter.com/MagnusManske/status/1083507467802365952
Further reading
- MediaWiki documentation and support: https://www.mediawiki.org
- Automatically-generated MediaWiki documentation: https://doc.wikimedia.org
- Domas Mituzas, Wikipedia: site internals, configuration, code examples and management issues, MySQL Users conference, 2007. Full text available at http://dom.as/talks/
- Faidon Liambotis, The Wikimedia infrastructure, dotScale 2014. (YouTube video)