iT邦幫忙

DAY 22
4

網站系統規劃實務系列 第 22

網站系統規劃 - 發文系統實作(登入篇)

本篇文章作為網站實戰開發的第八篇,我們繼續實作登入狀態。

--------系列簡介--------

網站系統可說是現在最多學子與新人想要入門的一個領域,
這個原本屬於新興的領域,這幾年來也累積許多年的知識與 pattern ,
在有限的環境(stateless)與有限的伺服器端、瀏覽器資源下,
成為許多人進入程式的一塊入門鐵板(?)。

這個系列希望能夠就網站系統設計幾個門檻著手,
這是設定給初心者作為學習,給同好們作為回顧,

重新認識有關網站系統的每個環節。
OK

在昨天我們討論到切分 view 跟畫面的細節,今天我們要接著實作接下來的部份。

首先是登入,一樣照慣例是建好 Login View

application/views/login.php

<?php include("_site_header.php"); ?>
<div class="container">
	<?php include("_content_nav.php") ?> 
	<div class="content">
		<form action="<?=site_url("user/logining")?>" method="post" > 
			<?php if(isset($errorMessage)){ ?>

			<div class="alert alert-error"><?=$errorMessage?></div>

			<?php } ?>
			<table>
				<tr>
					<td>帳號</td>
					<?php if(isset($account)){ ?>
						<td><input type="text" name="account" 
							value="<?=htmlspecialchars($account)?>" /></td>
					<?php }else{ ?>
						<td><input type="text" name="account" /></td>
					<?php } ?>
				</tr>
				<tr>
					<td> 密碼 </td>
					<td><input type="password" name="password" /></td>
				</tr>
				<tr>
					<td colspan="2"> 
						<a href="<?=site_url("/")?>">取消</a>
						<input type="submit" class="btn" value="送出" />
					</td>
				</tr>
			</table>
		</form>
	</div>
</div>

接著實作 controller 的細節

application/controllers/user.php

	public function login(){
		session_start();
		if(isset($_SESSION["user"]) && $_SESSION["user"] != null){ //已經登入的話直接回首頁
			redirect(site_url("/")); //轉回首頁
			return true;
		}

		$this->load->view(
			"login",
			Array( "pageTitle" => "發文系統 - 會員登入"	)
		);
	}
	public function logining(){
		session_start();
		if(isset($_SESSION["user"]) && $_SESSION["user"] != null){ //已經登入的話直接回首頁
			redirect(site_url("/")); //轉回首頁
			return true;
		}

		$account = trim($this->input->post("account"));
		$password = trim($this->input->post("password"));

		$this->load->model("UserModel");
		$user = $this->UserModel->getUser($account,$password);

		if($user == null){
			$this->load->view(
				"login",
				Array( "pageTitle" => "發文系統 - 會員登入"	,
					"account" => $account,
					"errorMessage" => "使用者或密碼錯誤"
				)
			);		
			return true;
		}

		$_SESSION["user"] = $user;
		redirect(site_url("/")); //轉回首頁
	}

	public function logout(){
		session_start();
		session_destroy();
		redirect(site_url("/user/login")); //轉回登入頁
	}

詳細完整原始碼請見:https://gist.github.com/3893200


大家可以看得出來都是一些邏輯與狀態的紀錄,
相信在我們之前介紹的內容後,讀者應該可以餘刃有餘的閱讀這些程式碼。

接著我們要繼續實作還沒實作完的 model ,從資料庫查詢這個帳號密碼是否存在。
(注意,這裡我們是用明碼實作密碼,正式環境中請記得透過 SHA1或 MD5 加密。)

application/models/usermodel.php

public function getUser($account,$password){
    $this->db->select("*");
    $query = $this->db->get_where("user",Array("account" => $account, "password" => $password ));

    if ($query->num_rows() > 0){ //如果數量大於0
        return $query->row();  //回傳第一筆
    }else{
        return null;
    }
}

詳細原始碼請見https://gist.github.com/3893198


最後則是修改一下,全站狀態登入狀態的判斷:

application/views/_content_nav.php

<!-- Content Header -->
<div class="content-header">
	<div class="navbar navbar-inverse">
	  <div class="navbar-inner">
	    <a class="brand" href="<?=site_url("/")?>">The Articles</a>
	    <ul class="nav">
	      <li class="active"><a href="#">Home</a></li>
	      <li><a href="#">My Articles</a></li>
	    </ul>
	    <!-- login status -->
	    <?php if(isset($_SESSION["user"]) && $_SESSION["user"] != null){ ?>
		<ul class="nav pull-right">
          <li><a href="#">Hi <?=$_SESSION["user"]->Account?></a></li>
          <li class="divider-vertical"></li>
          <li><a href="<?=site_url("user/logout")?>">登出</a></li>
        </ul>
        <?php }else{ ?> 
		<ul class="nav pull-right">
          <li><a href="<?=site_url("user/login")?>">登入</a></li>
          <li class="divider-vertical"></li>
          <li><a href="<?=site_url("user/register")?>">註冊</a></li>
        </ul>        
        <?php } ?>
	  </div>
	</div>
</div>

因為我們使用了 session 作為判斷,所以每一個需要用到他的 controller ,
都需要 call session_start() ,這樣實在是有一點沒效率,對吧? ;)

在 CI 裡面有很簡單的方式,可以透過 controller 一致性的進行共同性的動作,
如 session_start 之類的操作。

今天我們很簡單的實作了基本的登入狀態實作,接下來明天我們將繼續實作發文細節,
如果有餘裕的話,我們會再來加以說明怎麼做加密的密碼儲存與驗證。:)

那麼,明天見囉。


上一篇
網站系統規劃 - 很多重複的程式碼?談網頁內容重用、模組化。
下一篇
網站系統開發 - 發文系統實作(發文篇)
系列文
網站系統規劃實務27
1
tony1223
iT邦新手 2 級 ‧ 2012-10-16 00:04:37

補充一下如何避免逐一 function 撰寫 session_start() ,

在 CI 裡面有很簡單的方式,可以讓 controller 一致性的,
進行如 session_start 之類的操作。

這裡的作法相當單純,我們只要讓 CI Controller 繼承一個我們自己定義的父類別,
並且在 CI controlelr 設定為繼承,並且在該類別建構時預先做好我們希望他做的事情即可。

這個類別比較特別,是要放在 application/core 裡面,作法如下:

1.建立 MY_Controller 檔案
application/core/MY_Controller.php

內容為

&lt;pre class="c" name="code">
&lt;?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
&lt;?php
class  MY_Controller  extends  CI_Controller  {
	public function __construct(){
		parent::__construct();
		$this->_init();
	}
	protected function _init(){
		session_start();
	}
}

2.設定各Controller 從 extend CI_Controller 成為 MY_Controller。


class User extends CI_Controller
改為
class User extends MY_Controller

然後移除相關已存在 controller method 的 session_start() ,這樣就可以囉,
而且這個父類別也可以用來定義一些有用的共用元素,像是取得 user IP 之類的共同操作。

tony1223 iT邦新手 2 級 ‧ 2012-10-16 00:06:55 檢舉

另外可能有人會提到 CI 內建有他自己的 session 實作,
不過內建的 session 實作比較複雜,而且需要設定 secret key 。

筆者自己是也不常用他,加上我們之前已經介紹過 php 的 SESSION 機制,
所以就直接用 php 內建的 SESSION 機制進行介紹囉。;)

tony1223 iT邦新手 2 級 ‧ 2012-10-16 00:07:18 檢舉
1
老鷹(eagle)
iT邦高手 1 級 ‧ 2012-10-16 08:28:17

以下內容是俺跟某前輩對話整理~~!汗
CI的session理論上是session 但是ci是用cookie
$this->session->userdata();
這東東雖然是掛名session實際上是cookie

至於說ci能不能用「正港」的session
兩種方式
一種就是你用傳統的session寫法就好了
另一個是寫外掛
http://www.codeigniter.org.tw/user\_guide/libraries/sessions.html
你仔細看他第一行的說明

tony1223 iT邦新手 2 級 ‧ 2012-10-16 11:16:42 檢舉

CI 允許你切換為 db session 實作啊 :P
ex. sess_use_database

基本上 session 這個主題本身就很值得一談了,特別是扯到 clustering 分散式結構時,
memory session 通常會有問題而會需要採取 db session 或 cookie session 的狀況。

不過一般而言 cookie session 因為 cookie 長度有上限,所以使用上有所侷限,
另一方面是安全性也有顧慮,所以不會拿來放太重要的東西;

就算要放,也會放一定時間內就會過期的資訊。

tony1223提到:
session 這個主題本身就很值得一談了,特別是扯到 clustering 分散式結構時,
memory session 通常會有問題

俺前輩是寫外掛去使用讚
俺因為是存不重要的東西所以用CI的就好了~~!睡覺

0
HzChris
iT邦新手 5 級 ‧ 2013-08-02 00:56:40

全站狀態登入狀態的判斷那邊

不需要session_start()嗎?

如果是在某些controller沒預先載入session_start()的頁面,

是不是isset($_SESSION["user"]) 就會一直是true了?

piece601 iT邦新手 5 級 ‧ 2013-09-12 21:53:01 檢舉

welcome那一頁不是user這個Controller

所以唯獨這一頁 要在welcome_message.php加上 <? session_start() ?>

0
jack1234552000
iT邦新手 5 級 ‧ 2018-12-29 16:18:20

前一篇文章底下
作者有延伸補充MY_controller加上session_start的用法

但是你會發現即使這麼加
有登入帳號 首頁上方的nav_bar呈現的畫面還是不對
這個問題是welcome_message並沒有session_start
因為它並不屬於任何controller底下控制的頁面(?

詳細參考樓上@piece601的留言
我也是找好久 才看到他的留言

0
a8566012
iT邦新手 5 級 ‧ 2020-09-09 16:27:08

老師您好,近期因為課業需要在瀏覽這篇系列文,但是到這個登入篇就失敗了
我有照您補充說明 增加MY_Controller這個檔案也有刪除user.php裡面的session_start()和@piece601老師補充的要在welcome_message.php增加session_start()
但是全站登入判斷的狀態條依然是登入和註冊,註冊成功和登入後並沒有轉換成登出和發文
如圖上,這是登入後跳回主頁的畫面
Imgur
想請教老師 具體應該刪除user.php哪個方法的session_start()跟在welcome_message.php哪裡增加session_start()/images/emoticon/emoticon02.gif
謝謝老師!

我要留言

立即登入留言