スイーツ(笑)と呼ばないで!!
| |||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
11/24/21:30 [PR] |
05/26/12:55 クエリストリング? 懐かしい響き!!Laravelはクエリストリングについてあれこれ考える必要はありません!!
例えば、詳細な検索条件を入力して検索して表示される一覧画面。 ここから詳細画面とか他の画面に行って、その後またこの一覧画面に戻りたい、そんな時ありますね。 さて、複雑な条件保持するのどうしましょうか? クエリストリング(?param1=abc¶m2=defとか)を文字列として扱う? そんなコードを見かけます。 Laravelならそんなことは不要です。 Laravelなら検索条件がpostされた時点でInput::all()とすればすべてのパラメータが連想配列で取得できますね。 これは皆さんご存知だと思います。 この配列を例えばセッションにsearch_paramsというキーで保存していたとします。 そして、他のアクションで処理が終わって同じ一覧に戻りたいとした場合、 return Redirect::action(‘ArticlesController@index’,Session::get(’search_params’)); この1行で済みますね。 え?「アクションのreturnじゃなくて、画面にリンクを表示したいです」って? はい。そんな時も簡単です。 Laravelにはactionというヘルパー関数があります。 action(‘ArticlesController@index’,Session::get(’search_params’)) と書けば、クエリストリング付きのリンクのURLが取得できますね。 さあ、皆さん、もうクエリストリングについて思い悩むことはやめましょう。 あなたは自由です^^ ちなみに、Laravelのソースコード読むとわかりますが、第二引数のSession::get(’search_params’)がnullの場合、defaultとして空の配列が渡るので、ちゃんとLaravelは動いてくれます。 Laravelって便利ですねー ちなみに、いろんな場所から飛んできて、前の画面に戻りたいけどケースによって変わる、そんなケースはどうします? Laravelには、refererを見て判断してくれるRedirect::backというのが用意されていますね。 ソースを見るといろんなことがわかりますね。 皆さん、ガリガリ書くのではなく、バリバリとソースコードを読むことに時間を使いましょう!! PR
|
05/19/13:06 deleted_atではなく、deletedで論理削除したいと言われたら?laravelは本当に便利ですね。 いろんな機能がすでに用意されていて、簡単につけたり外したりできます。 システム開発でよくある論理削除。 これもEloquentのModelの頭で use SoftDeletes; とか書くだけで利用できるようになります。 これだけで毎回、削除されているものを除く、とか条件をつける必要がなくなります。 削除されたものも含みたい場合は、 Article::withTrashed()->get(); みたいな感じでwithTrashedというscopeを指定するだけで可能。 本当に便利ですね。 ただ、この仕組みには大きな前提があります。 削除の判定はそのテーブルのdeleted_atがnullかどうかで判定する というものです。 もちろんカラム名は const DELETED_AT = ‘delete_datetime’; なんて感じで上書き指定できる柔軟さがlaravelにはあります。 ただ、DB設計者が 「いや、ここはdeletedという1か0のフラグで判定する」 といった場合、ちょっと困りますね。 対処方法は大きく3つあります。 1.用意されているSoftDeletesの仕組みは使わない 毎回、where(‘deleted’,’=‘,0)とかって指定するパターンですね。 どうやら、皆この方法をとっているようです。 2.自前で論理削除の仕組みを実装する。 自分でdeletedを使ったtraitとdeletedを使ったグローバルscopeを用意します。 それなりに面倒ではありますね。ただ、deleted_byとか追加したりいろいろカスタマイズができます。 3.deletedではなく、deleted_atのnull判定を使うように説得する。 DB設計者はそこまでこだわりはないかもしれません。 毎回、where(‘deleted’,’=‘,0)と書く手間や、書き忘れによるバグが出るよりは良い、と判断するかもれません。 この週末に2のパターンで実装してみました。 一応、ちゃんと動きましたね。 ただ、deleted_atを使わず、deletedを使うためだけにこの仕組みをやるのは少し大げさかなと思いました。 私はDB設計をする側の立場ですが、いろいろバランスを考えると、laravelの標準のまま使う3の案が良いのではないかと思いました。 これはちょっと他のSEやPGたちと話し合いたいところです。 必ずしも統一する必要があるところではないと思いますが。 合わせて、created_by、updated_by、deleted_byといったデータの作成・更新・削除を行ったuser等のメタ情報の管理についても話し合いたいと思っています。 laravelにはmodel eventsという仕組みがあり、例えば、データが作成されたタイミングなどをイベントリスナーで取得し処理を実行させることができたりします。 例えばそのタイミングでログを作成することなどで、代用が可能かもしれません。 createdではなく、creatingでメタ情報をセットするのもあるかもしれません。 ただ、model毎にイベントリスナーを登録するのは面倒ですね。 今のところメタ情報更新用のtraitを作成し、modelでuseするのが一番手間では無い気がしています。 ということで、最終結論はでていませんが、同じ目的が達成できなるなら、楽でミスが少ない方法が良いですね。 |
05/18/20:37 guardedとfillable、ちゃんと使っている?そのデータの作成者、簡単に偽装できます!! と聞いたら誰もがビックリするでしょう。 今日はそんな可能性のあるお話です。 Laravelの初心者向けの講座や書籍でEloquentが紹介されるとき、 class Article extends Model{ protected $guarded = ['id']; } とか書かれたりしますね。 「これはおまじないです」なんて言われて「そうかそうか」と深く考えずにそのまま真似したりします。 で、少し学習が進むと、guardedはブラックリスト、fillableはホワイトリストという感じで理解が進みます。 class Article extends Model{ protected $fillable= [’title’,’body']; } こんな感じでホワイトリストの登録もできる、と。 簡単に表現すると、ブラックリストに書いてある項目はユーザー入力の配列渡しで更新ができない、ホワイトリストに書いてある項目はユーザー入力の配列渡しで更新ができる、ということになります。 そして、ホワイトリストとブラックリストは逆の意味・・・その理解から、「ホワイトリストの登録は面倒だから、テキスト通りブラックリストにidを指定しておけばいいや」と考えたりします。 本当にそうでしょうか? fillableではなく、guardedを使っている人の多くが、idだけを指定していますね。 確かに、id,title,bodyこれだけしか項目が無ければ同じ意味です。 しかし、実案件ではこれらの他に created_at created_by updated_at updated_by こんな項目も裏で用意されていたりしますね。 このようなケースを想定しても、ホワイトリスト方式の場合は、変わらずtitleとbodyしか更新できません。 しかし、ブラックリストでidだけ登録されている場合は、パラメータ偽装で簡単にcreated_byが更新できてしまいます。 実際にChromeの開発者ツールで簡単に試すことができました。 え、その前に頑張って配列を整理しているから問題ない? そうかも知れません、でもfillableでホワイトリストを設定していれば、そんな努力は不要です。 ブラックリストの設定漏れだと、更新されてはいけないものが更新される可能性があります。 ホワイトリストの設定漏れだと、更新されるべきものが更新されない可能性があります。 さて、どちらのリスクをとるべきでしょうか? 私の好みはホワイトリストの方です。 laravelは私たちにセキュリティを確保するための簡単な仕組みを用意してくれています。 是非その仕組を有効活用して、無駄なコードを減らしましょう。 |
05/13/07:49 validationと正規表現前回、urlやactive-urlのvalidation ruleを軽く紹介しながら、
「Validatorのソースを読もう!!」と呼びかけたわけだけれども、 ついでなので、emailのvalidation ruleについても触れておきます。 emailのvalidation ruleはソースを見ると内部的には filter_var($value, FILTER_VALIDATE_EMAIL) これを呼んでいる。 実はこの FILTER_VALIDATE_EMAIL はRFC 822の形式かどうかをチェックする。 ここで思い出さなきゃならないのは、ドコモが2009年3月までRFC違反でやっていた独自仕様だ。 ドットを複数回連続させることができたり、 アットマークの前にドットを使うことができたりする例のあれである。 完全に廃止されたわけではなく、新規登録では受け付けなくなった、というのが正確なところ。 よって、日本の6年以上前のドコモのメールアドレスを想定するなら、 このvalidation ruleではダメだということになる。 さて、ここまでくると、「なんだよ、laravelのvalidation使えねー」とか思うかもしれない。 でもそれは間違い。 alpha、array、in、numeric…….その他ほとんどのruleはそのまま使える。 ただ、一部のruleは注意が必要、というだけ。 例えば、前回のurlだって、webサイトの形式チェックしたいだけなら、その後に 「httpまたはhttpsで開始するか」 という正規表現を使ったvalidation ruleを追加すれば良い。 laravelにはregexという正規表現を使うためのvalidation ruleがある。 引数として正規表現をとれる。最強だ。 じゃ、どんな正規表現渡せば良いの?となるとやはりソースを読む。 preg_match($parameters[0], $value) という感じでpreg_matchに引数としてそのまま渡す感じ。 とすると、マルチバイトの時とかちゃんと考えないといけないですね。 末尾に「/u」つけたりとか。 ただ、たまに日本語とかマルチバイト文字例は「/u」と覚えている人いますが、 このuはUTF-8のuです。Shift-JISとかEUC-JPとかそのまま渡しちゃダメですね。 じゃ、mb_eregに渡してあげればうまくやってくれるかというと、 これ、内部的にはmb_regex_encodingで指定の文字エンコーディングを使用します。 この関数のchang logを見ると、 Changelog Version Description 5.6.0 Default encoding is changed to UTF-8. It was EUC-JP Previously. と書いてありますね。最新のPHP5.6ではデフォルトがEUC-JPからUTF-8に変更されています。 この辺はとってもとっても複雑ですねー。 私も正直勉強不足ですし、できれば専門のプログラマに任せたい領域です。 (だから、あまり私の言うこと信じないでくださいねー 笑) もし、あなたが駆け出しのPGで一芸に秀でて皆の役に立ちたいという志をもっているのなら、 この正規表現やvalidationの技術を極めてみてはいかがでしょうか? 私が新人の時には、その時点の先輩方の得意分野を考慮の上、先輩方が得意でない分野の1つを専門として担当しました。駆け出しの新人でもその分野については先輩方もプロフェッショナルとて敬意を表してくれますし、入社数ヶ月で何年も実務経験のある何百人もの前でその分野の講義をしたりもしたものです。 最後に、正規表現をいろいろ試せる便利なサイトを紹介して終わります。 http://www.regexr.com/ 選べるフラグも限られているし完全ではありませんが、 基礎を学ぶには十分かと思います。 いつか正規表現にめっちゃくちゃ詳しくなったあなたが、 私のプロジェクトにアサインされる日を心待ちにしております。 (誰へのメッセージ?このブログ、読者いないけど 笑) |
05/12/03:09 Validatorのソースを読もう!!前回、Form Request Validationについて書きました。
その中で、rulesメソッドに、例えば public function rules() { return [ ‘title’ => ‘required|between:3,100’, ‘body’ => ‘required|min:10’, 'url' => 'required|url' ]; } こんな感じに書くとvalidationが簡単に書けることを紹介しました。 これは ・titleは必須で3文字以上100文字以下 ・bodyは必須で10文字以下 ・urlは必須でURLの形式 とかって意味になります。 超、簡単ですねー。 でも、何か気になりませんか? URLの形式ってなんでしょう? URLの形式チェックなら ◯ http://abc.com ◯ https://abc.com/def.html ☓ ttp://abc.com なんとなく、無意識にこんな動きを期待しませんか? でも、実は先頭のhが足らない ttp://abc.com はvalidationを通過します。 それどころか hello://abc.com とかでも通過してしまいます。つまり「:」の前は何でもOKなんですね。 これはValidatorのソースを読むとわかります。 ValidatorのvalidateUrlというメソッドの中では、 filter_var($value, FILTER_VALIDATE_URL) というPHP標準関数を呼び出しています。 実はこの FILTER_VALIDATE_URL という指定ではrfc2396に準拠しているかは見ますが妥当なプロトコルを指定しているかまでは見ません。 したがって、 'url' => 'required|url' というvalidation ruleの指定はwebサイトのURLチェックとしては不十分ということになるのです。 また、laravelにはactive-urlという似たような名前のvalidation ruleがありますが、こちらも注意が必要です。 これは最終的には実はそのホストのDNSのAレコードが存在するかというチェックだったりします。 興味のある人は是非ソースを読んでみてください。 ということで、今回のお話は、命名だけで信用せず、大事なところはソース読もうねー、というお話でした。 |