Laravel 4.2 鑒權(quán)使用加鹽密碼
剛開始接觸laravel,發(fā)現(xiàn)laravel默認(rèn)的鑒權(quán)模塊密碼并未加鹽處理(密碼由password_hash方法創(chuàng)建)。所以自己琢磨著對(duì)密碼加鹽。像下面這樣校驗(yàn)密碼(密碼在最初創(chuàng)建時(shí),也以md5(salt . password .salt)的形式存儲(chǔ))
1 Auth::attempt(array('username'=>$user->username, 'password'=>$user->salt.Input::get('password').$user->salt))
但一直不成功,debug跟蹤源碼,可以看到最后,EloquentUserProvider的validateCredentials方法進(jìn)一步調(diào)用BcryptHasher的check方法,,再進(jìn)一步調(diào)用vendor/ircmaxell/password-compat/lib/password.php:230 password_verify方法,而不是我起初所想的直接$user->password == md5('input_password')。因此我在這里直接改寫了源碼,以此來實(shí)現(xiàn)密碼加鹽
Laravel 4.2 響應(yīng)存在多余的空行
在任意響應(yīng)中多四個(gè)空行,這個(gè)問題在4.2版本中遇到,并且在配置了auth過濾器的請(qǐng)求中才有
這個(gè)問題在下載請(qǐng)求時(shí)會(huì)有問題,比如壓縮文件。在下載zip文件時(shí),如果響應(yīng)前步多幾個(gè)空行,會(huì)造成文件起始多幾個(gè)字節(jié),造成這樣的錯(cuò)誤
warning [zip]: 8 extra bytes at beginning or within zipfile 。 因?yàn)榇a文件里是windows 換行符 CRLF,所以四個(gè)空行是八個(gè)字符,所以響應(yīng)頭部多了八個(gè)字節(jié)
或者提示 該文件已損壞或者需要另一個(gè)壓縮分卷
Laravel 5.3 清除客戶端cookie
有時(shí)需要服務(wù)端來清除cookie,以保證所有httponly屬性的cookie也能被清除。laravel已經(jīng)提供API來生成清除cookie的http頭
Laravel 5.3 實(shí)現(xiàn)controller路由
laravel 5.3中移出了controller路由,只保留了resources路由,這對(duì)開發(fā)規(guī)范的項(xiàng)目而言是好事,而對(duì)開發(fā)不規(guī)范的項(xiàng)目簡(jiǎn)直是災(zāi)難,開發(fā)不得不用get或者post路由為每一個(gè)控制器的方法注冊(cè)路由,這會(huì)造成路由文件routes.php(routes/web.php)文件巨大不好維護(hù)。個(gè)人比較喜歡按約定來,所以寫了個(gè)函數(shù)簡(jiǎn)單實(shí)現(xiàn)controller路由(約定namespace/controller/method)格式,如Home/XxYyController@getMmGg 將映射到 url : home/xx-yy/mm-gg,并且是get請(qǐng)求
1 /** 2 * 駝峰字符串轉(zhuǎn)蛇形字符串 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-gg21 * POST : XxYyController@postMmGg -> url : h5/xx-yy/mm-gg22 * @param string $controller 控制器類名23 * @param bool $namespace 相對(duì)于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 // 注冊(cè)get路由33 $methodName = humpToSnake(lcfirst(substr($method,3)),'-');34 Route::get($className.'/'.$methodName,$controller.'@'.$method);35 } else if(strpos($method,'post') === 0){36 // 注冊(cè)post路由37 $methodName = humpToSnake(lcfirst(substr($method,4)),'-');38 Route::post($className.'/'.$methodName,$controller.'@'.$method);39 }40 }41 }42 }
在php項(xiàng)目中獨(dú)立使用Eloquent ORM框架
laravel使用的eloquent orm框架極其強(qiáng)大,大部分?jǐn)?shù)據(jù)庫層面的操作都能夠在不寫任何sql的情況下實(shí)現(xiàn)查詢。所以在寫其余項(xiàng)目時(shí),比如爬蟲,也想將此orm集成進(jìn)來
eloquent 是一個(gè)獨(dú)立的項(xiàng)目 https://github.com/illuminate/database,所以完全可以單獨(dú)拿出來用
通過composer在項(xiàng)目中安裝依賴
1 composer require illuminate/database:~4.2
將eloquent初始化的代碼獨(dú)立于一個(gè)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 /*創(chuàng)建連接*/30 $capsule->addConnection($database);31 /*設(shè)置全局訪問*/32 $capsule->setAsGlobal();33 /*啟動(dòng)Eloquent*/34 $capsule->bootEloquent();
定義數(shù)據(jù)庫模型 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 Eloquent10 {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 BaseModel10 {11 protected $table = 'apk_class';12 }
在需要進(jìn)行數(shù)據(jù)庫操作中引入初始化文件和模型文件即可以使用
1 <?php 2 /** 3 * Created by PhpStorm. 4 * User: lvyahui 5 * Date: 2016/3/31 6 * Time: 17:00 7 * 掃描tmp/zip目錄,解壓左右的zip包,讓后進(jìn)行處理。 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 基于約定進(jìn)行子視圖填充
laravel 另一個(gè)強(qiáng)大之處是其模板引擎,開發(fā)中常用的有兩種,視圖繼承和子視圖填充。這里以子視圖填充為例,按約定的方式簡(jiǎn)化代碼的編寫
基礎(chǔ)控制器
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方法會(huì)確定視圖文件位置。
<?phpclass 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 <!-- 頁面級(jí)別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 <!-- 頁面級(jí)別js文件 -->15 @yield('page.level.js','')16 <!-- 頁面級(jí)別js代碼片段 -->17 @yield('page.level.script','')18 </body>19 </html>
上面幾份代碼實(shí)現(xiàn)這樣的約定是:UserController@getList方法渲染views/user/list.blade.php頁面,并將其填充到view/layouts/site.blade.php視圖中,也就是我認(rèn)為整個(gè)站點(diǎn)主視圖(布局,layouts/site.blade.php)基本一致,所有方法產(chǎn)生的內(nèi)容直接填充主視圖即可,那以后開發(fā)新的頁面或者接口,只需要按改約定開發(fā)即可