Niedziałający mod_rewrite – rozwiązanie

Ostatnio pisząc nowy skrypt strony (tego obecnego nie można już w żaden sposób uratować bo to jeden wielki śmietnik, praktycznie uczyłem się dopiero PHP pisząc go) natrafiłem na dość poważny problem. Obecna strona używa z powodzeniem mod_rewrite, więc aby nie cofać jej w rozwoju użycie tego modułu było jednym z podstawowych celów kolejnej wersji skryptu. Niestety już po napisaniu kilku regułek okazało się, że niektóre z nich działają a niektóre nie. Początkowo próbowałem radzić sobie w możliwie najprostszy sposób używając REQEST_URI zamiast korzystać z GETa. Po napisaniu kilku podstron kontynuowanie takiego obejścia okazało się niemożliwe. Zauważyłem, że problemy sprawiają te reguły, w których jako wzorzec zawarty jest ciąg występujący również w pliku na serwerze np.

RewriteRule ^projekty/([0-9]+)$ projekty.php?strona=$1

To już dało mi do myślenia i zacząłem kombinować co jest źródłem problemu. Jak przypuszczałem zmiana projekty we wzorze na dowolny inny ciąg powodowała, że problem znikał. Trudno jednak, aby użytkownik chcąc obejrzeć moje projekty wchodził na podstronę nazywającą się blablabla lub jakkolwiek inaczej. Zmiana nazwy pliku projekty.php też nie wchodziła w grę, bo utrudniałaby tym razem moje życie. W takiej sytuacji zacząłem szukać sposobu na podejrzenie co robi serwer oraz jakie dane dostaje. Możliwe to było do osiągnięcia jedynie dzięki logom. Jako, że serwer stoi na localhoście nie stanowiło to problemu. Do konfiguracji Apache’a dopisałem:

RewriteLog [sciezka do serwera]/logs/rewrite.log
RewriteLogLevel 5

Zresetowałem i otworzyłem log. Po bardzo szybkiej analizie (większości wpisów nawet nie trzeba rozumieć, wystarczą ścieżki) zauważyłem, że moduł rewrite zamiast projekty/1 dostaje projekty.php/1. Niestety nie wiedząc jaki jest powód takiego zachowania serwera odpuściłem sobie przez co straciłem dwa dni nie pisząc ani jednej linii nowego kodu.

Kiedyś jednak musiałem do niego wrócić. Wróciłem więc dzisiaj i zacząłem analizować konfigurację Apache’a. W pliku httpd.conf nie znalazłem nic co mogłoby powodować ten błąd. Jako, że wykorzystuję WAMP’a jako platformę testową (i nie tylko, bo screeny użyte we wpisie Kilka ciekawostek z bazy whois (i nie tylko) także pochodzą z mojego localhosta tylko z zupełnie innego skryptu, którego nie mam zamiaru teraz omawiać) miałem utworzony alias do skryptu (tego od bazy whois) a strona znajdowała się dodatkowo w podfolderze (co wcześniej uważałem za przyczynę błędu, okazało się jednak, że leży ona gdzie indziej). Zajrzałem więc do konfiguracji aliasu. Wygląda ona mniej więcej tak:

<Directory "x:/system/htdocs/">
    Options Indexes FollowSymLinks MultiViews
    AllowOverride all
        Order allow,deny
    Allow from all

Nie wklejam całości, żeby nie zaśmiecać wpisu. Od razu rzuciły mi się w oczy dwa elementy: MultiViews oraz AllowOverride all. Alias został wygenerowany przez WAMPa a dodatkową konfigurację pobrałem z Internetu. Trudno powiedzieć skąd wzięła się akurat ta część. W każdym razie zacząłem szukać informacji o MultiViews dzięki czemu trafiłem tutaj. Pomijając problemy jakie mógłbym mieć z Googlebotem gdyby taka konfiguracja była na serwerze dostępnym z Internetu autor wyjaśnia co robi ta dyrektywa:

Multiviews allow substitutions of file extensions, so you can call an URL like www.somehost.org/mypage.php using www.somehost.org/mypage.

Po przeczytaniu tego zdania od razu jasne stało się, że właśnie znalazłem źródło swojego problemu. Oczywiście dodając Options -MultiViews na początek pliku .htacces regułki zaczęły działać dokładnie tak jak powinny. Wniosek z tego jest taki, że gdy nie wiesz dlaczego coś nie działa zawsze czytaj logi!

Posted in Tutorials | Tagged , , , , , , | Leave a comment

[Delphi] Wyświetlanie stanu za pomocą ProgresBar’a

Wydaje się, że jest to proste zadanie: wystarczy umieścić na formie kontrolkę, pozmieniać nieco style i gotowe. Niestety praktyka wygląda zupełnie inaczej. Każdy, kto chciał to osiągnąć w Windowsie Vista lub 7 pewnie wie, że nowe paski postępu jednym szczegółem uniemożliwiają wykonanie tego tak prosto. Dzieje się tak, ponieważ pasek postępu przy włączonym Aero jest animowany i w żaden udokumentowany sposób nie da się owej animacji wyłączyć.

Microsoft oczywiście zaleca, aby zamiast standardowego ProgressBar’a użyć coś, co nazywa ‘Meter’. I tu pojawia się kolejny problem, bo o tym rozwiązaniu wzmianka znajduje się jedynie w tym przewodniku, nie ma natomiast żadnego opisu, jak takie coś można osiągnąć w praktyce a jedynym programem, w którym można zobaczyć jak takie coś działa jest Eksplorator Windows. Niestety podejrzenie w jaki sposób jest to wykonane od strony kodu jest dla większości praktycznie niewykonalne (nie można podejrzeć styli kontrolki za pomocą programów takich jak WinDowse więc jedynym sposobem byłaby dekompilacja). Na szczęście jest jeden trick umożliwiający wykonanie kontrolki przypominającej microsoftowy meter. Jak w każdym obejściu problemu tak i tu jest niestety jeden haczyk: po zmianie skórki np. na Klasyczny Windows, bądź też przy próbie zastosowania go w starszych wersjach Windows nie zobaczymy nic. Wymusza to więc zastosowanie dwóch kontrolek: dla Windows Vista/7 – tej, którą zajmę się za chwilę oraz standardowego ProgressBar’a dla starszych Windowsów.

Sam kod nie jest ani trudny do użycia, ani też jego napisanie nie stanowiło większego problemu. Przedstawia się on następująco:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var:tRECT;
theme:HTHEME;
Progress:integer;
begin
  Progress:=50;
  theme := OpenThemeData(Handle,'PROGRESS');
  if theme<>0 then
  begin
    SetRect(r,0,0,25,100);
    DrawThemeBackground(theme,Form1.Canvas.Handle,11,2,r,nil);
    SetRect(r,0,Progress,25,100);
    DrawThemeBackground(theme,Form1.Canvas.Handle,6,4,r,nil);
    CloseThemeData(theme);
  end;
end;

Jak widać dwukrotnie została użyta funkcja DrawThemeBackground: pierwszy raz rysuje ona tło, za drugim razem została użyta do narysowania paska postępu, który w tym wypadku został ustawiony na połowie maksymalnej wartości, a ponieważ pasek ma wysokość równą 100 nie było konieczności stosowania żadnych dodatkowych funkcji do przeliczania tej wartości. Zamiast Form1.Canvas lepiej byłoby użyć komponentu TPaintBox, ewentualnie możnaby wtedy nieco zmodyfikować kod tak, aby wypełniał cały komponent co ułatwiłoby późniejsze modyfikacje. Kod należy wkleić do zdarzenia OnPaint używanego komponentu. Jeżeli powyższy przykład jest dla kogoś niejasny bądź nie wie do czego służą poszczególne argumenty odsyłam do opisów poszczególnych funkcji w bibliotece MSDN: OpenThemeData, SetRect, DrawThemeBackground oraz CloseThemeData. Do funkcji DrawThemeBackground można przekazać także inne wartości (parametry 3 i 4) używając wartości podanych tutaj.
Dla mnie jednak próbowanie wszyskich wartości nie było zbyt wygodne, napisałem więc prosty program umożliwiający szybkie przejrzenie wszyskich elementów, które można użyć. Program ten można ściągnąć stąd i nie zaliczam go do projektów, ponieważ nie zamierzam wprowadzać do niego żadnych poprawek.

Posted in Tutorials | Tagged , , , , , , , | Leave a comment
Newer »