[SOLVED] gnu/stubs-32.h: No such file or directory

2010-08-10 | skomentuj

Kompilując kod w C na systemie 64-bitowym możemy otrzymać następujący komunikat:

gnu/stubs-32.h: No such file or directory

Rozwiązaniem jest dodanie opcji -m64 do wywołania kompilatora gcc.

Jeżeli program, który jest kompilowany, korzysta ze skryptu configure, można uruchomić ten skrypt następująco:

# CFLAGS=-m64 ./configure

Briefly Unavailable for Scheduled Maintenance

2010-07-31 | skomentuj

WordPress po (przerwanej) aktualizacji wita nas komunikatem:

Briefly Unavailable for Scheduled Maintenance

Szybkie rozwiązanie: usunąć plik .maintenance (nazwa pliku zaczyna się od kropki) z głównego katalogu WordPressa.

Polskie locale i UTF-8 na Ubuntu

2010-05-19 | skomentuj

Wynajmując serwer fizyczny bądź wirtualny (VPS) często otrzymujemy w pakiecie prekonfigurowany system operacyjny Linux. Gdy serwer jest wynajmowany za granicą, system operacyjny może nie być prawidłowo skonfigurowany do obsługi języka polskiego nawet, gdy zainstalujemy odpowiednie pakiety językowe i ustawimy odpowiednie wartości zmiennych środowiskowych LANG, LC_ALL i LANGUAGE.

Sygnałem, że konfiguracja systemu nie jest optymalna mogą być na przykład następujące komunikaty (poniższe wypisuje interpreter języka Perl):

perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
LANGUAGE = "pl_PL",
LC_ALL = "pl_PL.UTF-8",
LANG = "pl_PL.UTF-8"
are supported and installed on your system.

Wypisywane są nawet wtedy, gdy nadamy specyficznym zmiennym środowiskowym następujące wartości

LANG=pl_PL.UTF-8
LANGUAGE=pl_PL
LC_ALL=pl_PL.UTF-8

W dystrybucji Ubuntu rozwiązanie problemu jest następujące: przechodzimy do katalogu /var/lib/locales/supported.d i tworzymy w nim plik o nazwie pl i poniższej zawartości

pl_PL ISO-8859-2
pl_PL.UTF-8 UTF-8

Wywołujemy polecenie dpkg-reconfigure locales, które wypisze takie, lub podobne komunikaty

perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
LANGUAGE = (unset),
LC_ALL = "pl_PL.UTF-8",
LANG = "pl_PL.UTF-8"
are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").
locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_MESSAGES to default locale: No such file or directory
locale: Cannot set LC_ALL to default locale: No such file or directory
Generating locales...
de_AT.UTF-8... up-to-date
de_BE.UTF-8... up-to-date
de_CH.UTF-8... up-to-date
de_DE.UTF-8... up-to-date
de_LI.UTF-8... up-to-date
de_LU.UTF-8... up-to-date
pl_PL.ISO-8859-2... done
pl_PL.UTF-8... done
Generation complete.


Gotowe.

Jeżeli do łączenia się ze zdalnym serwerem wykorzystywany jest terminal PuTTY, należy pamiętać, aby również w jego ustawieniach zmienić sposób translacji znaków na UTF-8.

Zend Framework – Cannot redeclare class Zend_Loader

2010-05-18 | skomentuj

Po wywołaniu narzędzia zf w katalogu aplikacji pojawia się komunikat

Fatal error: Cannot redeclare class Zend_Loader in .../library/Zend/Loader.php on line 31

Problem wydaje się istnieć od wersji 1.9.2 narzędzia zf i jest nadal obecny w wersji 1.10.4. Rozwiązaniem, choć bardzo niewygodnym, jest zakomentowanie w pliku application/configs/application.ini – tylko na moment wywołania narzędzia – wiersza o treści

includePaths.library = APPLICATION_PATH "/../library"

Zend Framework, „A project profile was not found.”

2010-05-15 | skomentuj

Polecenie zf powinno być wywoływane w głównym katalogu aplikacji. Gdy i to nie pomaga, w tymże katalogu brakuje pliku .zfproject.xml

Import plików do SVN i komunikat „Error 301 Moved Permanently”

2010-05-04 | skomentuj

Napotkałem ostatnio interesujący problem: po przeniesieniu repozytorium SVN i poprawnym (wydawałoby się) skonfigurowaniu Apache wraz z modułem mod_dav do jego obsługi po protokole HTTPS, każda próba importu plików do nowego repozytorium kończyła się komunikatem

svn: PROPFIND of '/app': 301 Moved Permanently (/app/)

(lub bardzo podobnym). Jak widać, nowy url różni się od poprzedniego dodanym na końcu ukośnikiem.

Konfiguracja Apache do obsługi repozytorium SVN była standardowa, czyli:

<Location />
    DAV svn
    SVNParentPath /var/www/vhosts/svn
    AuthType Basic
    AuthName "http"
    AuthUserFile /etc/http.users
    Require valid-user
</Location>

SVNParentPath wskazuje na katalog, w którym znajdują się repozytoria różnych projektów. Sprawcą zamieszania okazało się umieszczenie repozytoriów SVN w tym samym katalogu, na który wskazywała dyrektywa DocumentRoot wirtualnego serwera. W ten sposób powstawał konflikt między mod_dav, a zwyczajną obsługą katalogów i plików przez Apache.

Gdy repozytorium SVN zostało umieszczone w innym katalogu, tym razem nie znajdującym się w głównym katalogu wirtualnego hosta, problem zniknął.

Drupal – kompresja plików javascript i css

2010-04-27 | skomentuj

Drupal pozwala na optymalizację plików CSS oraz JS (JavaScript) poprzez połączenie w jeden plik. Zysk czasowy jest oczywisty, bo przeglądarka pobiera jeden plik zamiast wielu, co znacząco przyspiesza otwieranie strony.

Jednak w sytuacji, gdy plik wynikowy jest duży, dodatkową korzyść może przynieść skompresowanie go przy pomocy gzip. Właściwie wszystkie współczesne przeglądarki są w stanie odebrać skompresowany plik, o ile tylko serwer jest w stanie taki plik wysłać.Drupal potrafi wysłać w postaci skompresowanej treść stron, czyli html, ale wysyłanie w taki sposób plików CSS oraz JavaScript wymaga pewnych zmian w plikach Drupala oraz w konfiguracji serwera www. Bezpośrednie zmiany w kodzie Drupala nie są zalecane, ponieważ ten system zarządzania treścią dysponuje bardzo rozbudowanym systemem modułów i hooków, ale w tym wypadku nie ma innego wyjścia.

Zmiany w Drupalu

Należy otworzyć w edytorze plik includes/common.inc, a następnie znaleźć w nim funkcję o nazwie drupal_build_css_cache. W funkcji tej, wiersz o treści

if (!file_exists($csspath .'/'. $filename)) {

zastępujemy wierszem

if (!file_exists($csspath .'/'. $filename) || (function_exists("gzencode") && !file_exists($csspath . '/' . $filename . '.gz'))) {

W tej samej funkcji, nieco niżej, lokalizujemy wiersz o treści

file_save_data($data, $csspath .'/'. $filename, FILE_EXISTS_REPLACE);

i dodajemy pod nim następujący kod:

if (function_exists("gzencode")) {
file_save_data(gzencode($data), $csspath .'/'. $filename . '.gz', FILE_EXISTS_REPLACE);
}

Po tych zmianach, nadal w pliku common.inc, szukamy funkcji o nazwie drupal_build_js_cache

W tejże funkcji wiersz o treści

if (!file_exists($jspath .'/'. $filename)) {

zastępujemy wierszem

if (!file_exists($jspath .'/'. $filename) || (function_exists("gzencode") && !file_exists($jspath .'/'. $filename . '.gz'))) {

Zaś parę linijek niżej (wciąż w tej samej funkcji) znajdujemy linię

file_save_data($contents, $jspath .'/'. $filename, FILE_EXISTS_REPLACE);

i dodajemy pod nią kod

if (function_exists("gzencode")) {
file_save_data(gzencode($contents), $jspath .'/'. $filename . '.gz', FILE_EXISTS_REPLACE);
}

To już wszystkie zmiany w Drupalu. Powodują one, że oprócz zwyczajnych plików .css i .js tworzone są ich skompresowane wersje. Pozostaje tylko skonfigurować serwer www, aby przeglądarkom obsługującym kompresję podsuwał pliki skompresowane. W tym celu musimy wyedytować plik .htaccess znajdujący się w głównym katalogu Drupala (zakładam, że używany jest serwer Apache, instrukcje dla IdeaWebServer znajdują się niżej).

Konfiguracja serwera Apache

Znajdujemy w nim fragment

<IfModule mod_rewrite.c>
RewriteEngine on

i dopisujemy pod nim

RewriteCond %{HTTP:Accept-Encoding} gzip
RewriteCond %{REQUEST_FILENAME}.gz -f
RewriteRule (.*)\.js$ $1.js.gz [L]

RewriteCond %{HTTP:Accept-Encoding} gzip
RewriteCond %{REQUEST_FILENAME}.gz -f
RewriteRule (.*)\.css$ $1.css.gz [L]

Następnie wyszukujemy poniżej (będzie to prawdopodobnie jedna z ostatnich linii w pliku .htaccess) wiersz o treści

</IfModule>

i pod nim dodajemy następujące dyrektywy:

<FilesMatch "\.js.gz$">
ForceType text/javascript
Header set Content-Encoding gzip
</FilesMatch>

<FilesMatch "\.css.gz$">
ForceType text/css
Header set Content-Encoding gzip
</FilesMatch>

Jeżeli w Drupalu obsługa łączenia plików CSS i JS była uprzednio włączona (co można sprawdzić wchodząc na podstronę administracyjną admin/settings/performance i szukając sekcji Optymalizacja wykorzystania pasma – opcje dotyczące plików CSS i JS są wówczas włączone), należy obydwie opcje wyłączyć, zapisać ustawienia, a następnie ponownie je włączyć i zapisać ustawienia. Wygenerowane zostaną wtedy nowe pliki CSS i JS, zaś oprócz nich wersje skompresowane.

IdeaWebServer

Niektóre firmy hostingowe, np. home.pl, korzystają z niestandardowych rozwiązań. W wypadku home.pl, który jest popularnym hostingiem, jest to IdeaWebServer, w którym konfiguracja wymagana w pliku .htaccess wygląda nieco inaczej.

W pliku .htaccess, w głównym katalogu Drupala, znajdujemy fragment

<IfModule mod_rewrite.c>
RewriteEngine on

i dopisujemy pod nim

RewriteCond %{HTTP:Accept-Encoding} gzip
RewriteCond %{REQUEST_FILENAME}.gz -f
RewriteRule (.*)\.js$ $1.js.gz [L]

RewriteCond %{HTTP:Accept-Encoding} gzip
RewriteCond %{REQUEST_FILENAME}.gz -f
RewriteRule (.*)\.css$ $1.css.gz [L]

(Powyższa część konfiguracji jest identyczna jak w przypadku serwera Apache).

Następnie wyszukujemy poniżej (będzie to prawdopodobnie jedna z ostatnich linii w pliku .htaccess) wiersz o treści

</IfModule>

i dodajemy pod nim dyrektywy

:Location *.js.gz
SetMime text/javascript
Header set Content-Encoding gzip
:Location

:Location *.css.gz
SetMime text/css
Header set Content-Encoding gzip
:Location

Gwoli ścisłości należy dodać, że istnieje moduł mod_gzip przeznaczony dla serwera Apache, ale rozwój tego modułu najwyraźniej zatrzymał się wiele lat temu.

Optymalizacja SEO stron opartych na Drupalu

2010-03-13 | skomentuj

Optymalizacja stron internetowych z myślą o wyszukiwarkach jest równie istotna, jak uczynienie ich wygodnymi w obsłudze przez odwiedzających ją ludzi. Co prawda spece z Google twierdzą, że najważniejsze jest, aby strona była odpowiednia dla ludzi, nie dla robotów, ale dlaczego nie pomyśleć o tych ostatnich?Drupal bezpośrednio po zainstalowaniu nie pozwala na tworzenie w pełni zoptymalizowanych stron. Brakuje choćby możliwości rozróżnienia treści w tytule nagłówkowym i w tagu title strony. Nie można też tworzyć własnych opisów meta description.

Meta description

Aby móc dowolnie zarządzać treścią tagu meta description, należy dołączyć moduł nodewords znany też jako „meta tags” i w ustawieniach konfiguracyjnych (admin/content/nodewords/settings) zaznaczyć przynajmniej checkbox odpowiadający tagowi description. W formularzach edycji zawartości pojawi się wówczas nowe pole tekstowe pozwalające na wpisanie własnego opisu strony.

Należy też sprawdzić, czy w używanej przez nas skórce nie jest przypadkiem zaimplementowane dodawanie znacznika opisu – należy wówczas wyłączyć taką możliwość.

Tytuły stron

Korzystne z punktu widzenia optymalizacji stron jest umieszczenie najważniejszych słów kluczowych na początku tytułu strony. Jednak czasem taki tytuł będzie niestrawny dla czytelnika, a jeżeli zapragniemy być figlarni i użyć metafory… dość powiedzieć, że Google ma bardzo prostolinijny stosunek do życia i gry słów należy stosować wszędzie, byle nie w tagu TITLE.

Po instalacji modułu Page Title zdobędziemy kontrolę nad zawartością tagu tytułowego w sekcji HEAD.

Przypadkowe H2

Jeżeli przygotowaliśmy już szablon strony, w którym najważniejsze rzeczy są zawarte w tagach nagłówkowych od H1 do H6, może nas czekać niemiła niespodzianka. O ile Google przeważnie dość trafnie wyszukuje najważniejszy nagłówek na stronie, o tyle wyszukiwarka Yahoo może jako tytuł strony wyświetlić zawartość pierwszego nagłówka, jaki znajdzie w treści strony, co ostatnio przydarzyło mi się na jednej z moich stron. Tak się składa, że był to nagłówek H2 wygenerowany przez blok wyświetlający menu nawigacyjne – o treści „Primary links” i taki też tytuł strony pojawił się w wynikach wyszukiwania Yahoo.

Jeżeli menu nawigacyjne znajduje się w źródle strony powyżej pierwszego istotnego znacznika H1 lub H2, warto wyłączyć wyświetlanie jego tytułu. W tym celu należy odwiedzić listę bloków (ścieżka admin/build/block), kliknąć na odnośniku konfiguruj przy bloku Primary links, a następnie w polu tytułu bloku wpisać tekst , dzięki czemu tytuł bloku nie będzie się pojawiał.
Duplikująca się treść na wielojęzycznych stronach

Na stronach tworzonych w wielu językach zazwyczaj korzysta się ze standardowego bloku wyświetlającego odnośniki do alternatywnych wersji językowych. Przede wszystkim dotyczy nas tu problem opisany w poprzedniej sekcji. Jeżeli blok zmiany języka znajduje się w źródle strony powyżej pierwszego istotnego znacznika H1 lub H2, należy pozbawić go tytułu w sposób opisany powyżej.

Problem jest jednak głębszy. Otóż nawet na stronach, które nie posiadają alternatywnej wersji językowej, pojawi się odnośnik zmiany języka prowadzący do tej samej strony, lecz z adresem wzbogaconym o odpowiedni prefiks. Na tejże stronie przetłumaczone zostaną wszelkie napisy wygenerowane przez Drupala, natomiast zasadnicza treść artykułu pozostanie ta sama.

W tej sytuacji pozostają nam dwa wyjścia – na takich stronach nie umieszczać odnośnika do innych wersji językowych w ogóle, lub umieścić odnośnik do alternatywnej wersji językowej głównej strony naszego serwisu.

Taka zmiana wymaga dopisania jednej funkcji w dowolnym module. Oczywiście dobrze, aby był to jeden z naszych własnych modułów: zmiany w modułach standardowych to zły pomysł (znikną przy kolejnej aktualizacji Drupala). Opis tworzenia modułów wykracza poza ramy tego tekstu, więc zaprezentuję jedynie treść funkcji. Zakładam, że moduł, w którym znajdzie się ta funkcja nosi nazwę „naszmodul”.

function naszmodul_translation_link_alter(&$links, $path) {
    global $language;
    if (!($paths = translation_path_get_translations($path))) {
        foreach ($links as $langcode => $link) {
            if (strpos($links[$langcode]['href'], 'node/') === 0) {
                if ($langcode == $language->language) {
                    unset($links[$langcode]);
                } else {
                    $links[$langcode]['href'] = '';
                }
            }
        }
    }
}

To wystarczy, aby odnośniki zmiany języka nie prowadziły do zduplikowanej treści.

Drupal i wydajność na serwerach VPS

2010-02-09 | skomentuj

Gdyby zastanowić się przez chwilę, czy serwis oparty o Drupala będzie działał wydajniej po przeniesieniu się z hostingu dzielonego na serwer VPS, odpowiedź wydaje się oczywista – VPS to duży skok jakościowy w sferze wydajności. Jednak nie zawsze.Gdy w konfiguracji Drupala włączone jest pobieranie wyświetlanych stron z cache, wydajność zależy przede wszystkim od prędkości procesora oraz wydajności bazy danych. Jednak zdarzają się serwisy, w których korzystanie z cache jest utrudnione lub wręcz niemożliwe.

W takiej sytuacji każde wywołanie strony oznacza włączenie co najmniej kilkunastu plików przy pomocy operacji include. Czy włączenie pliku to taka czasochłonna operacja?

Napotkałem ostatnio taką właśnie sytuację – serwis uruchomiony na dzielonym hostingu działał o rząd wielkości szybciej niż uruchomiony na serwerze VPS, co stwierdziłem przy pomocy narzędzia ab (istotne jest, aby uruchamiać ab bezpośrednio na testowanym serwerze, aby odrzucić wpływ komunikacji sieciowej na pomiar wydajności, jeżeli już mierzymy ją tym sposobem). Analiza logów wygenerowanych przez moduł xdebug wykazała, że ponad połowa czasu wykonania została spędzona w operacji włączania plików.

Szybkie pomiary wykonane naiwną metodą kopiowania gigabajta danych z /dev/zero do pliku i z powrotem wykazały, że dane były kopiowane ze średnią prędkością 20MB/s (megabajtów na sekundę), co jest wynikiem bardzo miernym.

Duże znaczenie dla wydajności operacji dyskowych ma wybór oprogramowania realizującego wirtualizację. Ogólnie rzecz biorąc serwery VPS oparte o OpenVZ lub Virtuozzo realizują dostęp do dysku z prędkością niewiele mniejszą niż działoby się to na serwerze dedykowanym. Z kolei platforma Xen, choć zapewnia lepszą izolację serwerów wirtualnych – albo w wyniku tego – wypada w tym porównaniu bardzo mizernie. Jeżeli więc wiemy z góry, że nasza aplikacja włącza wiele plików, serwer VPS oparty o Xen może nie być najlepszym wyborem.

Czasem też wydajność operacji dyskowych jest obniżona przez kiepskie sąsiedztwo, a więc serwery VPS znajdujące się na tym samym fizycznym serwerze, na których uruchamiane są aplikacje intensywnie korzystające z dostępu do dysku.

Dobrym pomysłem jest wykupienie w upatrzonej firmie serwera VPS na miesiąc i wykonanie własnych testów wydajnościowych.