netcoffee.pl*po godzinach - reaktywacja

Ten blog jest kontynuacją bloga dostępnego ongiś pod adresem netcoffee.pl/pogodzinach.
Artykuły, które na to zasługują są przenoszone do nowej wersji bloga. Pozostałe wkrótce znikną.

2006-12-03

Czyżby TODO idealne?

TODO: znaleźć TODO

Od bardzo długiego czasu, poszukiwałem programu, który pomógłby mi zarządzać listą zadań do zrobienia - TODO. Zainstalowałem wiele programów dla Windows, oraz systemów stworzonych w PHP i opartych o MySQL. Niestety, żaden z nich nie spełnił moich wymagań. Jak się okazało, autorzy popadali z jednej skrajności w drugą. Programy były albo bardzo ubogie, oferując jedynie możliwość tworzenia prostego spisu zadań, albo były bardzo rozbudowane. Przy czym wadą tych rozbudowanych było to, że wymagały od użytkownika podawania wszystkich istnejących parametrów zadań.

Jednym z bardziej złożonych systemów, był Eventum, udostępniony przez MySQL AB. Jego rozbudowane opcje budziły szacunek, niestety, aby rozpocząć używanie systemu, należało skonfigurować bardzo dużo parametrów - projekty, uczestnicy, klienci, statusy, priorytety itp. Skończyłem używać ten system zanim jeszcze tak naprawde zacząłem.

DONE: znaleźć TODO

W końcu, dzięki - o ile dobrze pamiętam - serwisowi dzone.com - znalazłem program, który ma szansę zostać moim TODO idealnym. Jest to ToDoList (obecnie w wersji 5.0.1) udostępniony przez AbstractSpoon Software.

ToDoList

Główne okno programu zawiera:

Todo - okno główne



  • listę zadań w postaci drzewa
  • panel z parametrami aktualnie wybranej pozycji
  • pole komentarza (RTF)
  • panel wyszukiwania

Dla każdego z zadań, można zdefiniować parametry:
  • priorytet (0-10)
  • ryzyko (0-10)
  • procent wykonania
  • przewidywany czas potrzebny na wykonanie
  • rzeczywisty czas poświęcony na wykonanie
  • datę rozpoczęcia pracy
  • datę rzeczywistego zakończenia pracy
  • termin wykonania
  • osobę, której przypisano zadanie
  • osobę, ktora przypisała zadanie
  • status (dowolnie definiowana lista)
  • kategoria (dowolnie definiowana lista)
  • zewnętrzne ID
  • koszt
  • zależność od innego zadania
  • kolor
  • komentarz
Dodatkowo, każde z zadań można oznaczyć flagą, oraz przypisać do niego plik.
Bardzo ważną zaletą programu jest to, że wszystkie parametry zadania są opcjonalne. Dzięki temu o wiele łatwiej można dostosować program do własnych potrzeb. Jeżeli nie mamy w zwyczaju określania terminu wykonania zadania - to go nie musimy definiować. Co nie oznacza, że gdy przyjdzie taka potrzeba, nie będziemy mogli tego zrobić.

Wszystkie parametry zadania definiujemy w panelu znajdującym się pod listą:
szczegóły zadania

Zadania można organizować w hierarchiczne drzewo z wieloma poziomami zagłębienia.
lista zadań
Zaznaczenie nadrzędnego zadania jako wykonanego, może powodować zaznaczenie poniższych zadań jako wykonane. Zadania można przemieszczać na liście względem innych, używając klawiszy kursora z wciśniętym klawiszem Control.

Kilka parametrów zadań zasługuje na dodatkowe kilka zdań:
priorytet
każdemu priorytetowi można przypisać kolor, lub wszystkim można przypisać kolejne etapy przejścia tonalnego między dwoma kolorami. Dodtakowo, zadanie nadrzędne może automatycznie otrzymać najwyższy priorytet zadań podrzędnych (można wykluczyć priorytet zadań wykonanych)
procent wykonania
ten parametr można oznaczać ręcznie, może on być też wyliczony na podstawie wykonania zadań podrzędnych. Podstawą obliczeń może być albo ilość zadań wykonanych/niewykonanych lub czas potrzebny i poświęcony na ich wykonanie.
rzeczywisty czas poświęcony na wykonanie
może być wyrażony w kilku jednostkach (minuty, godziny, dni, tygodnie, miesiące, lata). Dodatkowo program umożliwia automatyczne mierzenie czasu poświęconego na zadanie (pomiar jest wstrzymywany na czas działania wygaszacza ekranu).
status/kategoria
można przypisać dowolny status/kategorię. Wcześniej wprowadzone wartości tworzą listę, z której można szybko wybrać status/kategorię.
zależność
można zdefiniować ID zadania, które musi być wykonane przed wybranym zadaniem. Jeżeli spróbujemy oznaczyć zadanie zależne jako wykonane, a zadanie nadrzędne nie będzie wykonane, zostanie wyświetlone ostrzeżenie.
komentarz
jest edytowany w polu RTF, pozwalającym na formatowanie tekstu, a także na wstawianie odnośników do innych zadań, w postaci tdl://xxx gdzie xxx jest identyfikatorem zadania. Odnośnik może prowadzić także do zadań zdefiniowanych w innych plikach. Pole komentarza wygląda tak:
komentarze

Praca zespołowa
ToDoList umożliwia także współdzielenie pliku przez kilka osób. Wystarczy plik z listą zadań umieścić na dysku sieciowym. Aby wykluczyć konflikty w trakcie edycji, przed edycją pliku, należy wcześniej zablokować możliwość edycji innym użytkownikom:

Tryb blokowania

Wcześniej w opcjach trzeba włączyć opcję "Enable simple source control". Pracę kilku osób ułatwiają dodatkowe opcje:
  • automatyczne ponawianie próby zablokowania pliku do edycji, w przypadku gdy edycję zablokował inny użytkownik
  • automatyczne odblokowywanie edycji przy zamykaniu listy
  • odblokowywanie listy, gdy nie dokonano zmian przez ustalony czas
  • automatyczne sprawdzanie statusu listy co ustalony czas i automatyczne wczytywanie aktualnego pliku

Dodatkowe opcje
W ustawieniach można zdefiniować globalny skrót klawiaturowy przywołujący i minimalizujący program, który może minimalizować się do ikony systemowej. Dzięki temu łatwo operuje się programem, który czekając w gotowości, nie rozprasza uwagi, nie zabiera miejsca na pasku systemowym, i co ważniejsze - na liście okien (Alt-Tab).

Warto także wspomnieć o tym, że:
  • istnieje możliwości eksportu/importu list zadań (HTML, MLO, Outline, GanttProject, iCalendar, ...)
  • istnieje możliwości dodawania pluginów i narzędzi zewnętrznych (tu można wykorzystać parametr external ID)
  • lista jest przechowywana jako plik XML, można więc z łatwością stworzyć własne narzędzie potrafiące odczytywać plik
  • można w samym programie przetwarzać listę przy użyciu szablonu XSLT


To jest tylko pobieżne przedstawienie programu ToDoList. Zainstalowałem naprawdę sporo programów tego typu, ten jednak wydał mi się najlepszy z dotąd testowanych i godny polecenia. Nie twierdzę jednak, że jest najlepszy ze wszystkich istniejących. Dlatego właśnie chciałbym dowiedzieć się, czego używacie jako menadżera zadań? Co lubicie w tych programach, a co was drażni? Jakie macie wymagania względem takich programów? A może macie jakieś własne rozwiązania?

2006-09-18

Launchy - szybkie uruchamianie

Launchy, od kiedy zainstalowałem go pierwszy raz, stał się narzędziem, bez któego trudno mi jest się obejść. Dzięki temu małemu programowi zapomnisz o menu start i skrótach porozrzucanych po pulpicie i na pasku zadań.

Po zainstalowaniu programu, działa on w tle. Po wciśnięciu skrótu ALT + SPACJA (skrót można zmienić), na ekranie pojawia się przyjemne w wyglądzie okienko programu:

Launchy - okno programu


Po pojawieniu się okienka możemy zacząć wpisywać nazwę programu lub pliku, który chcemy otworzyć. Domyślnie Launchy indeksuje Menu Start. Gdy wpisywany tekst będzie pasował do nazwy przynajmniej jednego zindeksowanego pliku, Launchy wyświetli propozycje na rozwijalnej liście, z której można wybrać program/plik który chcemy uruchomić/otworzyć.

Konfigurując program, możemy zdefiniować, które katalogi i pliki z jakimi rozszerzeniami należy indeksować. Dzięki temu możemy uruchamiać nie tylko wszystkie programy, ale także np. pliki MP3 w domyślnym programie.

Samo dopasowywanie wpisanej nazwy do nazw w indeksie jest bardzo dopracowane i elastyczne. Dzięki temu możemy wpisać tylko fragment nazwy pliku/programu. Co więcej Launchy jest odporny na literówki i łatwo domyśla się, jaki program chcemy uruchomić.

Naprawdę polecam!

2006-08-02

mod_security: testowanie konfiguracji

mod_security to moduł serwera Apache będący systemem wykrywania włamań. mod_security analizuje przychodzące dane (metody GET i POST a także cookies) a także dane odsyłane do klienta. Po wykryciu zdefiniowanych w konfiguracji fraz (np. zapytań sql, kodu html, kodu javascript), mod_security wykonuje jedną ze zdefiniowanych akcji. Może to być np. wysłanie do klienta kodu błędu, przekierowanie klienta, wstrzymanie odpowiedzi na ustaloną ilość milisekund (przydatne w walce z botami) lub zablokowanie rządania. Tyle tytułem wstępu.

Sam moduł może być dla aplikacji którą chroni tyle zbawienny, co niebezpieczny. Zastosowanie zbyt restrykcyjnych reguł filtrowania może doprowadzić aplikację do stanu nieużywalności. Dlatego warto już na etapie tworzenia aplikacji skonfigurować moduł i testować konfigurację, na samym początku jako akcje podejmowane po wykryciu potencjalnie niebezpiecznych danych ustawić jedynie logowanie zdarzeń. W trakcie pracy można przeglądać logi serwera i korygować ustawienia mod_security lub zmieniać działanie aplikacji.

Innym, wygodniejszym sposobem wykrywania konfiliktów między konfiguracją mod_security a wymaganiami aplikacji (np. gdy w systemie CMS edytujemy kod html strony, mod_security nie powinien podejmować żadnych działań), jest poniższy kod PHP wklejony w sekcji BODY dokumentu HTML:


<?php
if(isset($_SERVER['HTTP_MOD_SECURITY_MESSAGE']) 
  and $_SERVER['REMOTE_ADDR'] == '192.168.0.32'){?>
 <img style='position: fixed; top: 10px; right: 10px;' 
  src='style/error.png' 
  alt='' 
  title='<?php echo htmlspecialchars(stripslashes($_SERVER['HTTP_MOD_SECURITY_MESSAGE'])) ?>'
 />
<?php } ?>


Rozwiązanie to bazuje na tym, że po wykryciu potencjalnie niebezpiecznych danych, mod_security ustawia zmienną systemową, której zawartość możemy odczytać w zmiennej $_SERVER['HTTP_MOD_SECURITY_MESSAGE']. W warunku sprawdzamy, czy ta zmienna jest ustawiona i czy rządanie nadeszło z komputera admina (ten warunek możemy oczywiście dostosować do naszych wymagań i sprawdzać np. czy zalogowany jest administrator itp). Jeżeli tak, do strony dodajemy mały obrazek, który prawdziwe przeglądarki wyświetlą zawsze w górnym prawym rogu. Jako tytuł obrazka wstawiona jest treść błędu zgłoszonego przez mod_security.

Dzięki takiemu rozwiązaniu, już podczas tworzenia, testowania lub w trakcie normalnej, codziennej pracy z aplikacją, na bieżąco będziemy wiedzieli, czy wprowadzone dane spowodują błąd zabezpieczeń.

Oczywiście to proste rozwiązanie jedynie ułatwi testowanie aplikacji - nadal konieczne będzie sprawdzanie logów serwera.

Polecam uwadze

2006-04-17

Zarządanie relacjami w phpMyAdmin

Jedną z mniej znanych funkcji phpMyAdmin jest zarządzanie relacjami w bazie danych. Na małą popularność tej opcji wpływa konieczność przeprowadzenia dodaktowej konfiguracji aby była ona widoczna.


phpMyAdmin informacje o relacjach między tabelami przechowuje w tabelach w zdefiniowanej bazie danych. Dlatego najlepiej jest utworzyć oddzielną bazę danych, tylko na potrzeby phpMyAdmin. Domyślna nazwa bazy to phpmyadmin.

Aby utworzyć tabele niezbędne do dzialania zaawansowanych funkcji phpMyAdmin, wystarczy uruchomić instrukcje SQL znajdujące się w pliku scripts/create_tables.sql w archiwum z phpMyAdmin. Skrypt ten zakłada, że istnieje użytkownik pma, z poziomu którego będzie odbywało się zarządanie danymi.

Skrypt:

  • usuwa bazę phpmyadmin (jeżeli istnieje)
  • zakłada ją ponownie
  • nadaje prawa do wykonywania SELECT, INSERT, UPDATE i DELETE użytkownikowi pma w bazie phpmyadmin
  • tworzy potrzebne tabele

Kolejnym krokiem jest uaktualnienie pliku config.inc.php. Dla każdego z używanych serwerów, należy podać wartość zmiennych:

# nazwa bazy danych phpMyAdmin
$cfg['Servers'][$i]['pmadb'] = 'phpmyadmin';

# nazwa tabeli z opisem relacji
$cfg['Servers'][$i]['relation'] = 'pma_relation';

Po przeprowadzeniu tych operacji, w interfejsie phpMyAdmin zobaczymy nową opcję: Widok relacyjny w widoku struktury tabeli: Nowa opcja: widok relacyjny


Po wybraniu opcji "Widok relacyjny" otrzymujemy dostęp do formularza, w którym możemy zdefiniować relacje między tabelami:
Definiowanie relacji między tabelami


Dla każdego pola tabeli, możemy zdefiniować, któremu polu w innej tabeli odpowiada. Robimy to wybierając odpowiednie pole z listy rozwijalnej. Dodatkowo, dla każdej tabeli możemy wybrać, zawartość którego pola będzie pokazywana jako etykieta rekordu.


Dla przykładu rozważmy takie dwie tabele, zawierające dane menedżera projektów.


Tabela project

  • id - int(10)
  • name - char(100)

Tabela item

  • id - int(10)
  • project_id - int(10)
  • name - char(100)

W tabeli 'project' przechowujemy nazwy projektów, w tabeli 'item' - nazwy poszczególnych elementów projektów. Każdy 'item' ma przypisany także id projektu, do którego należy. Po wejściu do widoku relacyjnego tabeli 'item', dla pola 'project_id' należy wybrać pozycję 'project -> id' (co oznacza pole 'id' w tabeli 'project').


W widoku relacyjnym tabeli 'project' wybieramy wyświetlane pole: 'name'.


Dzięki temu, podczas edycji rekordu z tabeli 'item', zamiast pola tekstowego, dla 'id' zobaczymy listę rozwijalną, z której będzie można wybrać odpowiedni projekt:
Formularz edycji danych


W widoku tabeli danych, zawartość pól w kolumnie 'project_id' będzie odnośnikiem:
Widok tabeli danych
Po jego kliknięciu zobaczymy szczegóły odpowiedniego projektu.

2006-02-13

Przykładowa konfiguracja serwera Apache

Przeglądając ostatnio archiwa dokumentów na dysku, natknąłem się na starą pracę zaliczeniową (z przedmiotu którego nazwy już nie pamiętam ;) ). Opisałem w niej przykładową konfigurację serwera Apache.

Poruszane zagadnienia obejmują:

  • serwery wirtualne
  • logowanie
  • pliki własnej konfiguracj - .htaccess
  • własne strony błędów
  • strony użytkowników
  • negocjacja zawartości
  • uwierzytelnianie

Cała opisana w dokumencie konfiguracja oczywiście działała na testowej instalacji Apache pod Windows 2000.

Doszedłem do wniosku, że mimo braków samego opracowania, warto udostępnić dokument szerszej publiczności. Co prawda powstał on ponad dwa lata temu i nigdy nie pretendował do miana "Wprowadzenia do Apache", myślę jednak, że może przydać się nie jednemu początkującemu użytkownikowi Apache.

Konfiguracja Apache - PDF 158kB

Dokument jest udostępniony na licencji Creative Commons - BY-NC-SA. Nie biorę na siebie żadnej odpowiedzialności za skutki wykorzystania informacji zawartych dokumencie.

2006-02-11

Kontrola wydajności - Apache Benchmark

Niejednokrotnie wprowadzamy rozwiązania, co do wydajności których nie możemy być pewni. Warto jest wówczas skorzystać z narzędzia pozwalającego na jej kontrolę. Moim ulubionym narzędziem jest Apache Benchmark (ab.exe), dostępny razem z dystrybucją serwera Apache.

AB (Apache Benchmark) pozwala na wielokrotne wywołanie URL i przygotowuje statystyki czasu wykonania.
Program wywołujemy z linii poleceń, jego najważniejsze parametry to:

  • n - ilość zapytań
  • c - ilość zapytań w tym samym czasie
  • k - wymusza użycie stałego połączenia - HTTP KeepAlive

Przykładowe wywołanie może mieć postać:

ab.exe -n100 -c100 -k http://www.example.org/ab_test.php

Spowoduje ono pobranie pliku ab_test.php z serwera www.example.org 100 razy, przy czym w jednym czasie będą przeprowadzane 3 połączenia.


Podczas testowania wydajności skryptów, warto pamiętać o włączeniu opcji stałego połączenia HTTP (parametr -k). Dzięki temu, czasy nawiązywania połączeń z serwerem nie wpłyną znacząco na wyniki. Jeżeli natomiast testujemy ogólną wydajność serwera oraz jego dostępność z innych sieci, warto pozostawić domyślne ustawienie.


Przykładowe wyniki działania Apache Benchmark:


Wynik 1

This is ApacheBench, Version 2.0.40-dev < 
                            $Revision: 1.121.2.8 $> apache-2.0 
Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, 
                            http://www.zeustech.net/ 
Copyright (c) 1998-2002 The Apache Software Foundation, 
                            http://www.apache.org/  

Benchmarking xxxxxxxxxxxxxxx (be patient).....done 


Server Software:        Apache/2.0.49 
Server Hostname:        xxxxxxxxxxxxxxx 
Server Port:            80 

Document Path:          /xxxxxxxxxxxxxxx/normal.php 
Document Length:        7496 bytes 

Concurrency Level:      3 
Time taken for tests:   6.879892 seconds 
Complete requests:      100 
Failed requests:        0 
Write errors:           0 
Total transferred:      766700 bytes 
HTML transferred:       749600 bytes 
Requests per second:    14.54 [#/sec] (mean) 
Time per request:       206.397 [ms] (mean) 
Time per request:       68.799 [ms] 
                        (mean, across all concurrent requests) 
Transfer rate:          108.72 [Kbytes/sec] received 

Connection Times (ms)                
              min  mean[+/-sd] median   max 
Connect:        0    2   5.2      0      30 
Processing:   130  196  38.3    190     310 
Waiting:       90  172  41.0    160     300 
Total:        130  198  38.5    190     310 

Percentage of the requests served within a certain time (ms) 
      50%    190 
      66%    210 
      75%    220 
      80%    230 
      90%    260 
      95%    270 
      98%    300 
      99%    310 
     100%    310 (longest request)

Wynik 2

This is ApacheBench, Version 2.0.40-dev < 
                             $Revision: 1.121.2.8 $> apache-2.0    
Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, 
                             http://www.zeustech.net/    
Copyright (c) 1998-2002 The Apache Software Foundation, 
                             http://www.apache.org/        

Benchmarking xxxxxxxxxxxxxxx (be patient).....done        

Server Software:        Apache/2.0.49    
Server Hostname:        xxxxxxxxxxxxxxx    
Server Port:            80      

Document Path:          /xxxxxxxxxxxxxxx/normal.php    
Document Length:        7496 bytes      

Concurrency Level:      3    
Time taken for tests:   5.988612 seconds    
Complete requests:      100    
Failed requests:        0    
Write errors:           0    
Total transferred:      766700 bytes    
HTML transferred:       749600 bytes    
Requests per second:    16.70 [#/sec] (mean)    
Time per request:       179.658 [ms] (mean)    
Time per request:       59.886 [ms] 
                        (mean, across all concurrent requests)    
Transfer rate:          124.90 [Kbytes/sec] received        

Connection Times (ms)
                min  mean[+/-sd] median   max    
Connect:        0    2   4.7      0      20    
Processing:    90  168  48.7    160     350    
Waiting:       70  144  50.3    140     330    
Total:         90  170  48.5    160     350        

Percentage of the requests served within a certain time (ms)
      50%    160
      66%    180
      75%    190
      80%    210
      90%    230
      95%    260
      98%    330
      99%    350
     100%    350 (longest request)

W obu przypadkach testowany był jeden skrypt PHP. Podczas pierwszego testu, skrypt łączył się z serwerem MySQL za pomocą funkcji mysql_connect(). Podczas drugiego testu, skrypt został zmodyfikowany tak, aby do połączenia z serwerem MySQL używał funkcji mysql_pconnect() która otwiera stałe połączenie z serwerem MySQL. Jak widać, użycie stałego połączenia z bazą przyspieszyło stukrotne wykonanie skryptu o 0,89 sekundy.


Polecam uwadze

2006-01-19

Wykrywanie języka użytkownika

Często pojawia się pytanie, jak - w wielojęzycznych serwisach - ustalić język, w którym powinna pojawić się zawartość strony. Przeszukując Internet można znaleźć kilka rozwiązań:
  • ustalać język na podstawie adresu IP
  • ustalać język na podstawie nazwy domenowej hosta
  • ustalić język użytkownika na podstawie informacji o wersji językowej przeglądarki

Niestety, każda z powyższych metod ma swoje wady: użytkownik może łączyć się przez serwer proxy, więc adres IP nie jest miarodajny, może używać przeglądarki w innej wersji językowej, niż jego język itd. Te wady można by wymieniać, ale nie o to tutaj chodzi.

Najlepszą moim zdaniem metodą wykrycia języka użytkownika, jest ustalenie go na podstawie nagłówków http wysyłanych przez przeglądarkę. Każda nowoczesna przeglądarka pozwala użytkownikowi wybrać w ustawieniach programu preferowane języki. Na wybranie języków pozwala użytkownikowi nawet Internet Explorer. Wybór ten jest następnie wysyłany do serwera w postaci nagłówka Accept-Language.

Zawartość tego nagłówka ma postać listy dwuliterowych kodów języków rozdzielonych znakiem przecinka, np:

pl,en

Kod języka może być także uzupełniony o oznaczenie dialektu:

pl,en-gb

Ten zapis oznacza, że użytkownik zna język polski i angielski (brytyjski), ale preferuje ten pierwszy.

W przypadku podania kilku języków, każdy z nich może być oznaczony dodatkowym parametrem q (quality). Parametr ten oznacza wagę danego języka. q może przyjmować wartości od 0 do 1. 0 oznacza język ignorowany. Waga języka jest zapisywana jako q=xx i oddzielona od kodu języka średnikiem (;):

pl,en;q=0.9,ru;q=0.8

Jeżeli dany język nie posiada wagi, przypisuje mu się domyślnie wagę 1. W powyższym przykładzie wagi języków wynoszą:
  • polski - 1
  • angielski - 0.9
  • rosyjski - 0.8

W PHP zawartość nagłówka Accept-Language jest dostępna w zmiennej $_SERVER['HTTP_ACCEPT_LANGUAGE'].Przy użyciu niezbyt skomplikowanej funkcji można określić język, w którym należy wyświetlić zawartość strony:


function getLanguage($sDefault, $ihSystemLang){
$sLangs = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
preg_match_all(
'!([a-zA-Z]+)(?:-[a-zA-Z]+)?(?: *; *q *= *([01]\.[0-9]+))?!',
$sLangs, $shFound);
foreach($shFound[1] as $i => $sLang){
$iW = (float)$shFound[2][$i];
$ihUserLang[$sLang] = $iW > 0 ? $iW : 1;
}
$iChoiceWeight = 0;
$sChoiceLang = '';
foreach($ihSystemLang as $sLang => $iW){
if(isset($ihUserLang[$sLang])){
$iTmpChoice = $iW * $ihUserLang[$sLang];
if($iTmpChoice > $iChoiceWeight and $iTmpChoice > 0){
$iChoiceWeight = $iTmpChoice;
$sChoiceLang = $sLang;
}
}
}
return $sChoiceLang != '' ? $sChoiceLang : $sDefault;
}


Funkcja przyjmuje dwa parametry: kod domyślnego języka oraz tablicę asocjacyjną dostępnych na stronie języków wraz z ich wagami. Funkcja zwraca kod języka wybranego na podstawie ustawień przeglądarki. W czasie wyznaczania języka, ignorowane jest oznaczenie dialektu (gdyż niepotrzebnie komplikuje wybór).

Jeżeli strona jest dostępna w języku polskim i angielskim oraz posiada częściowe tłumaczenie na język francuski, wywołanie funkcji może przyjąć postać:

$sLang = getLanguage('pl', array('pl' => 1, 'en' => 0.9, 'fr' => 0.4));

Językiem podstawowym serwisu jest polski, dlatego właśnie ten język jest podany jako domyślny (pierwszy parametr funkcji) oraz na liście wag otrzymuje 1. Język angielski otrzymuje wysoką wagę 0.9, natomiast francuski tylko 0.4 (ze względu na to, że tłumaczenie jest tylko częściowe).

Wynik działania funkcji zależy od nagłówka Accept-language. Przykładowe wyniki:

Accept-language: pl,en
wynik: pl
Accept-language: fr,en
wynik: en
Accept-language: fr,en;q=0.3
wynik: fr

W przypadku, gdy w nagłówku nie ma żadnego z języków obsługiwanych przez stronę, funkcja zwróci kod domyślny (podany jako pierwszy parametr).

Na koniec kilka słów wyjaśnienia, dlaczego uważam metodę wyboru języka na podstawie nagłówka Accept-language za najlepszą. Oczywiście, jest ona tak samo zawodna jak te, które wymieniłem wcześniej. W końcu, użytkownik może korzystać z przeglądarki w której domyślnie jest ustawiony język inny niż język, którym posługuje się użytkownik. Może używać komputera w pracy za granicą itd.
Jednak powyższa metoda jest jedyną z wymienionych, w której do wykrycia języka używamy parametru, nad którym użytkownik ma całkowitą kontrolę. Przecież nie zawsze możemy wpływać na adres IP z którego łączymy się z siecią (przebywamy za granicą, używamy serwera proxy itp). Możemy używać ulubionej przeglądarki w wersji językowej innej niż nasz język gdyż nie jest jeszcze dostępne tłumaczenie. Nie zmienimy wersji językowej, ale preferowane języki możemy zmienić!

Oczywiście trudno wymagać od użytkowników aby wybierali język strony poprzez ustawienia przeglądarki - dlatego więc nie należy zapominać o udostępnieniu użytkownikowi możliwości zmiany języka na wypadek, gdyby funkcja dokonała złego wyboru.

2006-01-15

Optymalizacja bazy MySql - część II

Wcześniej (Prędkość czy miejsce) pisałem, jak można zaprojektować tabelę MySQL aby baza działała szybciej lub zajmowała mniej miejsca. Teraz przedstawiam garść innych porad:

używaj pól o jak najmiejszym rozmiarze
zmniejszenie rekordu redukuje ilość operacji dyskowych. Jeżeli przechowujesz hasło w postaci hasza md5, użyj pola char(32) a nie varchar(100)
deklaruj kolumny jako NOT NULL
zmniejszysz rozmiar rekordu
dla tabel MyISAM używaj rekordu o stałej długości
patrz: Prędkość czy miejsce
podstawowy indeks tabeli powinien być tak mały, jak to możliwe
przyspieszy to przeszukiwanie i tworzenie pliku indeksu
twórz indeksy których naprawdę potrzebujesz
tworzenie i odczytywanie indeksu też zajmuje czas. Indeksuj te kolumny, których używasz w części WHERE, ORDER BY lub GROUP BY zapytania. Nie musisz indeksować kolumn, których używasz tylko w części SELECT
pierwsza kolumna złożonego klucza powinna być kolumną najczęściej używaną
przyspieszy to przeszukiwanie indeksu
jeżeli pobierasz wiele kolumn z tabeli, najpierw użyj kolumny posiadającej wiele duplikatów
jeżeli kolumna ma unikalny prefiks na kilku pierwszych znakach, lepiej jest zindeksować tylko te kilka pierwszych znaków
użyj do tego funkcji MySQL pozwalającej na tworzeniu indeksu lewej części kolumny znakowej
w pewnych warunkach może przydać się podzielenie tabeli na dwie
w ten sposób możesz uzyskać w jednej tabeli rekordy o stałej długości
indeksy działają wydajniej dla kolumn, które mają dużą ilość unikalnych wartości w stosunku do ilości rekordów (ang. cardinality)
lepiej działa indeks dla kolumny 'login' (wszystkie wartości unikalne) niż dla kolumny 'wojewodztwo' (tylko 16 różnych wartości)
zwróć uwagę na typ pól podczas porównywania
jeżeli wyszukujesz rekordy na podstawie pola typu INTEGER, nie używaj porównania tego pola z typem STRING (np. WHERE id = '78'). Lepiej porównuj pola tego samego typu (np. WHERE id = 78). Jeżeli porównujesz wartość pola z wartością innego pola, zadbaj aby miały one ten sam typ. Dzięki temu unikniesz konieczności rzutowania. Pamiętaj także, że int i bigint to inne typy pól oraz char(10) nie odpowiada polu char(12).
staraj się umieszczać indeksowane samotnie po jednej stronie porównania
w przeciwnym wypadku MySQL nie będzie mógł użyć indeksów. Lepszą wydajność uzyskasz pisząc 'WHERE i < 4 / 2' niż 'WHERE i *2 < 2'
nie używaj znaków wieloznacznych na początku porówanania LIKE
używaj pól typu ENUM jeżeli to możliwe