Etykiety

sobota, 31 grudnia 2016

MariaDB - Widoki

Widoki MariaDB - Wstęp


Podstawowym celem tego tutorialu jest omówienie podstaw widoków w MariaDB. Zobaczymy czym są widoki i do czego mogą się one nam przydać. Powiem wstępnie, iż widoki są tworzone na podstawie polecenia SELECT. Nazwy utworzonych widoków widnieją w bazie danych analogicznie do nazw istniejących tam tabel, ponieważ tabele i widoki dzielą się tą samą przestrzenią nazw. Po ich utworzeniu widoki mogą być modyfikowane lub usuwane, podobnie jak tabele.

MariaDB - Widoki
MariaDB

Praca z widokami wymaga gruntownej wiedzy z zakresu formułowania zapytań MySQL, a także z zakresu struktury tabel. Zobaczymy, że widoki MariaDB są potężnym i bardzo przydatnym narzędziem.

Dla lepszego zrozumienia zagadnienia widoków przygotowałem przykładowe tabele i wprowadziłem do nich wiersze danych.

Oto moje przykładowe tabele, zawierające tylko potrzebne dla niniejszego tutorialu kolumny, symulujące fragment bazy danych, powiedzmy jakiegoś rodzaju sklepu:
MariaDB [tests]> show tables; +-----------------+ | Tables_in_tests | +-----------------+ | cennik | | kontrahenci | | zakupy | +-----------------+ 4 rows in set (0.00 sec)

Tabela `cennik` jest cennikiem produktów. Zakładając, dla naszego przykładu, że ceny produktów są aktualizowane codziennie i w danym dniu dla każdego produktu może być wyłącznie jedna cena, utworzyłem odpowiedni klucz UNIQUE:
CREATE TABLE `cennik` ( `produkt` smallint(5) unsigned NOT NULL,> `cena_netto` decimal(6,2) NOT NULL, `data` date NOT NULL, UNIQUE KEY `produkt` (`produkt`,`data`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8

Wprowadzamy przykładowe dane do tabeli `cennik`:
MariaDB [tests]> insert into cennik values(1,10.15,"2016-03-03"),(1,10.16,"2016-03-04"),(2,10.15,"2016-03-03"),(2,11.16,"2016-03-04");

Tabela `kontrahenci`, jak sama nazwa sugeruje, zawiera dane osobowe kontrahentów, czyli klientów dokonujących zakupy w sklepie:
CREATE TABLE `kontrahenci` ( `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT, `imie` varchar(15) DEFAULT NULL, `nazwisko` varchar(20) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8

Wprowadzamy przykładowe dane do tabeli `kontrahenci`:
MariaDB [tests]> insert into kontrahenci (imie, nazwisko) values("Jan","Kowalski"),("Janusz", "Kowal");

Tabela zakupy zawiera informacje o zakupionych produktach i prezentuje się następująco:
CREATE TABLE `zakupy` ( `produkt` smallint(5) unsigned NOT NULL, `kontrahent` smallint(5) unsigned NOT NULL, `data` date NOT NULL, `ilosc` smallint(5) unsigned NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8

A oto przykładowe dane dla powyższej tabeli:
MariaDB [tests]> insert into zakupy values(1,1,"2016-03-03",3), (2,1,"2016-03-03",1),(1,1,"2016-03-04",3),(1,2,"2016-03-04",6);

Nasze tabele zawierają już jakieś informacje o dokonanych w naszym sklepie zakupach ;-) Załóżmy teraz, że chcemy się dowiedzieć, ile w sumie wydali klienci każdego dnia, kupując produkty w naszym sklepie. Aby uzyskać tego typu informacje wykonujemy następujące zapytanie:
MariaDB [tests]> select concat(kontrahenci.imie, ' ',kontrahenci.nazwisko) as klient, sum(cennik.cena_netto * zakupy.ilosc) as razem, zakupy.data from kontrahenci cross join zakupy on (zakupy.kontrahent = kontrahenci.id) left join cennik on (cennik.produkt = zakupy.produkt and cennik.data = zakupy.data) group by kontrahenci.id, zakupy.data; +--------------+-------+------------+ | klient | razem | data | +--------------+-------+------------+ | Jan Kowalski | 40.60 | 2016-03-03 | | Jan Kowalski | 30.48 | 2016-03-04 | | Janusz Kowal | 60.96 | 2016-03-04 | +--------------+-------+------------+ 3 rows in set (0.00 sec)

Zapytanie jest już samo w sobie nieco złożone.

Widoki MariaDB - Podstawowe koszyści


Mają na uwadzę powyżej przedstawione zapytanie i zakładając, iż mamy zamiar generować podobne raporty dość często, a na dodatek chcemy mieć możliwość filtrowania uzyskiwanych w ten sposób informacji, np. na podstawie zakresów dat, wówczas sprawy się nieco bardziej komplikują. Załóżmy również, że powyższe zapytanie ma być częścią kodu php aplikacji web, obsługującej nasz sklep internetowy. W przypadku konieczności modyfikacji struktury naszych tabeli, konieczna może stać się ingerencja w skrypty php zawierające zapytania SQL. Tutaj właśnie przychodzą nam z wielką pomocą widoki, nie tylko dlatego, iż mogą one uprościć nasze zapytania SQL, ale także dlatego, iż mogą one stanowić dodatkową programistyczną warstwę abstrakcyjną pomiędzy aplikacją web a właścimym zapytaniem SQL, co daje programistom dodatkową elastyczność. Jednak widoki mogą nam ułatwić wiele innych zadań. O tym napiszę w dalszej części tego artykułu.

Przed przejściem do dalszej części tego artykułu warto zapoznać się z poleceniem CREATE VIEW Wyjaśniam, że stosowana w naszym przykładzie składnia, zawierająca 'sql security invoker' oznacza iż dostęp do utworzonego widoku ma mieć miejsce z uprawnieniami, jakie posiada użytkownik wywołujący widok. Oznacza to, iż w przykładowym przypadku wywołania widoku przez osobę nie posiadającą uprawnień do tabeli `cennik`, zostanie wygenerowany błąd.

Zobaczmy teraz jak działają widoki w praktyce! Pamiętajmy o tym, iż do tworzenia widoków musimy posiadać uprawnienia CREATE VIEW do tabeli, które mają być objęte widokiem. Aby rozpocząć utwórzmy widok na podstawie naszego poprzedniego zapytania SQL. Robi się to przykładowo w ten oto sposób:
MariaDB [tests]> create sql security invoker view zakupy_wedlug_daty as select concat(kontrahenci.imie, ' ',kontrahenci.nazwisko) as klient, sum(cennik.cena_netto * zakupy.ilosc) as razem, zakupy.data from kontrahenci cross join zakupy on (zakupy.kontrahent = kontrahenci.id) left join cennik on (cennik.produkt = zakupy.produkt and cennik.data = zakupy.data) group by kontrahenci.id, zakupy.data; Query OK, 0 rows affected (0.03 sec)

Nowy widok jest dostępny w tej samej przestrzeni nazw co tabele:
MariaDB [tests]> show tables; +--------------------+ | Tables_in_tests | +--------------------+ | cennik | | kontrahenci | | zakupy | | zakupy_wedlug_daty | +--------------------+ 5 rows in set (0.00 sec)

Możemy już teraz zacząć korzystać z nowo utworzonego widoku:
MariaDB [tests]> select * from zakupy_wedlug_daty; +--------------+-------+------------+ | klient | razem | data | +--------------+-------+------------+ | Jan Kowalski | 40.60 | 2016-03-03 | | Jan Kowalski | 30.48 | 2016-03-04 | | Janusz Kowal | 60.96 | 2016-03-04 | +--------------+-------+------------+ 3 rows in set (0.00 sec)

Jak widać, wyniki powyższego zapytania są analogiczne do wyników naszego poprzedniego, bardziej złożonego zapytania, ponieważ widok został utworzony właśnie na jego podstawie, lecz nasze zapytanie jest teraz o wiele prostsze niż poprzednie, co daje większą swobodę i przejrzystość! W takiej sytuacji, możemy w prosty sposób dodawać kolejne warunki do naszego zapytania. Na przykład:
MariaDB [tests]> select * from zakupy_wedlug_daty where data between "2016-03-02" and "2016-03-03" and klient like "%Kowalski"; +--------------+-------+------------+ | klient | razem | data | +--------------+-------+------------+ | Jan Kowalski | 40.60 | 2016-03-03 | +--------------+-------+------------+ 1 row in set (0.00 sec)

Jak wspomniałem wcześniej, dodatkowym atutem widoków, jest ich programistyczna warstwa abstrakcyjna w przypadku aplikacji zawierających zapytania SQL. Jeśli w naszych aplikacjach stosujemy widoki, modyfikacje struktury tabeli nie niosą za sobą konieczności dopasowania zapytań SQL obecnych w aplikacji! Jedyne co może być w takim przypadku konieczne, będzie dopasowanie widoku, a można to przykładowo zrobić za pomocą polecenia ALTER VIEW.
Aby sprawdzić, w jaki sposób został utworzony dany widok, można wydać polecenie SHOW CREATE VIEW, przykładowo:
MariaDB [tests]> show create view zakupy_wedlug_daty;

Ciekawostką, o której warto tutaj wspomnieć, jest to, iż widoki mogą być tworzone nie tylko na podstawie zapytań obejmujących tabele, lecz zapytania te mogą obejmować także widoki!
Widoki usuwamy za pomocą polecenia DROP VIEW.

Widoki - Dodatkowe korzyści


Widoki w MariaDB to cudowne narzędzie! Oprócz omówionych wcześniej korzyści, stosowanie widoków daje nam możliwość ograniczenia dostępności poufnych informacji. Załóżmy, że tabela kontrahenci zawiera o wiele więcej kolumn niż imię i nazwisko, a są to przykładowo kolumny takie jak numer pesel, czy numery kart kredytowych. Załóżmy również, że użytkownik widoku ma mieć możliwość formułowania zapytań obejmujących wyłącznie wybrane kolumny tej tabeli. Staje się jasne, jak przydatne są tutaj widoki! Możemy w ten sposób tworzyć różne widoki, oparte na tych samych tabelach, lecz umożliwiające dostęp wyłacznie do wybranych kolumn tych tabel, w zależności od rodzaju dostępu do informacji, jaki mamy zamiar przydzielić użytkownikom tych widoków.

Dodatkowym atutem stosowania widoków, w przypadku baz danych złożonych z wielu tabel, w których występują bardzo złożone relacje danych, jest możliwość tworzenia idealnie zoptymalizowanych zapytań zawierających różnego rodzaju skomplikowane łączenia i udostępniania ich mniej doświadczonym użytkownikom, w celu ograniczenia obciążeń serwera wynikających z nieodpowiednio sformułowanych zapytań.

Mam nadzieję, iż niniejszy tutorial okaże się pomocny. W przypadku pytań proszę o komentarze :-)

czwartek, 29 grudnia 2016

Serwer DHCP Linux - Podstawowa konfiguracja

Serwer DHCP umożliwia automatyczne przydzielanie adresów IP klientom sieciowym obsługującym ten protokół, ale jego rola nie kończy się na tym zadaniu. Wraz z adresem IP, maszyny klienckie moga otrzymywać wiele innych informacji związanych ze środowiskiem sieciowym, takich jak adresy routerów, adresy serwerów DNS, adresy serwerów WINS i wiele innych. W ten sposób użytkownicy poszczególnych komputerów w sieci, nie muszą ani znać, ani recznie wprowadzać tych informacji w ustawieniach interfejsów sieciowych swoich maszyn. Jest to szczególnie pożyteczne w rozległych sieciach, w których znajduje się duża ilość komputerów.

W tym tutorialu, pierwszym z serii poświęconej zagadnieniom DHCP / BIND, ograniczam się do wyjaśnienia jak uruchomić, z podstawowymi ustawieniami konfiguracyjnymi, serwer DHCP na maszynach pracujących pod kontrolą systemów Red Hat Linux, Fedora lub Centos. Choć w większości innych dystrybucji systemu Linux konfiguracja sewera DHCP przebiega analogicznie, występują tam pewne różnice związane z pozostałymi kwestiami poruszanymi w tym tutorialu.

Zobaczmy teraz jak pozyskać, zainstalować i skonfigurować pakiet oprogramowania serwera DHCP.

Przed rozpoczęciem, na maszynie na której mamy zamiar zainstalować serwer DHCP, należy ustawić stały adres IP dla interfejsu sieciowego, obsługującego sieć, dla której mamy zamiar skonfigurować oprogramowanie. Aby to zrobić należy edytować odpowiedni skrypt konfiguracyjny interfejsu sieciowego, domyślnie noszący nazwę interfejsu z prefiksem ifcfg-.

Skrypty zawierające konfiguracje interfejsów sieciowych znajdują się w lokalizacji:
/etc/sysconfig/network-scripts/
Ponieważ w naszym przykładzie interfejs sieciowy nosi nazwę enp6s0, plik zawierający ustawienia konfiguracyjne to odpowiednio:
/etc/sysconfig/network-scripts/ifcfg-enp6s0
Konfiguracja interfejsu sieciowego, dla którego ma zostać uruchomiony serwer DHCP, powinna uwzględniać ustawienie stałego adresu IP. Dla naszego przykładu będzie to adres klasy C:
TYPE=Ethernet NAME=enp6s0 ONBOOT=yes HWADDR=10:43:54:E2:CC:18 IPADDR=192.168.0.7 NETMASK=255.255.255.0 GATEWAY=192.168.0.1
Jeśli stały adres IP dla naszego interfejsu nie jest jeszcze ustawiony, warto to zrobić przez przejściem do kolejnego kroku. Należy oczywiście ustawić adres IP należący do podsieci, która ma być obsługiwana przez nasz serwer DHCP, zgodnie z ustawieniami w pliku konfiguracyjnym dhcpd.conf, o którym będzie mowa troszkę dalej.

Po dostosowaniu ustawień interfejsu sieciowego należy zrestartować usługi sieciowe:
[root@amanda ~]# systemctl restart network
Warto teraz upewnić się, że sieć działa jak neleży:
[root@amanda ~]# systemctl status network ● network.service - LSB: Bring up/down networking Loaded: loaded (/etc/rc.d/init.d/network; bad; vendor preset: disabled) Active: active (exited) since Sun 2016-12-25 21:46:32 CET; 3 days ago Docs: man:systemd-sysv-generator(8) Dec 25 21:46:31 amanda systemd[1]: Starting LSB: Bring up/down networking... Dec 25 21:46:32 amanda network[1207]: Bringing up loopback interface: [ OK ] Dec 25 21:46:32 amanda network[1207]: Bringing up interface enp6s0: [ OK ] Dec 25 21:46:32 amanda systemd[1]: Started LSB: Bring up/down networking. Hint: Some lines were ellipsized, use -l to show in full.
Jeśli usługi sieciowe działają prawidłowo, możemy przejść do instalacji pakietu zawierającego serwer DHCP:
[root@amanda ~]# yum install dhcp
Następnie, przed uruchomieniem serwera DHCP, należy wprowadzić ustawienia konfiguracyjne w pliku dhcpd.conf. Plik dhcpd.conf jest miejscem, w którym określamy co nasz serwer ma robić i jak ma to robić. Może on zawierać rozmaite ustawienia i opcje. Jest tego naprawdę bardzo dużo. Tych, którzy chcieliby już teraz zapoznać się ze wszystkimi możliwościami konfiguracji serwera DHCP, zachęcam do przeczytania manuala dhcpd.conf a także manuala opcji dhcpd.conf. Dla niniejszego przykładu wystarczą jednak poniższe, podstawowe i proste ustawienia:
option routers 192.168.0.1; default-lease-time 600; max-lease-time 7200; authoritative; log-facility local7; subnet 192.168.0.0 netmask 255.255.255.0 { range 192.168.0.170 192.168.0.180; } host maszyna_janka { hardware ethernet 91:12:e9:a7:97:7b; fixed-address 192.168.0.100; } host hp2055dn { hardware ethernet 00:22:5e:8E:94:61; fixed-address 192.168.0.108; }
A oto znaczenie powyższych ustawień:

option-routers: opcja pozwala określić listę routerów znajdujących się w obsługiwanej podsieci. Jeśli routerów jest więcej, wówczas należy je oddzielić przecinkami;

default-lease-time: ustawienie pozwala określić domyślną wartość czasu ważności przydziału, wyrażoną w sekundach, dla przydziałów, dla których klient nie żąda konkretnego czasu ważności;

max-lease-time: uswtawienie pozwala określić maksymalną wartość czasu przydziału, wyrażoną w sekundach;

authoritative: ustawienie to oznacza, iż serwer DHCP jest autorytatywny dla obsługiwanych podsieci;

log-facility: ustawienie określa sposób prowadzenia dzienników zdarzeń;

subnet: ustawienie pozwala zdefiniować obsługiwane przez serwer podsieci, w których pula przydzielnych adresów IP określana jest słowem kluczowym range;

host: ustawienie umozliwiające zdefiniowanie stałych adresów IP dla maszych znajdujących się w obsługiwancyh podsieciach. Adresy te powinny jednak znajdować się poza zakresami puli przydzielnych adresów;

Przed przystąpieniem do uruchomienia serwera DHCP, warto sprawdzić, czy plik dhcpd.conf nie zawiera błędów, a można to zrobić w następujący sposób:
[root@amanda ~]# dhcpd -t -cf /etc/dhcp/dhcpd.conf Internet Systems Consortium DHCP Server 4.2.5 Copyright 2004-2013 Internet Systems Consortium. All rights reserved. For info, please visit https://www.isc.org/software/dhcp/ Not searching LDAP since ldap-server, ldap-port and ldap-base-dn were not specified in the config file
Uruchamiamy serwer dhcp i sprawdzamy jego status:
[root@amanda ~]# systemctl status dhcpd ● dhcpd.service - DHCPv4 Server Daemon Loaded: loaded (/usr/lib/systemd/system/dhcpd.service; disabled; vendor preset: disabled) Active: active (running) since Thu 2016-12-29 16:44:42 CET; 3min 15s ago Docs: man:dhcpd(8) man:dhcpd.conf(5) Main PID: 25995 (dhcpd) Status: "Dispatching packets..." CGroup: /system.slice/dhcpd.service └─25995 /usr/sbin/dhcpd -f -cf /etc/dhcp/dhcpd.conf -user dhcpd -group dhcpd --no-pid Dec 29 16:44:42 amanda dhcpd[25995]: Wrote 0 leases to leases file. Dec 29 16:44:42 amanda dhcpd[25995]: Listening on LPF/enp6s0/00:23:54:f2:cc:18/192.168.0.0/24 Dec 29 16:44:42 amanda dhcpd[25995]: Sending on LPF/enp6s0/00:23:54:f2:cc:18/192.168.0.0/24 Dec 29 16:44:42 amanda dhcpd[25995]: Sending on Socket/fallback/fallback-net Dec 29 16:44:42 amanda systemd[1]: Started DHCPv4 Server Daemon. Dec 29 16:45:40 amanda dhcpd[25995]: DHCPREQUEST for 192.168.0.111 (192.168.0.6) from 90:02:a9:c5:27:24 via enp6s0: unknown lease 192.168.0.111.
Jeśli chcemy, aby serwer automatycznie się uruchamiał przy starcie systemu, wówczas należy wykonać następujący krok:
[root@amanda ~]# systemctl enable dhcpd Created symlink from /etc/systemd/system/multi-user.target.wants/dhcpd.service to /usr/lib/systemd/system/dhcpd.service.
Na tym etapie możemy już ustawić maszyny klienckie, do automatycznego pozyskiwania adresów IP. Przykładowo w systemach Windows można to zrobić w następujący sposób:


Automatyczne uzyskiwanie adresu IP - Windows
Automatyczne uzyskiwanie adresu IP w systemie Microsoft Windows

Aby sprawdzić aktualny stan przydziałów, po stronie serwera można to zrobić w następujący sposób:
[root@amanda ~]# cat /var/lib/dhcpd/dhcpd.leases lease 192.168.0.172 { starts 4 2016/12/29 15:45:23; ends 4 2016/12/29 15:55:23; tstp 4 2016/12/29 15:55:23; cltt 4 2016/12/29 15:45:23; binding state free; hardware ethernet 32:d8:1b:f4:69:82; uid "\0014\336\032\363\211\202"; }

Aby otrzymać lub wznowić przydział dla maszyny po kontrolą systemu Windows, można z wiersza poleceń Windows cmd, wydać następujące polecenie:
C:\Users\XNOTE>ipconfig /renew

Aby sprawdzić na wszystkich interfejsach sieciowych danego komputera, czy maszyna kliencka Windows otrzymała przydziały IP, a także odczytać inne informacje pozyskane wraz z przydziałami, można to zrobić w następujący sposób z wiersza poleceń Windows cmd:

C:\Users\XNOTE>ipconfig /all
Powodzenia! W przypadku pytań proszę o komentarze.

wtorek, 27 grudnia 2016

Aktualizacja serwera MariaDB z wersji 5.5 do wersji 10.1 w systemach Red Hat, Centos i Fedora

Aktualizacja pakietu MariaDB z wersji 5.5 do wersji 10.1 może wydawać się czynnością banalną, bo takową w rzeczywistości jest, lecz powikłania jej nieprawidłowego wykonania mogą spędzać sen z powiek niejednemu adminowi.
Ponieważ wewnętrzne struktury tabeli baz danych sporo się różnią pomiędzy tymi dwoma wersjami pakietów, kluczowe znaczenie w tej procedurze ma uruchomienie programu mysql_upgrade tuż po zainstalowaniu nowych wersji oprogramowania i uruchomieniu serwera MariaDB, ale tylko jeśli aktualizacja miała miejsce w systemach Red Hat, Fedora lub Centos, ponieważ pakiety oprogramowania w systemach Ubuntu i Debian wykonują tą czynność automatycznie i samodzielnie.
Przygotowałem ten krótki artykuł, ponieważ w ostatnim czasie zbyt wielu użytkowników Linuxa kontaktowało się ze mną w związku z problemami, które występowały po przejściu z wersji 5.5 do 10.1 pakietu MariaDB. Najbardziej zdesperowani byli Ci, którzy zatrudnieni są w dużych korporacjach, gdzie aktualizowano jednocześnie więcej serwerów. Niektorzy z nich wpadali w prawdziwy szał gdy serwer MariaDB nie uruchamiał się tuż po aktualizacji.
Najczęściej występujące problemy po aktualizacji z wersji 5.5 do wersji 10.1 to nie tylko brak możliwości uruchomienia serwera MariaDB, lecz także inne przykre błędy, uniemożliwiające normalne korzystanie z baz danych.
Przykładowe problemy występujące po błędnie wykonanej aktualizacji pakietu, na podstawie dziennika logów MariaDB:
[ERROR] mysqld: Can't lock aria control file '/var/lib/mysql/aria_log_control' for exclusive use, error: 11. Will retry for 30 seconds [ERROR] mysqld: Got error 'Could not get an exclusive lock; file is probably in use by another process' when trying to use aria control file '/var/lib/mysql/aria_log_control' [ERROR] Plugin 'Aria' init function returned error. [ERROR] Plugin 'Aria' registration as a STORAGE ENGINE failed. [ERROR] InnoDB: Unable to lock ./ibdata1, error: 11 [ERROR] InnoDB: Could not open or create the system tablespace. If you tried to add new data files to the system tablespace, and it failed here, you should now edit innodb_data_file_path in my.cnf back to what it was, and remove the new ibdata files InnoDB created in this failed attempt. InnoDB only wrote those files full of zeros, but did not yet use them in any way. But be careful: do not remove old data files which contain your precious data! [ERROR] Plugin 'InnoDB' init function returned error. [ERROR] Plugin 'InnoDB' registration as a STORAGE ENGINE failed. [ERROR] /usr/sbin/mysqld: unknown option '--log-slow-queries' [ERROR] Aborting

Aktualizacja MariaDB z wersji 5.5 do wersji 10.1 w systemach Red Hat, Fedora i Centos - zalecana procedura krok po kroku


1. Tworzymy plik /etc/yum.repos.d/MariaDB.repo, którego zawartość powinna wyglądać tak:
[mariadb] name = MariaDB
baseurl = http://yum1.mariadb.org/10.1/centos7-amd64
gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
gpgcheck=1
2. Wykonujemy kopię zapasową wszystkich baz danych MariaDB. Przykładowo w następujący sposób:
[root@amanda /]# mysqldump -c --all-databases -p > backup_27122016.sql
3. Usuwamy wersje 5.5 pakietu oprogramowania MariaDB
[root@amanda /]# yum remove mariadb mariadb-server
4. Instalujemy nowe wersje oprogramowania
[root@amanda /]# yum install MariaDB-client MariaDB-server MariaDB-shared MariaDB-common
5. Uruchamiamy serwer
[root@amanda /]# systemctl start mariadb
6. Aktualizujemy strukturę istniejących tabeli MariaDB
[root@amanda /]# mysql_upgrade -p
Przykładowy wynik uruchomienia programu mysql_upgrade:


Zobacz film: aktualizacja MariaDB z 5.5 do 10.1 - jak to zrobić krok po kroku!


W przypadku prawidłowego wykonania procedury aktualizacyjnej pakiet MariaDB nie powinien sprawiać jakichkolwiek problemów. Powodzenia!

niedziela, 24 lipca 2016

Jak automatycznie pobierać kursy walut NBP ?

Automatyczne pobieranie kursów poszczególnych walut z sieci to niekiedy złożone zadanie, z którym jednak każdy zawodowy twórca systemów informatycznych prędzej czy później musi się zmierzyć.
W niniejszym artykule, który przeznaczony jest dla średnio zaawansowanych i zaawansowanych programistów, chciałbym przestawić uproszczoną wersję opracowanej przeze mnie i wielokrotnie zastosowanej w wielu środowiskach produkcyjnych, metodę pobierania z sieci średniego kursu danej waluty z wybranej daty oraz automatycznego wstawiania tej wartości do formularza HTML w aplikacjach web.

Kursy walut z API NBP
Kursy walut dla aplikacji web - API NBP - Jak to działa


Jak dobrze wiadomo, w aplikacjach o charakterze finansowym, bądź biznesowym, dość często pojawia się konieczność wpisywania aktualnego kursu danej waluty do przetwarzanego na serwerze formularza. Po co więc za każdym razem wchodzić na witrynę Narodowego Banku Polskiego NBP, szukać tam tabeli kursów z danego dnia, odczytywać z niej wartości i przepisywać, bądź kopiować i wklejać do formularza, skoro można w sposób w pełni zautomatyzowany pobierać wartości kursów i wstawiać je do fomularza web za jednym wciśnięciem przycisku? Zautomatyzowane rozwiązanie może okazać się bardzo przydatne, szczególnie w przypadku konieczności codziennego, częstego odczytu wartości kursów walut, np. w aplikacjach web związanych z eksportem i fakturowaniem.
Przedstawiona tutaj metoda automatycznego pobierania średniego kursu Euro, obowiązującego dla konkretnej daty, wymaga zastosowania zarówno skryptów jQuery - po stronie przeglądarki - jak i skryptów php po stronie serwera oraz uproszczonego, przykładowego kodu html, koniecznego do osadzenia w nim formularza.
Chciałbym z góry zaznaczyć, że działającym przykładem zastosowania przedstawionego tutaj rozwiązania jest witryna Kursy Walut mojego autorstwa.

Założenia wstępne


Przedstawiony w niniejszym artykule przykład jest zupełnie "nagi" i ma służyć jedynie jako materiał szkoleniowy. Nie zastosowałem w nim żadnych dodatkowych funkcji, oprócz tych, które są niezbędne do zwyczjnego zadziałania mechanizmu. Aby jednak mechanizm mógł mieć zastosowanie w środowisku produkcyjnym, powinien on zostać opatrzony przez programistę w należyte środki bezpieczeńśtwa.

Skąd pobierać kursy walut?


Jedynym wiarygodnym źródłem kursów walut jest Narodowy Bank Polski. Jak powszechnie wiadomo, NBP od bardzo dawna udostępnia na swojej oficjalnej witrynie tabele kursów walut. Od dość niedawna jednak została uruchomiona dodatkowa poddomena NBP http://api.nbp.pl/, pod którą są umieszczane kursy walut w formatach .xml oraz .json dla celów programistycznych. Stąd właśnie będziemy pobierać kursy dla celów przedstawionego tutaj przykładu. Pliki API NBP są generowane po stronie serwera NBP, w sposób zależny od zapytania HTTP wysłanego przez klienta. Warto wstępnie zapoznać się z różnymi, możliwymi parametrami zapytań: http://api.nbp.pl/#kursyParams. Wstępne zapoznanie się z instrukcjami znajdującymi się w witrynie API NBP znacznie ułatwi zrozumienie mojego przykładu.

Jak to działa?


Pod adresem http://api.nbp.pl/api/exchangerates/rates/A/EUR/ znajdują się dane aktualnie obowiązującego średniego kursu Euro. Aby jednak uzyskać informacje dotyczące kursu Euro dla konkretnie wybranej daty, należy dołączyć datę do zapytania, np. http://api.nbp.pl/api/exchangerates/rates/A/EUR/2016-07-22
Należy zwrócić uwagę na fakt, iż możemy w ten sposób uzyskać pliki z danymi kursów, zarówno w formacie JSON jak i XML. Aby zrobiło się trochę ciekawiej, w niniejszym przykładzie posługuję się formatem XML!

Aby uzyskać informacje o kursach w formacie XML należy dodać odpowiedni parametr do naszego przykładowego zapytania: http://api.nbp.pl/api/exchangerates/rates/A/EUR/2016-07-22?format=xml

Gdy klikamy w przycisk "Pobierz i wstaw" w formularzu, którego źródło HTML przedstawiam poniżej, osadzony w sekcji HEAD kod jQuery wywołuje skrypt php api_nbp_tab_A_xml.php, przekazując mu interesującą nas datę w zmiennej $_POST. Skrypt php sprawdza czy szukany przez nas plik xml istnieje w lokalnym katalogu, a jeśli nie, to stara się go uzyskać ze zdalnego serwera NBP. Jeśli plik ze średnim kursem naszej przykładowej waluty, dla wybranej daty, nie został już uprzednio skopiowany na nasz lokalny katalog, skrypt php api_nbp_tab_A_xml.php stara się odnaleźć takowy zdalny plik kursu średniego Euro dla wybranej przez nas daty, wywołując odpowiednie zapytanie HTTP. Jeśli plik zostaje odnaleziony na zdalnym serwerze, skrypt php kopiuje go do lokalnego katalogu /xml, jeśli natomiast plik nie zostaje odnaleziony, wówczas skrypt zwraca odpowiedni komunikat.

W kolejnym etapie skrypt jQuery wysyła lokalne zapytanie XMLHttpRequest, tworząc objekt tej klasy, w celu odniesienia się do ewentualnie skopiowanego lokalnego pliku, po czym, jeśli odpowiedź lokalnego sewera jest pozytywna i plik jest "gotowy" - czyli mamy:
xhttp.readyState == 4 && xhttp.status == 200
, wówczas następuje przetwarzanie zawartości pliku poprzez funkcje getRates() i wydobywanie z niego interesujących nas wartości, które są wstawiane do formularza poprzez:
$("#kurs_euro1").val(rateInt);
$("#kurs_euro2").val(rateDec);
$("#kurs-result").html(tab);
$("#tabela_nbp").val(tab);


Formularz HTML




CSS



Kod jQuery




Skrypt PHP


Oto zawartość wywoływanego przez powyższy kod jQuery skryptu api_nbp_tab_A_xml.php:
define('XML_FILES_PATH', $_SERVER['DOCUMENT_ROOT']."xml/");

function isValidDate($date) {
$d = DateTime::createFromFormat('Y-m-d', $date);
return $d && $d->format('Y-m-d') === $date;
}

function URL_exists($url){
$headers=get_headers($url);
return stripos($headers[0],"200 OK")?true:false;
}

// Jeżeli data jest prawidłowa
if (isValidDate($_POST['data'])) {

// Jeżeli plik xml jeszcze nie istnieje w lokalnym katralogu
if(!file_exists(XML_FILES_PATH.$_POST['data'].".xml")) {

// Jeżeli istnieje dokument xml
if(URL_exists("http://api.nbp.pl/api/exchangerates/rates/A/EUR/".$_POST['data']."?format=xml")) copy("http://api.nbp.pl/api/exchangerates/rates/A/EUR/".$_POST['data']."?format=xml", XML_FILES_PATH.$_POST['data'].".xml");
else die('Tabela nie została odnaleziona!');

if (file_exists(XML_FILES_PATH.$_POST['data'].".xml")) die('Zaimportowano tabelę!'); else die('Proba zaimportowania tabeli nie powiodła się!');

} else die('Tabela istnieje!');

} else die('Proszę wybrać datę!'); -


Działający przykład


Działający przykład przedstawionej tutaj metody można przetestować pod adresem http://kursy-walut.info


Czy artykuł okazał się pomocny?


Jeśli artykuł spodobał się lub okazał się pomocny uprzejmie proszę o udostępnianie go w sieci. W razie pytań służę pomocą. Proszę o komentarze.

sobota, 23 kwietnia 2016

Odzyskiwanie hasła admina Drupal 7

Odzyskiwanie hasła admina w systemie zarządzania zawartością Drupal 7 jest bardzo proste, pod warunkiem, iż system jest w stanie wysłać nam wiadomość z nowym hasłem dostępu. Niestety, nie zawsze wszystko idzie po najlepszej myśli. Od długiego czasu administruję bardzo dużą ilością witryn www, z których spora część to strony oparte na systemie Drupal, więc zdarza mi się niekiedy, iż hasła admina do danej witryny po prostu nie pamiętam, a system z tej lub owej przyczyny nie jest w stanie wysłać mi wiadomości z nowym hasłem, bądź stary adres poczty elektronicznej już od dawna nie jest aktualny, więc hasło nie dociera. Tak czy inaczej, w praktyce tego typu sytuacje mają często miejsce.

Opiszę tutaj jak odzyskać hasło admina do systemu CMS Drupal 7 w przypadku pojawienia się kłopotów z wysłaniem nowego hasła w wiadomości email i nie mając dostępu do Shell'a. Zakładam tutaj jednak możliwość dostępu do katalogu www poprzez FTP, a także dostęp do bazy danych poprzez phpMyAdmin.

Odzyskiwanie hasła admina - Drupal 7



W systemie Drupal 6, w którym hasło admina zabezpieczane było w tabeli bazy danych SQL algorytmem kryptograficznym MD5, odzyskanie hasła w sytuacji opisanej powyżej wiązało się jedynie z wydaniem jednego polecenia SQL w interfejsie phpMyAdmin, np:
 
update users set pass = md5('newpass') where uid = 1;

W systemie Drupal 7, gdzie hasła użytkowników haszowane są za pomocą o wiele bezpieczniejszego od MD5 algorytmu sha512, sytuacja nieco się komplikuje, lecz odzyskanie hasła jest możliwe nadal w sposób dość banalny, pod warunkiem, że wiemy jak to zrobić. Jak więc odzyskać hasło admina Drupal 7 gdy system nie wysyła poczty? Ponadto, skoro nie mamy dostępu do Shell'a to nie możemy wygenerować zahaszowanego ciągu znaków nowego hasła, korzystając ze specjalnego skryptu znajdującego się zestawie skryptów Drupal 7, tak aby wygenerowany w ten sposób ciąg znaków wpisać później do kolumny o nazwie pass w tabeli users, w wierszu odpowiednim użytkownikowi admin, czyli o wartości uid = 1 . Gdy dostęp do Shell'a jest możliwy, wówczas z poziomu głównego katalogu Drupal ciąg znaków odpowiadający zahaszowanemu hasłu można wygenerować w ten oto sposób:

cd scripts;
password-hash.sh 'nowehasloadmina'

Jedyne co nam pozostaje, w sytuacji gdy nie mamy dostępu do Shell'a, a wiadomości z nowym hasłem nie są wysyłane przez system Drupal, to utworzenie skryptu php z odpowiednią zawartością, przesłanie go na główny katalog systemu Drupal poprzez ftp i uruchomienie skryptu w przeglądarce. Oto jaką treść powinien zawierać nasz magiczny skrypt php, który po uruchomieniu w przeglądarce wyświetli nam ciąg znaków odpowiadający zahaszowanemu hasłu:
<?php
define('DRUPAL_ROOT', getcwd());
require_once DRUPAL_ROOT . '/includes/bootstrap.inc';
require_once 'includes/common.inc';
require_once 'includes/password.inc';
echo user_hash_password('nowehasloadmina');
die();
?>

Otrzymany w ten sposób ciąg znaków należy wprowadzić do kolumny o nazwie pass, w tabeli users, po uprzednim uwierzytelnieniu się w interfejse phpMyAdmin, wydając następujące polecenie SQL:
update users set pass = 'zahaszowanehasloadmina' where uid = 1;

To wszystko na dziś i mam nadzieję, że artykuł okaże się pomocny. Jeśli tak, to z góry dziękuję za udostępnianie.