<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                # 會話控制 在現代 Web 程序中,常見的 `HTTP 會話機制` 有多種: * JWT (JSON Web Token): https://jwt.io/ * Session * Cookie * ... 在本章的學習中,我們采用 `session` 來控制會話. ## 會話控制器 在控制器中鍵入 `php think make:controller user/Session` 創建會話控制器并編輯, `application\user\controller\Session.php`: ~~~~ php use app\user\model\User; ... public function create() { $token = $this->request->token('__token__', 'sha1'); $this->assign('token', $token); return $this->fetch(); } ~~~~ `route\route.php`: ~~~~ php Route::resource('session', 'user/session'); ~~~~ 創建模板 `resources\views\user\session\create.blade.php`: ~~~~ html @extends('_layout.default') @section('title', '登入') @section('content') <div class="col-md-offset-2 col-md-8"> <div class="panel panel-default mt-5"> <div class="panel-heading mb-3"> <h4>登入</h4> </div> @if(session('validate')) <div class="alert alert-warning" role="alert"> {{ session('validate') }} </div> @endif <div class="panel-body"> <form method="POST" action="{{ url('save') }}"> <input type="hidden" name="__token__" value="{{ $token }}" /> <div class="input-group mb-3"> <div class="input-group-prepend"> <span class="input-group-text">郵箱</span> </div> <input type="email" class="form-control" name="email"> </div> <div class="input-group mb-3"> <div class="input-group-prepend"> <span class="input-group-text">密碼</span> </div> <input type="password" class="form-control" name="password"> </div> <button type="submit" class="btn btn-primary btn-block">登入</button> </form> </div> </div> </div> @stop ~~~~ 以上創建的內容與上一張所建內容大多類似,不再詳細說明. 現在訪問 `http://thinkphp.test/user/session/create` 即可看到登錄頁面. 同樣的,我們創建驗證器,在控制臺中鍵入 `php think make:validate user/Session` 并打開創建好的 `application\user\validate\Session.php`: ~~~~ php protected $rule = [ '__token__' => 'token', 'email|郵件' => 'require|email|max:255', 'password|密碼' => 'require|min:6' ]; ~~~~ 再打開 `application\user\controller\Session.php`: ~~~~ php public function save(Request $request) { $result = $this->validate($request->post(), 'app\user\validate\Session'); if (true !== $result) { return redirect('user/session/create')->with('validate',$result); } else { $user = User::where('email', $request->email)->find(); if ($user !== null && password_verify($request->password, $user->password)) { return 'Password is valid!'; } else { return 'Invalid password.'; } } } ~~~~ 在以上 `save` 方法中, `password_verify($request->password, $user->password)` 對應著上一章所用的 `password_hash` 方法,目的是驗證 `hash` 之后的數據, `password_verify(請求數據, 待驗證的數據)`,如果驗證成功則拋出 `true`: http://php.net/manual/zh/function.password-verify.php 請注意,在 PHP 中判斷 `null`: 標識 | empty == null | is_null === null | isset | array_key_exists ---- | ---- | ---- | ---- | ---- ? | T | T | F | F null | T | T | F | T "" | T | F | T | T [] | T | F | T | T 0 | T | F | T | T false | T | F | T | T true | F | F | T | T 1 | F | F | T | T \0 | F | F | T | T * `$user != null` == 在 PHP 運算符中不檢查類型 * `$user !== null` === 在 PHP 運算符中檢查類型 意味著如果使用 `==`,PHP 將會轉換成一致的類型再做判斷,這也是動態弱類型語言的一大弱勢,如果無法提前知曉接收的值的類型,也沒有類型檢查,解釋器所轉換的類型將不可控制. 在要求高精度的程序中(例如財務系統),請使用靜態強類型語言,在弱類型語言當中,一些高精度的浮點數將會丟失(int to double),例如 `0.9999999999999^2`,甚至也有 `'0.999999999999' * 0.999999999999` 下面是一些例子: * 無類型: 匯編 * 弱類型、靜態類型 : C/C++ * 弱類型、動態類型檢查: Perl/PHP * 強類型、靜態類型檢查 :Java/C# * 強類型、動態類型檢查 :Python, Scheme * 靜態顯式類型 :Java/C * 靜態隱式類型 :Ocaml, Haskell * ... 筆者注: 我經常遇到一些朋友想使用 PHP 來做通訊系統,爬蟲系統甚至 GUI 程序,做一個一款語言就能集大成的程序,這是非常不可取的,軟件行業沒有銀彈(Silver Bullet),沒有任何一款語言能做完所有的事情,也沒有任何一款語言能夠讓你掌握了就吃到老,對陣下藥,不要宰牛用殺豬刀. 重新看到 `application\user\controller\Session.php` 并修改: ~~~~ php if ($user !== null && password_verify($request->password, $user->password)) { return redirect('user/auth/read')->params(['id' => $user->id]); } else { return redirect('user/session/create')->with('validate','郵件地址不存在或密碼錯誤'); } ~~~~ 現在如果驗證成功,那么就會跳轉到上一章所編寫的 `user/auth/read` 方法. 雖然現在已經成功驗證賬戶對應的密碼,但是還未做到權限的狀態管理,用戶不管登錄是否,都可以 `http://thinkphp.instudy.test/user/auth/read/id/:id` 的地址. ## 中間件攔截 中間件相當于在 `路由至控制器` 之間修建一道門,如果通過中間件的規則則可以進行下一步的操作,我們現在通過中間件來驗證 `是否已經登入`: http://www.hmoore.net/manual/thinkphp5_1/564279 經過筆者兩小時的測試,ThinkPHP 的中間件與路由有非常大的邏輯缺陷問題,中間件無法正確掛載至資源路由,資源路由生成規則錯誤及混亂,URL 綁定在資源路由中不起作用,以下是一些針對這一章節 ThinkPHP 框架的錯誤: * 框架版本: V5.1.28 LTS(2018-10-28) * PHP 版本: PHP 7.2.11-4+ubuntu18.04.1+deb.sury.org+1 (cli) (built: Nov 4 2018 05:11:49) ( NTS ) 定義中間件: ~~~~ php public function handle($request, \Closure $next) { $request->mid = 'mid'; return $next($request); } ~~~~ 如果中間件不在路由注冊: ~~~~ php Route::resource('auth', 'user/auth') ~->middleware('Auth')~ ~~~~ 那么在控制器不管怎么定義了中間件, dump 都是 null ~~~~ php protected $middleware = [ 'Auth', ]; ~~~~ 訪問地址: `http://thinkphp.test/user/auth/create.html` 或者 `http://thinkphp.test/auth/create.html` 都會提示: `/home/vagrant/code/instudy/thinkphp/thinkphp/library/think/Debug.php:226:null` 而如果在路由中進行注冊中間件: ~~~~ php Route::resource('auth', 'user/auth')->middleware('Auth') ~~~~ 基于完整的控制器路徑 `http://thinkphp.test/user/auth/create.html` 仍然輸出 `null` 而進入綁定之后的地址 `http://thinkphp.test/auth/create.html` 卻有值 `mid` 更加神奇的是,如果要使用 URL 生成路由 `url('user/auth/create')`,只會生成到 完整的控制器路徑(http://thinkphp.test/user/auth/create.html),而不會生成綁定的地址(http://thinkphp.test/auth/create.html) 如果你要強行用綁定的地址,只能寫死路徑 `return redirect('/auth/read')->params(['id' => $user->id]);` 當寫死路徑之后,`params()` 方法將不會傳值到 `auth/read/:id`,只會跳轉到 `/auth/read` 關于路由的錯誤,在前面的章節已經遇到并且不得已才琢磨出了匹配完整路徑的方法,可惜 URL 生成:http://www.hmoore.net/manual/thinkphp5_1/353977 根本不工作,導致了路由中間件掛載無效. 同時,無論怎么樣在資源控制器中掛載中間件,都是無效的,不執行任何東西. 基于以上的問題,我們不再采用中間件的方式進行會話攔截. ## 手動攔截 此方法比較繁瑣,代碼復用程度極差,是一個臨時解決中間件問題的辦法. `application\user\controller\Session.php`: ~~~~ php use think\facade\Session as SessionFacade; ... if ($user !== null && password_verify($request->password, $user->password)) { SessionFacade::set('user', $user); return redirect('user/auth/read')->params(['id' => $user->id]); } ~~~~ 可以看到,我們在頂部引入了 Session 的庫,再引入之后,類就會默認掛載 `class Session`,可是這與我們當前 `Session` 的命名出現了沖突,所以使用 `as SessionFacade` 來為 `Session 外部類` 增加別名. 現在重新進行登錄操作,就會重定向至 `'user/auth/read/:id'` 并且附帶一個 `user` 的 `session`. 現在我們打開 `application\user\controller\Auth.php`: ~~~~ php use think\facade\Session; ... public function read($id) { if (Session::has('user')) { $user = User::find($id); $this->assign('user', $user); return $this->fetch(); } else { return redirect('user/session/create')->with('validate','請先登錄'); } } ~~~~ `Session::has(param)` 是判斷 `param` 的 `session` 值是否存在,現在訪問 `http://thinkphp.instudy.test/user/auth/read/id/1.html` 則會跳轉至登錄頁面.
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看