天天看點

Laravel 開發筆記

Laravel 4.2  鑒權使用加鹽密碼

剛開始接觸laravel,發現laravel預設的鑒權子產品密碼并未加鹽處理(密碼由password_hash方法建立)。是以自己琢磨着對密碼加鹽。像下面這樣校驗密碼(密碼在最初建立時,也以md5(salt . password .salt)的形式存儲)

1 Auth::attempt(array('username'=>$user->username, 'password'=>$user->salt.Input::get('password').$user->salt))      

但一直不成功,debug跟蹤源碼,可以看到最後,EloquentUserProvider的validateCredentials方法進一步調用BcryptHasher的check方法,,再進一步調用vendor/ircmaxell/password-compat/lib/password.php:230 password_verify方法,而不是我起初所想的直接$user->password == md5('input_password')。是以我在這裡直接改寫了源碼,以此來實作密碼加鹽

Laravel 開發筆記

Laravel 4.2  響應存在多餘的空行

在任意響應中多四個空行,這個問題在4.2版本中遇到,并且在配置了auth過濾器的請求中才有

Laravel 開發筆記

這個問題在下載下傳請求時會有問題,比如壓縮檔案。在下載下傳zip檔案時,如果響應前步多幾個空行,會造成檔案起始多幾個位元組,造成這樣的錯誤

warning [zip]: 8 extra bytes at beginning or within zipfile  。 因為代碼檔案裡是windows 換行符 CRLF,是以四個空行是八個字元,是以響應頭部多了八個位元組

Laravel 開發筆記

或者提示 該檔案已損壞或者需要另一個壓縮分卷

Laravel 5.3 清除用戶端cookie

有時需要服務端來清除cookie,以保證所有httponly屬性的cookie也能被清除。laravel已經提供API來生成清除cookie的http頭

Laravel 開發筆記
Laravel 開發筆記

Laravel 5.3 實作controller路由

laravel 5.3中移出了controller路由,隻保留了resources路由,這對開發規範的項目而言是好事,而對開發不規範的項目簡直是災難,開發不得不用get或者post路由為每一個控制器的方法注冊路由,這會造成路由檔案routes.php(routes/web.php)檔案巨大不好維護。個人比較喜歡按約定來,是以寫了個函數簡單實作controller路由(約定namespace/controller/method)格式,如Home/XxYyController@getMmGg 将映射到 url : home/xx-yy/mm-gg,并且是get請求

1 /**
 2  * 駝峰字元串轉蛇形字元串
 3  * @param $str
 4  * @param string $delimiter
 5  * @return string
 6  */
 7 function humpToSnake($str,$delimiter = '_'){
 8     if ( ! ctype_lower($str))
 9     {
10         $replace = '$1'.$delimiter.'$2';
11         $str = strtolower(preg_replace('/([A-Za-z])([A-Z])/', $replace, $str));
12     }
13     return $str;
14 }
15 
16 
17 /**
18  * 基于controller約定路由
19  * 例如:  $namespace = 'H5'
20  * GET :  XxYyController@getMmGg   ->    url : h5/xx-yy/mm-gg
21  * POST : XxYyController@postMmGg    ->  url :   h5/xx-yy/mm-gg
22  * @param string $controller 控制器類名
23  * @param bool $namespace  相對于App\Http\Controllers的命名空間
24  */
25 function routeController($controller,$namespace = false){
26     if (preg_match('/([\w]+)Controller$/', $controller, $matches))
27     {
28         $className = humpToSnake($matches[1],'-');
29         $methods = get_class_methods('App\Http\Controllers\\'.($namespace ? $namespace.'\\' : '').$controller);
30         foreach($methods as $method){
31             if(strpos($method,'get') === 0){
32                 // 注冊get路由
33                 $methodName = humpToSnake(lcfirst(substr($method,3)),'-');
34                 Route::get($className.'/'.$methodName,$controller.'@'.$method);
35             } else if(strpos($method,'post') === 0){
36                 // 注冊post路由
37                 $methodName = humpToSnake(lcfirst(substr($method,4)),'-');
38                 Route::post($className.'/'.$methodName,$controller.'@'.$method);
39             }
40         }
41     }
42 }      

在php項目中獨立使用Eloquent ORM架構

laravel使用的eloquent orm架構極其強大,大部分資料庫層面的操作都能夠在不寫任何sql的情況下實作查詢。是以在寫其餘項目時,比如爬蟲,也想将此orm內建進來

eloquent 是一個獨立的項目 https://github.com/illuminate/database,是以完全可以單獨拿出來用

通過composer在項目中安裝依賴

1 composer require illuminate/database:~4.2       

将eloquent初始化的代碼獨立于一個php檔案(start.php)中

1 <?php
 2 /**
 3  * Created by PhpStorm.
 4  * User: lvyahui
 5  * Date: 2016/3/17
 6  * Time: 17:23
 7  */
 8 require_once __DIR__ . '/vendor/autoload.php';
 9 require_once 'config.php';
10 
11 $localDBConf = config('db.local');
12 
13 $database = array(
14     'driver'    => 'mysql',
15     'host'      => $localDBConf['host'],
16     'port'      => $localDBConf['port'],
17     'database'  => $localDBConf['name'],
18     'username'  => $localDBConf['user'],
19     'password'  => $localDBConf['pass'],
20     'charset'   => 'utf8',
21     'collation' => 'utf8_unicode_ci',
22 );
23 
24 //use  Illuminate\Container\Container;
25 use Illuminate\Database\Capsule\Manager as Capsule;
26 
27 $capsule = new Capsule();
28 
29 /*建立連接配接*/
30 $capsule->addConnection($database);
31 /*設定全局通路*/
32 $capsule->setAsGlobal();
33 /*啟動Eloquent*/
34 $capsule->bootEloquent();      

定義資料庫模型 BaseModel.php

1 <?php
 2 use Illuminate\Database\Eloquent\Model as Eloquent;
 3 /**
 4  * Created by PhpStorm.
 5  * User: samlv
 6  * Date: 2016/3/17
 7  * Time: 17:30
 8  */
 9 class BaseModel extends Eloquent
10 {
11     protected $guarded = array('id');
12     public $timestamps = false;
13 }      

ApkClass.php

1 <?php
 2 require_once ('BaseModel.php');
 3 /**
 4  * Created by PhpStorm.
 5  * User: lvyahui
 6  * Date: 2016/3/31
 7  * Time: 16:35
 8  */
 9 class ApkClass extends BaseModel
10 {
11     protected $table = 'apk_class';
12 }      

在需要進行資料庫操作中引入初始化檔案和模型檔案即可以使用

1 <?php
 2 /**
 3  * Created by PhpStorm.
 4  * User: lvyahui
 5  * Date: 2016/3/31
 6  * Time: 17:00
 7  * 掃描tmp/zip目錄,解壓左右的zip包,讓後進行處理。
 8  */
 9 require_once ('start.php');
10 require_once ('models/ApkClass.php');
11 
12 foreach($usedApkClasss as $map_id=>$num){
13     ApkClass::where('map_id',$map_id)->update(array('num' => $num));
14 }      

Laravel 基于約定進行子視圖填充

laravel 另一個強大之處是其模闆引擎,開發中常用的有兩種,視圖繼承和子視圖填充。這裡以子視圖填充為例,按約定的方式簡化代碼的編寫

基礎控制器

1 <?php
  2 
  3 use Illuminate\Support\Facades\View;
  4 use Illuminate\Support\Facades\Redirect;
  5 use Illuminate\Support\Facades\Input;
  6 class BaseController extends Controller
  7 {
  8 
  9     protected $layout = 'layouts.site';
 10 
 11     protected $stdName = null;
 12 
 13     protected $routeParams = false;
 14     /**
 15      * Setup the layout used by the controller.
 16      *
 17      * @return void
 18      */
 19     protected function setupLayout()
 20     {
 21         if ( ! is_null($this->layout))
 22         {
 23             $this->layout = View::make($this->layout);
 24         }
 25     }
 26 
 27     public function __construct()
 28     {
 29 
 30     }
 31 
 32     /**
 33      * 擷取控制器名稱
 34      * 例如:
 35      * 類:admin/DataSourceController
 36      * 将傳回
 37      * dataSource
 38      * @return null|string
 39      */
 40     public function getStdName()
 41     {
 42         if(!$this->stdName){
 43             $className = get_class($this);
 44             if (preg_match('/([\w]+)Controller$/', $className, $matches))
 45             {
 46 //                $this->stdName =  camel_case($matches[1]);
 47                 $this->stdName = lcfirst($matches[1]);
 48             }
 49             else
 50             {
 51                 $this->stdName = $className;
 52             }
 53         }
 54         return $this->stdName;
 55     }
 56 
 57 
 58     public function makeView($data = array(),$view = null){
 59         if(!$view){
 60             $routeParams = $this->getRouteParams();
 61             $controllerName = $routeParams['c'];
 62             $methodName = $routeParams['m'];
 63             if(preg_match('/^get(.*)$/',$methodName,$matches)){
 64                 $methodName = StringUtils::humpToSnake($matches[1]);
 65             }
 66             $view = $controllerName.'.'.$methodName;
 67         }
 68         if(!is_array($data)){
 69             $data = array();
 70         }
 71         if(Request::ajax()){
 72             return View::make($view,$data);
 73         }else{
 74             $this->layout->nest('content',$view,$data);
 75             return false;
 76         }
 77     }
 78 
 79     /**
 80      *
 81      * @return array|bool
 82      */
 83     public function getRouteParams(){
 84         if(!$this->routeParams){
 85 
 86             list($class,$method) = explode('@',Route::current()->getActionName());
 87             $class = str_replace("\\",".",substr($class,0,strrpos($class,'Controller')));
 88 //            $names = explode(".",$class);
 89 //            foreach ($names as & $name) {
 90 //                $name = snake_case($name);
 91 //            }
 92             $class = StringUtils::humpToSnake($class);
 93 //            $class = implode('.',$names);
 94 
 95             $this->routeParams = array(
 96                 'c'    =>  $class,
 97                 'm'        =>  $method
 98             );
 99         }
100 
101         return $this->routeParams;
102     }
103 
104     public function getRouteParam($key){
105         $routePatams = $this->getRouteParams();
106         return $routePatams[$key];
107     }
108 
109 }      

控制器方法中隻需要return makeView()方法即可,makeView方法會确定視圖檔案位置。

<?php

class UserController extends BaseController
{
    public function getList(){
        return $this->makeView(array('users'=>array()));
    }
}      

主視圖(site.blade.php)寫法

1 <!DOCTYPE html>
 2 <html lang="zh-CN">
 3 <head>
 4     @include('layouts.head')
 5     <!-- 頁面級别css -->
 6     @yield('page.level.css','')
 7 </head>
 8 <body>
 9 @include('layouts.header')
10 <div class="container-fluid">
11     {{$content}}
12 </div>
13 @include('layouts.footer')
14 <!-- 頁面級别js檔案 -->
15 @yield('page.level.js','')
16 <!-- 頁面級别js代碼片段 -->
17 @yield('page.level.script','')
18 </body>
19 </html>      

上面幾份代碼實作這樣的約定是:UserController@getList方法渲染views/user/list.blade.php頁面,并将其填充到view/layouts/site.blade.php視圖中,也就是我認為整個站點主視圖(布局,layouts/site.blade.php)基本一緻,所有方法産生的内容直接填充主視圖即可,那以後開發新的頁面或者接口,隻需要按改約定開發即可