W poprzednich częściach stworzyliśmy prostą makietę dla naszej aplikacji, projekt bazy danych oraz napisaliśmy pliki z migracjami dla bazy danych. W tej części zajmiemy się logowaniem do aplikacji. Na początek stworzymy model oraz kontroler. Zanim jednak w ogóle poruszymy ten temat, warto abyśmy zapoznali się z materiałem z podręcznika na ten temat: modele, klasa Active Record i kontrolery.
Teraz można założyć, że mamy już podstawy, więc możemy przejść do konkretów. Nasz model będzie nosił nazwę User_model, a kontroler Users – w plikach znajdzie się kod odpowiedzialny za uwierzytelnianie użytkownika w naszej aplikacji. Na początek utwórzmy plik w katalogu application/models o nazwie user_model.php:
<?php defined('BASEPATH') OR exit('No direct script access allowed');
class User_model extends CI_Model
{
// Nazwa tabeli, z której będziemy korzystać w modelu
public $table = 'users';
/**
* Logowanie użytkownika
* Sprawdza, czy użytkownik o podanym adresie email i haśle istnieje w bazie danych
*
* @access public
* @return mixed
*/
public function login($email, $password)
{
// Jeśli w bazie zostanie znaleziony użytkownik o podanym adresie email i haśle,
// to wynik zostanie zwrócony do kontrolera w postaci tablicy, w innym wypadku otrzymamy pusty wynik.
return $this->db->where(array('email' => $email, 'password' => $password))->get($this->table)->row_array();
}
}
/* End of file user_model.php */
/* Location: ./application/models/user_model.php */
Jeśli zastanawiasz się co w powyższym kodzie robi funkcja row_array(), to warto zapoznać się ze sposobami na generowanie wyników zapytań w CodeIgniterze – wtedy wszystko powinno być jasne. Teraz możemy się zająć kontrolerem. Utwórzmy plik users.php w katalogu application/controllers o takiej treści:
<?php defined('BASEPATH') OR exit('No direct script access allowed');
class Users extends CI_Controller
{
public function login()
{
// Ładujemy bibliotekę walidacji formularza
$this->load->library('form_validation');
// Określamy jakie tagi będą otaczać komunikat błędu walidacji.
// To kwestia stricte kosmetyczna - dostosowanie wyglądu do Twitter Bootstrap.
$this->form_validation->set_error_delimiters('<div class="alert alert-error"><a class="close" data-dismiss="alert" href="#">×</a>', '</div>');
// Ustalamy reguły walidacji dla formularza
$this->form_validation->set_rules('email', 'Login', 'required|trim|valid_email|xss_clear');
$this->form_validation->set_rules('password', 'Hasło', 'required|trim|sha1');
// Sprawdzamy, czy formularz został wysłany i czy wystąpiły błędy walidacji.
if ($this->form_validation->run() === FALSE)
{
// Ładujemy helper Form, aby ułatwić sobie pracę z formularzem.
$this->load->helper('form');
// Jeśli walidacja formularza nie powiodła się (lub metoda jest wywołana po raz pierwszy), wyświetlamy pliki z katalogu partials oraz widok "user_login",
// który znajduje się w katalogu "application/views". Ewentualne informacje o błędach w formularzu są przekazywane automatycznie.
$this->load->view('partials/header');
$this->load->view('user_login');
$this->load->view('partials/footer');
}
else
{
// Jeśli walidacja formularza powiodła się, przypisujemy odpowiednie zmienne z tablicy $_POST do zmiennej $email i $password
$email = $this->input->post('email');
$password = $this->input->post('password');
// Ładujemy wcześniej utworzony model
$this->load->model('user_model');
// Wywołujemy metodę "login" modelu "user_model" wraz z parametrami i przypisujemy zwrócony wynik do zmiennej $user
if ($user = $this->user_model->login($email, $password))
{
// Jeśli zwrócony wynik nie jest pusty (czyli znaleziono użytkownika o podanym adresie email i haśle),
// ustawiamy zmienną sesyjną o nazwie "user_id" na wartość unikalnego identyfikatora użytkownika.
$this->session->set_userdata('user_id', $user['id']);
// Ustawiamy zmienną flashadata o nazwie success i przypisujemy do niej komunikat o powodzeniu logowania.
$this->session->set_flashdata('success', 'Logowanie przebiegło pomyślnie!');
// Przekierowujemy użytkownika na stronę ze wszystkimi postami podając w funkcji nazwę kontrolera/metody, która ma zostać wywołana.
// W tym wypadku nie ma znaczenia, czy podamy 'posts/index', czy samo 'posts', ponieważ CodeIgniter domyślnie zinterpretuje samo 'posts' jako wywołanie
// metody 'index' - jako domyślnej funkcji dla każdego kontrolera.
redirect('posts');
}
else
{
// Jeśli zwrócony wynik jest pusty (czyli nie znaleziono użytkownika o podanym adresie email i haśle),
// ustawiamy zmienną flashadata o nazwie error i podajemy komunikat o niepowodzeniu logowania.
$this->session->set_flashdata('error', 'Podany login lub hasło są nieprawidłowe!');
// Przekierowujemy użytkownika na stronę logowania podając dla funkcji nazwę kontrolera/metody, która ma zostać wywołana
redirect('users/login');
}
}
}
public function logout()
{
// Niszczymy aktualną sesję
$this->session->sess_destroy();
// Przekierowujemy na stronę logowania
redirect('users/login');
}
}
/* End of file users.php */
/* Location: ./application/controllers/users.php */
Teraz pora przejść do widoków. Oczywiście nie będziemy omawiać całej struktury Twitter Bootstrap – jeśli chcesz ją poznać, musisz to zrobić samodzielnie. Na początek utworzymy dwa „partiale” – w katalogu application/views, tworzymy katalog partials, a w nim dwa pliki z nagłówkiem szablonu i stopką. Te dwa pliki będziemy wczytywali za każdym razem, co widać w metodzie login.
Kod zawarty w samych partialach jest stosunkowo prosty i wygląda następująco, header.php:
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="utf-8">
<base href="<?php echo base_url(); ?>">
<title>Blog tutorial</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="author" content="CodeIgniter.org.pl">
<!-- Le styles -->
<link href="assets/css/bootstrap.css" rel="stylesheet">
<style type="text/css">
body {
padding-top: 60px;
padding-bottom: 40px;
}
</style>
<link href="assets/css/bootstrap-responsive.css" rel="stylesheet">
<!-- HTML5 shim, for IE6-8 support of HTML5 elements -->
<!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<a class="brand">Blog tutorial</a>
<div class="nav-collapse collapse">
<ul class="nav">
<!--
Poniżej sprawdzamy, czy dana pozycja w menu jest aktualnie odwiedzaną stroną.
Jeśli tak, to do tagu <li> dodajemy klasę "active", która zmieni wygląd tego elementu.
Aby dowiedzieć się jak działa funkcja rsegment zajrzyj do podręcznika: http://podrecznik.codeigniter.org.pl/libraries/uri.html
-->
<li <?php echo ($this->uri->rsegment('2') == 'index') ? 'class="active"' : ''; ?>><a href="<?php echo site_url('posts/index'); ?>">Lista</a></li>
<li <?php echo ($this->uri->rsegment('2') == 'add') ? 'class="active"' : ''; ?>><a href="<?php echo site_url('posts/add'); ?>">Dodaj</a></li>
</ul>
<ul class="nav pull-right">
<!--
Sprawdzamy, czy użytkownik jest zalogowany i w zależności od tego wyświetlamy
odpowiednie pozycje w menu.
-->
<?php if ($this->session->userdata('user_id')): ?>
<li><a href="<?php echo site_url('users/logout'); ?>">Wyloguj</a></li>
<?php else: ?>
<li <?php echo ($this->uri->rsegment('2') == 'login') ? 'class="active"' : ''; ?>><a href="<?php echo site_url('users/login'); ?>">Logowanie</a></li>
<?php endif; ?>
</ul>
</div><!--/.nav-collapse -->
</div>
</div>
</div>
<div class="container">
<!-- Jeśli istnieją komunikaty o błędach walidacji, wyświetl je. -->
<?php if (validation_errors()): ?>
<?php echo validation_errors(); ?>
<?php endif; ?>
<!-- Jeśli istnieje zmienna flashdata o nazwie 'error' wyświetl ją. -->
<?php if ($this->session->flashdata('error')): ?>
<div class="alert alert-error">
<a class="close" data-dismiss="alert" href="#">×</a>
<?php echo $this->session->flashdata('error'); ?>
</div>
<?php endif; ?>
<!-- Jeśli istnieje zmienna flashdata o nazwie 'success' wyświetl ją. -->
<?php if ($this->session->flashdata('success')): ?>
<div class="alert alert-success">
<a class="close" data-dismiss="alert" href="#">×</a>
<?php echo $this->session->flashdata('success'); ?>
</div>
<?php endif; ?>
Zauważ, że w tym pliku korzystamy m.in. z funkcji base_url i site_url z helpera Url oraz klasy sesji. Plik header.php będzie wczytywany w obrębie całej naszej aplikacji – mamy więc dwa wyjścia: albo będziemy ładować helper Url i klasę sesji w każdym kontrolerze, albo skorzystamy z automatycznego ładowania. W tym wypadku wybierzemy to drugie rozwiązanie, ponieważ jest wygodniejsze. Wystarczy więc, że zmienimy odpowiednie linijki kodu w pliku application/config/autoload.php na następujące: $autoload[’helper’] = array(’url’); oraz $autoload[’libraries’] = array(’database’, 'session’); .
Kod partialu footer.php:
<hr>
<footer>
<p>© 2012 CodeIgniter.org.pl</p>
</footer>
</div> <!-- /container -->
<!-- Le javascript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="assets/js/jquery-1.8.2.min.js"></script>
<script src="assets/js/bootstrap.min.js"></script>
</body>
</html>
Teraz czas na szablon, który wykorzystamy do logowania, czyli plik user_login.php.
<div class="row"> <div class="span4 offset4 well"> <legend>Logowanie</legend> <!-- Otwieramy formularz za pomocą funkcji z helpera Form. --> <?php echo form_open(); ?> <!-- Również do definicji pól formularza możemy użyć funkcji z helpera Form, ale w tym przypadku nie widać specjalnych korzyści dla których musielibyśmy to robić, dlatego zostaniemy przy "normalnym" zapisie. --> <input type="email" id="email" class="span4" name="email" placeholder="Email"> <input type="password" id="password" class="span4" name="password" placeholder="Hasło"> <button type="submit" name="submit" class="btn btn-info btn-block">Zaloguj</button> <!-- Zamykamu formularz. --> <?php echo form_close(); ?> </div> </div>
To by było na tyle. Teraz wystarczy, że przejdziemy na stronę logowania pod adres: http://localhost/blogtutorial/index.php/users/login i zalogujemy się podając dane z poprzedniej części tutorialu (login: admin@admin.dev, hasło: admin). Oczywiście po zalogowaniu CodeIgniter będzie próbował odnaleźć kontroler „Posts” (tak jak sobie tego życzyliśmy), a z racji tego, że jeszcze takowego nie utworzyliśmy, otrzymamy komunikat „404 Page Not Found”. Wystarczy jednak jeszcze raz przejść na stronę logowania aby zobaczyć komunikat o poprawnym zalogowaniu, a w prawym rogu menu zamiast opcji „Logowanie” zobaczymy napis „Wyloguj”. To znak, że logowanie przebiegło pomyślnie.
Kod źródłowy tutorialu jak zawsze jest dostępny na githubie. W następnej części zajmiemy się dodawaniem postów do naszego bloga.
Przydałaby się informacja, że należy utworzyć foldery:
/assets/css,
/assets/js,
a w nich, umieścić odpowiednie pliki bootstrap i jquery.
Teraz na pewno nikt nie przeoczy tej informacji. Ale mam nadzieję, że każdy kto zapozna się z kodem, będzie tego świadomy. Dodatkowo do dyspozycji są zawsze źródła na github.
Na marginesie, skąd wzięła się fotka obok mojego imienia?
Ja jej nie dodawałem, co więcej, nawet się nie rozpoznaję.
Spodziewam się, że gravatar jest włączony z taką opcją.
A tak dla geeka:D to gdzie ma być ten user_login.php w view?
Niestety nie za bardzo rozumiem Twoje pytanie. Mógłbyś sprecyzować?
Np piszesz gdzie wrzucić header i footer, i zgaduje że user_login.php do /views a nie views/partial?
Tak, dokładnie. Jeśli będziesz miał jeszcze inne wątpliwości, to proponuję zajrzeć do pełnych źródeł tutorialu, które są dostępne na github pod adresem: https://github.com/codeigniter-polska/blog-tutorial
Noom okej, przekopiowałem sobie wszystkie kody na serwer lokalny, odpalam i uzyskuję błąd „Aby użyć klasy sesji są zobowiązane do ustawienia klucza szyfrowania w pliku konfiguracyjnym”. Ustawiam klucz na byle jaki ($config[’encryption_key’]) a tu błąd, że nie ma tabeli „ci_sessions”.
Dodam, że to mój pierwszy framework, ciężko się do nich przekonałem i podczas pierwszej próby już jakieś przeszkody…
Musiałeś zmienić ustawienie w pliku config.php:
$config['sess_use_database']musi mieć wartośćFALSEDodatkowo najpierw warto zapoznać się z całkowitymi podstawami, czyli konfiguracją wstępną, która nie jest skomplikowana: CodeIniter bazy danych, sesje i autoloader
parametry bazy mam dobrze ustawione w database.php a on mi mowi ze nie.
active records mam na true
linia 346 w system/core/loader.php wyglada tak: $CI->db =& DB($params, $active_record); czyli zaczytuje parametry bazy i czy ustawiony jest active record. ale nie wiem czemu sie wysypuje takim bledem?
Unable to connect to your database server using the provided settings.
Filename: core/Loader.php
Line Number: 346
Witaj lukass. Przyczyn może być wiele i leżą zapewne po stronie konfiguracji Twojego serwera. Na początek możesz sprawdzić, czy poskutkuje ustawienie zmiennej
$db['default']['pconnect'] = FALSE;. Później proponuję sprawdzić, czy na pewno możesz się połączyć przy podanych danych dostępowych do mysql poza CI, np:mysql_connect('host','user','pass') or die(mysql_error());mysql_select_db('nazwabazydanych') or die(mysql_error());
Ogólnie, z pytaniami zapraszam na forum – tam więcej osób zauważy Twoje pytanie i pomoże rozwiązać problem.
Do walidacji pola e-mail musimy dodać wartość valid_email, ponieważ nie wszystkie przeglądarki obsługują typy pól email w formularzach HTML.
Masz rację, dzięki na zwrócenie uwagi.
Cześć, mam problem i siedze juz nad tym sporo czasu. Robiłem wszystko tak jak ty, oprócz migracji ( zrobilem wszystko w phpmyadmin) wpisuje email i haslo i nic sie nie dzieje, tzn. nie wyskakuje error 404 tak jak powinno tylko po prostu ciagle jestem na stronie logowania. Sprawdzanie poprawnosci wpisanych danych chyba dziala bo jak wpisalem w polu email bez malpy to wyswietlilo nieprawidlowy email, ale jak daje poprawne dane to nic sie nie dzieje nie wiem czemu. Sciągnalem twoj kod na githubie i jest to samo. Poza tym czy nie pomyliles sie z tym : http://localhost/blogtutorial/index.php/users/login , przeciez widok sie nazywa user_login.
Dodam ze w autoload mam database i session oczywiscie
Witaj Michal i dziękuję za komentarz.
Błąd jest po mojej stronie, ponieważ udostępniłem wersję z zakomentowaną funkcją
redirect. Zarówno artykuł jak i repozytorium na github, zostały poprawione.Jeszcze raz dziękuję za zwrócenie uwagi. Jeśli nadal będziesz miał jakieś problemy, to pytaj.
Faktycznie, ten redirect byl zakomentowany ale i tak to nie ma znaczenia w moim przypadku poniewaz to sie odnosilo do niepoprawnego loginu, tzn jezeli login jest nie poprawny do odeslij mnie do strony logowania, okej – tylko ja mam problem ze loguje poprawne dane i nie przechodze dalej czyli w tym przypadku do 'posts’ – redirect(’posts’) – u mnie wlasnie, tam mnie nie chce poprowadzic.
Przesylam ci video gdzie pokazuje problem : http://screencast.com/t/40R7T7CvGGDf
w video jest redirect(users/posts) ale to nie ma znaczenia bo powinien byc blad 404 – nie ma takiej strony prawda ? A nie dzieje sie kompletnie nic.
Przepraszam, że tak późno – powiadomienia nam nawaliły :(
Pewnie już rozwiązałeś problem – w każdym razie chodziło o brak określonego adresu w form_open.
Cześć
mam pewien problem a mianowicie strona logowania w IE 10 ładuje się bez styli CSS, natomiast po zalogowaniu kolejna strona jest już ze stylami?
Macie może jakiś pomysł czym to jest spowodowane?
Znalazłem błąd kodowanie pliku user_login.php miałem ustawione na ANSI.
Gdzie można ustawić widok users/login jako stronę starową? tak aby po wpisaniu adresu http://localhost/blogtutorial/ przechodziło od razu na stronę logowania?
Pozdrawiam
Przepraszam, że tak późno – powiadomienia nam nawaliły :(
Wystarczy zmienić wartość dla 'default_controller’ w pliku 'application/config/routes.php’.
jeszcze można sprawdzić czy uzytkownik zalogowany i jak nie to przeniesc go na stronę logowania
[code]session->userdata(’user_id’)):
redirect(’strona-logowania’,’refresh’);
?>[/code]
Witam! Mam pytanie odnośnie logowania. Co trzeba byłoby zrobić aby mogła się zalogować większa liczba osób np na takiego bloga? Dodałem użytkownika do bazy danych, ale jakoś nie chce mi się zalogować na dane nowego użytkownika. Co zrobić?
Pozdrawiam, Sebastian
Już sobie jakoś poradziłem.
Witam. Mam następujący problem, zrobiłem wszystko tak jak trzeba, ale niestety sesje mi się nie zapisują. I co dziwne inne sesje które stworzyłem działają, tylko te znajdujące się w plikach logowania nie. Bardzo proszę o pomoc.
Witaj. Hmm… co masz na myśli pisząc o innych sesjach?
Możesz dokładnie opisać, co się dzieje i który element nie działa (co się nie zapisuje, a powinno)?
Sesje zapisują się w bazie danych, ale nie działają, w sensie nie wyświetla warunków, wyloguj, logowanie przebiegło itd. Pomimo, że w bazie w sesjach są zapisane. Chodzi głównie o to logowanie z poradnika.
Wykonałeś kawał roboty, ale ten „tutorial” praktycznie nic nie wnosi, praktycznie nic tu nie jest omówione, tylko kod do wklepania.
Dzięki za opinię.
Dla mnie osobiście, tutorial powinien przede wszystkim zawierać kod i jego omówienie – to właśnie można tutaj znaleźć (czyli co się dzieje w każdej linijce). Omówienie poszczególnych bibliotek jest dostępne w podręczniku, więc bez sensu tutaj powielać to samo. Wychodzę z założenia, że po przejrzeniu podręcznika niekoniecznie wszyscy muszą wiedzieć jak to wszystko „poskładać do kupy”, więc ten tutorial ma za zadanie własnie to pokazać. Tylko tyle.
Jeśli masz jakieś konkretne uwagi, czego wg Ciebie tutaj zabrakło – chętnie posłucham.
Pozdrawiam.