- 投稿日:2019-07-19T21:15:09+09:00
YYPHP#93「PHPの勉強何から始めたらいい?」 「一番やらかした失敗談は何?」 「ソースコードが酷すぎる現場で生き抜く術」 「テストコードを書くタイミングって?」
これは2019年7月19日に開催したPHPerイベントYYPHP#93のイベントレポートです。
YYPHPは一言で「PHPerの部室」です。PHPについて、雑に、ゆるく、ワイワイ話し合う集いです。毎回お題を決めずに雑談を出発点にいろいろなことを突発的にやります。集まった人でコードリーディングをすることもあれば、一緒に開発ツールを触ってみたり、フレームワークについての情報交換をすることもあります。開催はほぼ毎週、高田馬場にて。
今回の配信動画
本日のYYPHP主なお題
— suin❄️AWSできる方募集中です??固定ツイートご覧ください (@suin) July 19, 2019
「PHPの勉強何から始めたらいい?」
「一番やらかした失敗談は何?」
「ソースコードが酷すぎる現場で生き抜く術」
「テストコードを書くタイミングって?」https://t.co/xeyDRlHre5過去回の配信動画
https://www.youtube.com/playlist?list=PLpOeTEye3Bg6PodrLHHC72jWMJYZz8VbG
雑談
PHPの勉強何から始めたらいい? (ふるちゃん)
SQLとPythonの経験がある場合。
- 何を目指すのかによるかも
- 目的を作る
- 例えば。。
- WordPressのカスタマイズができるようになる
- 公開しなくてもいいからサービスを作ってみるのがいい。
- サービスを作ってみると、よく使うものが何なのか分かる。
- 自分で使って便利なサービスを作るのもあり。
- ウェブが考えることが多いので、CLIアプリから作るといいかも。
- 覚えることが少ないけど、PHPでよく使う機能は使うから勉強になる。
- 参考書を読んで、写経する
- サービスといっても作りたいものが無かったので。
- 自分で考えていちから作ったほうが、技術として身につく。
- Amazon.co.jp: 独習PHP 第3版 eBook: 山田祥寛: Kindleストア
- パーフェクトPHP | 小川雄大, 柄沢聡太郎, 橋口誠 | 工学 | Kindleストア | Amazon
みんな、どういう勉強のしかたをしてる? (はたけ)
ひたすら業務(自社サービス)を開発しているが、勉強という概念がわからなくなっている。
ひたすら業務すること=勉強みたいになっている。
聞きたいこととしては:
- どんな勉強している?
- いつ勉強している?
...
- 業務で取り扱っている技術を、業務時間外で深く調べてみる。
- 集中したほうがいい?
- なにかしら一つ極めたほうが、他に行きやすいと思う。
- 結果的に効率がいいはず。
- 朝7:30に会社近くのカフェに行って勉強している。
- リファクタリングを読んでいるがJavaなので苦戦している。
- Java→PHPに書き換えることで結構勉強になると思う。
- 家に帰ってから、興味がある分野(サーバサイド)について調べたり、読書したり。
- Kaggleを使い倒す。
- 疑問点を放置しない。
エンジニアとして伸びる心構えとは? (はたけ)
- reoringが意識していること
- 楽しむ
- 技術に対する愛情
- 探究心
- nouphetさん
- 自分の適性が合っているのを見つけたほうが伸びる
- いろんなものを触ってみて、チャレンジしてみて、得意を探すのも大事
- 発散 → 選択 → 集中
- Bulkerさん
- 自分が愉しむのが一番だと思う
エンジニアになってから一番やらかした失敗談は何? (いっとく)
- 本番サーバで誤って
rm -rf /<space>hoge/hoge
rm -rf $DIR/$VARで$DIRも$VARも定義されていなかったというミスも。
set -euxを習慣化しよう- ターミナルが右クリックしたらクリップボードの中身が貼り付けられる設定だった
- 大量にコピーされて、どこかのファイルが破損、バッチが起動しなくなり怒られた
- SPAMメッセージ抽出
- 個人情報を扱うのに、外部環境につないでやっていた
- スイッチを何気なくつないだら社内のネットワークが全部落ちた
- パケットが循環してしまうネットワークになってしまっていた。
- パケットストームが発生。
- ファイルの削除を再帰処理
- バグで下位ディレクトリだけでなく、上位ディレクトリの中身も消えた。
ソースコードがひどい現場に入ったときでも成長できる方法って何? (いっとく)
1600行のメソッドがあったり。
- できるだけどうすればもっと保守しやすくなるか?というのを考えながらやってる。
- キレイなコードをさっと出せるようにするには?
- 何がキレイかは最初はわからないと思う。
- キレイが分かっている人に見てもらうのが一番いい
- 綺麗さが大事じゃなくて、いろいろ考えられたため機能美として美しさが生まれる
- 自分が気持ち悪いと思う部分があるから、良くしたいと考えられるし、違和感について深掘りしていったほうがいい。
- ボーイスカウトルール
- 「来たときよりもキレイに」
- 他の人が書いたソースを見て学ぶ
テストコード書くときはどのタイミングで書いてる? (かきうち)
- テスト駆動開発というのをよく耳にするが、
- テストのパターン
...
- 慣れていればテストを先に書き上げることはできるが、
- テストファーストとTDDは厳密には違う
- TDD: Red Green Refactor
おすすめの技術書、教えて! (いっとく)
今まで読んだもの:
- パーフェクトPHP
- JavaScript忍者の極意
- リファクタリング
...
PHP以外が弱い
PHPと関連のある分野(DB、サーバー、セキュリティ……)...
- スッキリわかるMySQL
- わかりやすかった
- 徳丸本 体系的に学ぶ 安全なWebアプリケーションの作り方
- PHPer必読、バニラPHPerにはかなり必読
- クリーンコード、クリーンアーキテクチャ、アジャイル開発の奥義
- キレイなコード、いい設計について
- クリーンコード、コードコンプリート上巻
- この2冊を理解すれば、良いコードが何か分かる。
- PHPエンジニアが絶対に読みたい本 - Qiita
IT系特有の疾患を持っていて転職活動中です。企業に属すかフリーランスとして頑張るか迷ってます。(ばるかー)
- どっちにするかは人による
- フリーランスは負担が大きい
- 経理や営業、契約締結手続きなども自分でやらないとならない。
- プレッシャー
- どういう企業に入るかによって違う
- 通勤があるかリモートワークできるかで違う
YYPHPは毎週やってます
PHPについてワイワイ話したい方は、YYPHPのイベント情報をチェックしてみて下さい。
以上、YYPHPのレポートでした。次回もワイワイやっていきたいと思います! では、また来週!
- 投稿日:2019-07-19T18:15:14+09:00
PHPで簡単なBANをする
攻撃的な発言をする人などをBANしたい時に.使えるかも…?
前提
- php 7.0
- apache2
- ubuntu 18.04
BANしたいユーザーのipを書く(BAN.php)
BAN.php<?php $ip = $_SERVER["REMOTE_ADDR"]; $nguser = array('123.456.789.012', '111.222.333.444'); ?>
- 123.456.789.012とか111.222.333.444のところはBANしたいIP名に書き換える
- 最初と最後の<?php と ?>を書かないと後々htmlとして読み込まれるので注意...
- IP増やしたい時はコンマで区切って増やしてね
メインページでの処理(index.php)
index.php<?php include 'BAN.php'; if (in_array($ip, $nguser)) { header('Location: https:/mysite.mysite/banuser.php'); } ?> <!--ここからhtmlとか内容を書いてね-->
- include 'BAN.php';のところはそれぞれの環境に応じてパスを変えてね。(この例だと同ディレクトリにBAN.phpが置いてある)
- https://misite.misite のところは自分のサイトに書き換えてね
BANされた人向けのページ(banuser.php)
banuser.php<?php include 'BAN.php'; if (in_array($ip, $nguser)) { }else{ header('Location: https://correctjp.work'); } ?> <!--ここから先は自由に書いてね--> <h1>あなたはBANされました。</h1>
- 別になくてもまあいいですがnot foundだとあれなので...
- phpのところはBANされてない人にURLから飛んでこられても見せないためです。
- リンクの書き換えとかはさっきと同じ
その他
個人的には誰にでもわかるように書いた...つもりです。
初心者が思いつきで考えたのでもっといい方法があると思います..
Apache2でBANすればいいんですが面倒だった時とかに使えればいいかもです。
どう動いてるかとかは今後追記するかもしれませんが他の人の見たりggって見てください..
一応これ、そのまま怪しい日本語ジェネレーター(https://correctjp.work )で使ってます..
お疲れ様でした!
- 投稿日:2019-07-19T16:23:54+09:00
CentOS 或いはEC2 にapache2.4 ,php5.4 を追加する
あらすじ
先輩に教えてもらったキーワードを元にサーバーを構築する備忘録。
今回はapache,phpを追加する。AWSのEC2にも同様の記述が使えるそうなので、そちらでも構いません。
EC2で動作確認しながら書いてます。とりあえず2ついっぺんにインストール
$ sudo yum install httpd php # Is this ok [y/d/N]: が出て止まったら y,Enter でokapache
# httpdを起動 $ sudo systemctl start httpd # 確認(active:runningになればOK) $ sudo systemctl status httpd # システム起動時に毎回起動するように設定 $ sudo systemctl enable httpd # 確認 $ sudo systemctl is-enabled httpd # 起動 $ sudo systemctl start httpd.serviceうまくいけばapacheのテストページが表示されます。
AWSでElastic IPに書かれてるIPをブラウザに打ち込んで入ってみましょう。もし失敗したらAWSのセキュリティグループのページを確認して、HTTPのポート80番が空いているか確認しましょう。hello world!!
お約束ですね、動作確認のためやりましょう!
本来ならconfigファイルを確認したほうがいいかもしれませんが別の機会に回します。初期設定としてapacheは/var/www/html内のファイルを最初に読むようになっています。そこにphpファイルを作成しついでphpの動作確認をするとしましょう。
$ sudo vim /var/www/html/index.phpindex.php<?php echo'hello world!!'; echo phpinfo() ?>下のようになっていればOK!ようこそ,PHPの世界へ・・
はい!ということで必要最小限の設定はできたかと思います。本当はDBも入れようと思ったんですがec2の方はどうも勝手が違うようで(RDSあるから?)それ確認してからにします。
次回もどんどん機能を足していきましょう!参考文献
- 投稿日:2019-07-19T14:40:28+09:00
getでの処理
受け手側
$request->input('key')
例 URL
http://google.com?hoge=hoge1&test=test1
↓
$request->input('hoge')
↓
hoge1
- 投稿日:2019-07-19T13:59:54+09:00
CakePHPでAjaxのデバック
Ajaxでリクエストを飛ばした際は、CakePHPのコントーラの処理でdebug&exitで処理を止めて見ることができません。
CakePHPなどのフレームワークを使う場合はレスポンスにエラーが返されるので、それをHTMLファイルに貼り付けて、エラー箇所を特定する方法を紹介します。Ajaxの流れ
- ビューからコントローラにjsでリクエストを送る
- コントローラで受け取った通信に含まれている値で処理を行い、ビューにレスポンスを送る
- コントローラからビューに送られてきたレスポンスを受け取り一連の流れが終了
1. jsコード
function userAdd(id, name) { let userId = '#userIdFlg' + '_' + id; let userName = '#userNameFlg' + '_' + name; // Ajax による POST 送信 $.ajax({ url: "/users/userAdd/", type: "POST", data:{ user_id : $(userId).val(); name : $(userName).val(); }, dataType: "text", success : function(response){ alert("成功"); }, error: function(){ console.log(response); } }); }2. コントローラ
UsersコントローラUsersController.phppublic function userAdd() { if ($this->request->is(['ajax'])) { $this->autoRender = false; $this->loadModel('Users'); $data = $this->request->data; $user = $this->Users->newEntity(); $user = $this->Users->patchEntity($user, $data); $this->Users->save($user); return; } }3. htmlでエラーコードを見る
コントローラの処理でエラーがあった場合に、ビューに送られるレスポンスにエラーが含まれている場合があります。
デベロッパーツールでconsole.log(response)の中身を見てみましょう。training_progress.js?1562823821:21 <pre class="cake-error"><a href="javascript:void(0);" onclick="document.getElementById('cakeErr5d26d2a3581d1-trace').style.display = (document.getElementById('cakeErr5d26d2a3581d1-trace').style.display == 'none' ? '' : 'none');"><b>Notice</b> (8)</a>: Undefined index: content_id [<b>APP/Controller/TrainingController.php</b>, line <b>563</b>]<div id="cakeErr5d26d2a3581d1-trace" class="cake-stack-trace" style="display: none;"><a href="javascript:void(0);" onclick="document.getElementById('cakeErr5d26d2a3581d1-code').style.display = (document.getElementById('cakeErr5d26d2a3581d1-code').style.display == 'none' ? '' : 'none')">Code</a> <a href="javascript:void(0);" onclick="document.getElementById('cakeErr5d26d2a3581d1-context').style.display = (document.getElementById('cakeErr5d26d2a3581d1-context').style.display == 'none' ? '' : 'none')">Context</a><pre id="cakeErr5d26d2a3581d1-code" class="cake-code-dump" style="display: none;"> <code><span style="color: #000000"><span style="color: #0000BB"> $mg_checks </span><span style="color: #007700">= </span><span style="color: #0000BB">$this</span><span style="color: #007700">-></span><span style="color: #0000BB">MgChecks</span><span style="color: #007700">-></span><span style="color: #0000BB">find</span><span style="color: #007700">()</span></span></code> <span class="code-highlight"><code><span style="color: #000000"><span style="color: #0000BB"> </span><span style="color: #007700">-></span><span style="color: #0000BB">where</span><span style="color: #007700">([</span></span></code></span> <code><span style="color: #000000"><span style="color: #0000BB"> </span><span style="color: #007700">[</span><span style="color: #DD0000">'content_id' </span><span style="color: #007700">=> </span><span style="color: #0000BB">$data</span><span style="color: #007700">[</span><span style="color: #DD0000">'content_id'</span><span style="color: #007700">]],</span></span></code></pre><pre id="cakeErr5d26d2a3581d1-context" class="cake-context" style="display: none;">$progress_code = '1' $level_code = null $group_code = null $loginuser = [ 'id' => (int) 1, 'login_code' => 'opema_sys', 'nice_name' => 'テスト 管理者(創新ラボ)', 'email' => '', 'sei' => 'テスト', 'mei' => '管理者(創新ラボ)', 'kana_sei' => 'テスト', 'kana_mei' => 'カンリシャ2', 'section' => '本部', 'position' => '24', 'birth' => null, 'joined' => null, 'img_path' => null, 'role' => '9', 'status' => null, 'onetime_password' => null, 'onetime_password_limit' => null, 'passport' => '', 'keycode' => null, 'created' => object(Cake\I18n\FrozenTime) { 'time' => '2018-11-15T02:52:25+09:00', 'timezone' => 'Asia/Tokyo', 'fixedNowTime' => false }, 'modified' => object(Cake\I18n\FrozenTime) { 'time' => '2018-11-19T18:43:34+09:00', 'timezone' => 'Asia/Tokyo', 'fixedNowTime' => false }, 'shop_id' => (int) 32, 'memo' => '', 'level_id' => (int) 4, 'affiliation_dept' => null, 'store_in_charge' => '' ] $data = [] $loginID = (int) 1 $ajwh_group_no = [ 'group_no is' => null ]</pre><pre class="stack-trace">App\Controller\TrainingController::progress() - APP/Controller/TrainingController.php, line 563 Cake\Controller\Controller::invokeAction() - CORE/src/Controller/Controller.php, line 440 Cake\Http\ActionDispatcher::_invoke() - CORE/src/Http/ActionDispatcher.php, line 119 Cake\Http\ActionDispatcher::dispatch() - CORE/src/Http/ActionDispatcher.php, line 93 Cake\Routing\Dispatcher::dispatch() - CORE/src/Routing/Dispatcher.php, line 60 Cake\Controller\Controller::requestAction() - CORE/src/Routing/RequestActionTrait.php, line 177 Cake\Controller\Component\RequestHandlerComponent::beforeRedirect() - CORE/src/Controller/Component/RequestHandlerComponent.php, line 285 Cake\Event\EventManager::_callListener() - CORE/src/Event/EventManager.php, line 414 Cake\Event\EventManager::dispatch() - CORE/src/Event/EventManager.php, line 391 Cake\Controller\Controller::dispatchEvent() - CORE/src/Event/EventDispatcherTrait.php, line 78 Cake\Controller\Controller::redirect() - CORE/src/Controller/Controller.php, line 551 App\Controller\Trainin上記のようなレスポンスが返ってきています。この中にエラーメッセージがあります。上部の方にHTML形式でエラーメッセージが返されているので、htmlファイルを作って、その中にコピペして見てましょう!
index.html<pre class="cake-error"> <a href="javascript:void(0);" onclick="document.getElementById('cakeErr5d26d2a3581d1-trace').style.display = (document.getElementById('cakeErr5d26d2a3581d1-trace').style.display == 'none' ? '' : 'none');"> <b>Notice</b> (8) </a> : Undefined index: content_id [ <b>APP/Controller/TrainingController.php</b>, line <b>563</b> ] <div id="cakeErr5d26d2a3581d1-trace" class="cake-stack-trace" style="display: none;"> <a href="javascript:void(0);" onclick="document.getElementById('cakeErr5d26d2a3581d1-code').style.display = (document.getElementById('cakeErr5d26d2a3581d1-code').style.display == 'none' ? '' : 'none')">Code</a> <a href="javascript:void(0);" onclick="document.getElementById('cakeErr5d26d2a3581d1-context').style.display = (document.getElementById('cakeErr5d26d2a3581d1-context').style.display == 'none' ? '' : 'none')">Context</a> <pre id="cakeErr5d26d2a3581d1-code" class="cake-code-dump" style="display: none;"><code><span style="color: #000000"> <span style="color: #0000BB"> $mg_checks </span><span style="color: #007700">= </span> <span style="color: #0000BB">$this</span><span style="color: #007700">-></span> <span style="color: #0000BB">MgChecks</span> <span style="color: #007700">-></span> <span style="color: #0000BB">find</span> <span style="color: #007700">()</span></span> </code> <span class="code-highlight"> <code><span style="color: #000000"><span style="color: #0000BB"> </span><span style="color: #007700">-></span><span style="color: #0000BB">where</span><span style="color: #007700">([</span></span></code></span> <code><span style="color: #000000"><span style="color: #0000BB"> </span><span style="color: #007700">[</span><span style="color: #DD0000">'content_id' </span><span style="color: #007700">=> </span><span style="color: #0000BB">$data</span><span style="color: #007700">[</span><span style="color: #DD0000">'content_id'</span><span style="color: #007700">]],</span></span></code></pre><pre id="cakeErr5d26d2a3581d1-context" class="cake-context" style="display: none;">$progress_code = '1'するとブラウザ側でコントローラのエラーが確認できますね。
※上記のスクショと今回紹介したコードは関係ありません。イメージを掴んでもらうためにスクショを載せました。
Ajaxのデバック 番外編1(Chromeデベロッパーツール)
- デベロッパーツールを開く
- Networkタブをクリック
- POST通信を走らせる
- Nameにある該当ファイルをクリック
これで
Status Codeや送られたデータであるForm Dataが確認できますね。ログをファイルに書き込んで処理を確認
例えば下記のようなAjaxの処理がコントローラに記述されているとします。
UsersController.phppublic function addUser() { $this->autoRender = false; $this->loadModels('Users'); $result = false; if ($this->request->is(['ajax'])) { $data = $this->request->data; $user = $this->Users->newEntity(); $user = $this->Users->patchEntity($user, $data); if ($this->Users->save($user)) { $result = true; } } return $result; }これをロギング設定をします。
use Cake\Log\Log;に記述して、確認したい変数を変数の部分に記述します。$this->log('変数', 'debug');UsersController.phpuse Cake\Log\Log; public function addUser() { $this->autoRender = false; $this->loadModels('Users'); $result = false; if ($this->request->is(['ajax'])) { $data = $this->request->data; $user = $this->Users->newEntity(); $user = $this->Users->patchEntity($user, $data); $this->log($user, 'debug'); if ($this->Users->save($user)) { $result = true; } } return $result; }
/logs/debug.logに書き込まれます。Ajaxのデバック 番外編3(コントローラに擬似的に処理を飛ばす)
Viewから飛んできたが値がどう処理されるか確認した場合がありますよね。そんな時の確認方法です。
コントローラの処理↓
UsersController.phppublic function addUser() { $this->autoRender = false; $this->loadModels('Users'); $result = false; if ($this->request->is(['ajax'])) { $data = $this->request->data; $user = $this->Users->newEntity(); $user = $this->Users->patchEntity($user, $data); if ($this->Users->save($user)) { $result = true; } } return $result; }上記の処理はAjaxでビューから通信が走った時に処理されます。この部分があるからですね→
if ($this->request->is(['ajax'])) {このif文を一時的にコメントアウトし、下記のアクションに遷移して通信を擬似的に発生させてdebugして確認します。
UsersController.phppublic function addUser() { //$this->autoRender = false; $this->loadModels('Users'); $result = false; $data['id'] = 11; $data['name'] = '西村'; //if ($this->request->is(['ajax'])) { $data = $this->request->data; $user = $this->Users->newEntity(); $user = $this->Users->patchEntity($user, $data); debug($user);exit; // $userにどんな結果が返ってきているか確認 if ($this->Users->save($user)) { $result = true; } //} return $result; }参考
- 投稿日:2019-07-19T13:57:35+09:00
NixOS で PHP 環境作ったった
なにこれ?
NixOS でPHPアプリケーションサーバを作ってみました。
NixOS はパッケージマネージャ Nix を利用した Linux ディストリビューションで、宣言的な記述でシステム環境を構築することが可能で、インストールパッケージの細かい制御が可能な点が魅力です。
イメージとしては Ansible が組み込まれた Linux といったところでしょうか。
またパッケージマネージャ Nix は既存の Linux 環境に導入が可能です。NixOS には独自のコンテナ機能があったり、クラウドへのデプロイまで済ませられる NixOps コマンドを提供していたり、色々と魅力的に思えます。
本稿では 基本的な設定方法とハマりやすい点について説明し、最後に設定ファイルを紹介します。
インスタンスを立ち上げる
まずは AWS で EC2 インスタンスを立ち上げます。公式が AWS 向けの AMI を公開していますので、それを使用できます。
インスタンスタイプは、今回の構成では t2.micro でも十分です。ただしディスクスペースをかなり使うので、最低でも 10 GiB は取っておいたほうが良さそうです。インスタンスが立ち上がったらログインしましょう。初期ユーザは root です。
NixOS の環境設定の基本
続いて環境設定ファイルを記述しましょう。環境設定ファイルは /etc/nixos/configuration.nix です。後述する nixos-rebuild コマンドを実行すると、このファイルに基づいた環境が構築されます。デフォルトでは以下のような記述になっているかと思います。
{ imports = [ <nixpkgs/nixos/modules/virtualisation/amazon-image.nix> ]; ec2.hvm = true; }configuration.nix は nix 言語で記述されています。 nix 言語をインタラクティブに実行することの出来る nix-shell という処理系もありますが、今回は使用しません。
変数 imports にはファイルパスのリストが束縛されます。 nix 言語では複数のファイルに分割して設定を行っていくことが可能で、 imports に設定されたリスト中のパスのファイルを読み込んでいき、それを評価してオプションに値を束縛をしてゆきます。これはモジュールなどと呼ばれます。
ec2.hvm は EC2 インスタンスを使用するときのオプションの一つで、 HVM 仮想化を利用する際に設定する必要がある値です。 NixOS はこういったオプションに値を束縛していくことで設定を行います。 NixOS はオプションの検索ページを用意しており、大半のオプションが検索可能です。
以下のコマンドを実行することで環境のテストビルドをできます。
nixos-rebuild -v test
-vオプションは冗長出力オプションです。ビルド中、様々なファイルが評価されていることが見て取れるはずです。
引数の test は nixos-rebuild のサブコマンドで、テストビルドを行う事を指定しています。テストビルドの場合は再起動するともとの環境に戻ります。
ブートローダにもインストールして、起動時から立ち上げたい場合は nixos-rebuild switch を実行しましょう。特定のパッケージを使用する
まずは使用するパッケージコレクションのリビジョンを固定しましょう。
NixOS のパッケージコレクションは、nixpkgs という名前で github で公開されています。
この nixpkgs レポジトリのリビジョンを固定することで、インストールされるパッケージのバージョンを固定することができます。
また、リビジョンの他にブランチを指定することも可能です。この場合はリリース毎のブランチを指定することである程度パッケージのバージョンを固定しつつ、セキュリティパッチだけあてるなどが出来そうです。今回は利用するブランチを、 "release-19.03" に固定しましょう。
configuration.nix に以下のパッチを当てます。0a1,7 > let > pkgsSrc = (builtins.fetchGit { > url = https://github.com/nixos/nixpkgs; > ref = "release-19.03"; > }); > pkgs = import pkgsSrc {}; > inパッチの内容を cat などを使ってファイル、 patch などに書き出し、
patch configuration.nix patchなどとすることでパッチを当てることが出来ます。builtins.fetchGit は git レポジトリを取得する nix 組み込み関数で、
{ url = ... }は fetchGit に渡す引数です。 pkgsSrc にダウンロードしたレポジトリが束縛され、これを import して引数なしで評価して pkgs に束縛しています。fetchGit は git コマンドを利用しますが、 NixOS にはデフォルトでは git コマンドがインストールされていないので、このまま nixos-rebuild を実行しても途中で失敗してしまいます。以下のコマンドを実行して git をインストールしましょう。
nix-env -iA nixos.git基本的なパッケージのインストール
パッケージコレクションを指定したので、今度はこのコレクションからパッケージをインストールしてみましょう。
NixOS はデフォルトでは git はもちろん、 syslog デーモンや vim エディタすら入っていません。試しに file コマンドを実行して、インストールされていないことをみましょう。続いて今回使用するパッケージをインストールしましょう。
configuration.nix に以下のパッチを当てます。10a11,14 > > environment.systemPackages = with pkgs; [ > rsyslog git vim file nginx php73 > ];オプション environment.systemPackages に、インストールしたいパッケージのリストを束縛します。右辺の冒頭で
with pkgs;とすることで、リスト内のパッケージは全て先ほど指定したパッケージコレクションの名前空間から選択されます。nixos-rebuild を実行すると、パッケージがインストールされた環境が構築されます。試しにまた file コマンドを実行してみましょう。
利用可能なパッケージはnix searchコマンドで検索をすることができます。環境設定時の Tips
オプション束縛値の上書き
ここまで見たように NixOS ではオプションに値を設定して環境を定義していきます。NixOS はオプションの検索ページを用意しており、大半のオプションが検索可能です。
モジュールは import することでいくつもの値を設定してくれるので便利なのですが、そういったオプションの値を変更したい場合は以下のような書き方をする必要があります。
services.openssh = pkgs.lib.mkForce { permitRootLogin = "no"; passwordAuthentication = false; };値を一度 mkForce で処理してから services.openssh に束縛しています。
NixOS の束縛は全て優先度が設定されています。デフォルトの優先度は 1000 です。
複数の束縛がある場合、優先度が最も高いものが採用されます。
mkForce は優先度を 50 に設定する関数です。具体的に優先度を設定したい場合は、 mkOverride が使えます。services.openssh.permitRootLogin には、モジュール
amazon-image.nixで値が束縛されているので、 mkForce を利用する必要があります。
pkgs.libを書く手間を減らしたい場合は、withを用いた書き方が可能です。詳しくは configuration.nix ファイルを見てください。モジュールの引数
今回はファイル自体で設定を完結させるため、自分でパッケージコレクションを指定しました。しかし NixOS がデフォルトで提供するものを使用することも可能です。
configuration.nix はそれ自体モジュールであり、 nixos-rebuid は pkg, lib, config などの引数を与えて評価します。
configuration.nix の冒頭を、let ... inで始めるのではなく、以下のように記述することで簡潔に記述をすることが可能になります。{ pkgs, lib, ... }:configuration.nix ファイル
最終的な configuration.nix ファイルの内容は以下のようになります。
主要な設定項目は以下の通りです。
- パッケージコレクションの指定とパッケージのインストール
- rsyslog の設定
- ユーザの追加、および sudo, sshd など権限まわりの設定
- nginx, phpfpm, ファイアウォールの設定
この記述を利用する場合、ユーザ名と SSH 公開鍵については、自分自身で書き換えて使用してください。
!TODO!とコメントにある行がそれです。let pkgsSrc = (builtins.fetchGit { url = https://github.com/nixos/nixpkgs; ref = "release-19.03"; }); pkgs = import pkgsSrc {}; lib = pkgs.lib; in with lib; { imports = [ <nixpkgs/nixos/modules/virtualisation/amazon-image.nix> ]; ec2.hvm = true; nix.gc = { automatic = true; dates = "19:30"; }; environment.systemPackages = with pkgs; [ rsyslog git vim file screen shellcheck nginx php73 ]; services.rsyslogd = { enable = true; extraConfig = '' *.*; -/var/log/all ''; }; ################################################ services.openssh = mkForce { permitRootLogin = "no"; passwordAuthentication = false; }; security.sudo.wheelNeedsPassword = false; users.users.username = { # !TODO! username にユーザ名をセット isNormalUser = true; extraGroups = [ "wheel" ]; openssh.authorizedKeys.keys = [ "ssh-rsa ..." ]; # !TODO! 使用する SSH 公開鍵をセット }; ################################################ networking.firewall.allowedTCPPorts = [ 80 443 ]; services.phpfpm = { poolConfigs."default" = '' listen = /var/run/default-phpfpm.sock user = nginx group = nginx pm = dynamic pm.max_children = 32 pm.max_requests = 500 pm.start_servers = 2 pm.min_spare_servers = 2 pm.max_spare_servers = 5 listen.owner = nginx listen.group = nginx php_admin_value[error_log] = 'stderr' php_admin_flag[log_errors] = on env[PATH] = ${lib.makeBinPath [ pkgs.php ]} catch_workers_output = yes ;; security.limit_extensions = ;; to accept *.html file ''; }; services.nginx = { enable = true; virtualHosts."_".locations."/" = { root = "/var/www/default"; extraConfig = '' fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_index index.php; fastcgi_pass unix:/var/run/default-phpfpm.sock; include ${pkgs.nginx}/conf/fastcgi_params; include ${pkgs.nginx}/conf/fastcgi.conf; ''; }; }; }
- 投稿日:2019-07-19T12:27:01+09:00
【Laravel5】認識機能を実装した際に追加される「Auth::routes()」にオプションを指定してカスタマイズする
php artisan make:authは便利だけど登録機能は別で作りたいという場合があると思うので、標準で実装される登録機能のルーティングを外してみたりしてみます。
(※Laravel5.7系以上)ソース
php artisan make:authを実行後、ルーティングに以下のコードが自動追加されると思うので、こいつに引数を渡していくroutes\web.phpAuth::routes();
Auth::routes()に対して以下のようにオプションで引数をbooleanで渡してやるとルーティングの設定をON/OFFできるroutes\web.phpAuth::routes([ 'verify' => true, // メール確認機能(※5.7系以上のみ) 'register' => false, // デフォルトの登録機能OFF 'reset' => true, // メールリマインダー機能ON ]);上記のルーティング情報は以下の通り。
registerが消えてverifyが追加されていると思います。
大本のソースは以下(
laravel\framework\src\Illuminate\Routing\Router.php)にあります。
コードを見てもらったらわかると思いますが、デフォルトでregister(登録機能)とreset(パスワードリマインダー)はスカフォールディングした段階で有効になるように書かれています。
(以下のソースはLaravel5.8系なので、新機能のメール確認機能のverifyが記述されていてかつデフォルトで無効になるようになっています)laravel\framework\src\Illuminate\Routing\Router.php/** * Register the typical authentication routes for an application. * * @param array $options * @return void */ public function auth(array $options = []) { // Authentication Routes... $this->get('login', 'Auth\LoginController@showLoginForm')->name('login'); $this->post('login', 'Auth\LoginController@login'); $this->post('logout', 'Auth\LoginController@logout')->name('logout'); // Registration Routes... if ($options['register'] ?? true) { $this->get('register', 'Auth\RegisterController@showRegistrationForm')->name('register'); $this->post('register', 'Auth\RegisterController@register'); } // Password Reset Routes... if ($options['reset'] ?? true) { $this->resetPassword(); } // Email Verification Routes... if ($options['verify'] ?? false) { $this->emailVerification(); } }おわり
- 使用してない機能はルーティングをOFFにして不要なコントローラーは削除しておきましょう
- ただし、↑の引数で設定を切り替えられるのは5.7系以前は実装されてないみたいなので注意してください。
- 投稿日:2019-07-19T12:20:14+09:00
【Laravel5】たまに出てくる「the page has expired due to inactivity. please refresh and try again」を表示させない
多くの原因はCSRFトークンを記述していない場合で発生する
ググってみると多くの場合はフォーム内にCSRFトークンの記述漏れで発生していることが多いようです。
なのでまずはフォーム内にCSRFトークンの記述があるかを確認してください
Laravel5.6以前なら{{ csrf_field() }}を、
Laravel5.6系以降なら@csrfというシンプルに記述できるので、これをフォーム内に埋め込んでください。以下Laravel5.6以前の記述例
form.blade.php<form method="POST" action="/profile"> {{ csrf_field() }} ... </form>以下Laravel5.6系以降の記述例
form.blade.php<form method="POST" action="/profile"> @csrf ... </form>以下参考になるのかもしれませんが少し情報が古いので注意
【Laravel】TokenMismatchExceptionが発生する原因 - QiitaCSRFトークンの有効期限切れで表示される
CSRFトークンの有効期限切れで表示される場合(例えばログイン画面で長時間放置してからログインしたりする)
以下のような画面が表示され、リロードしろと促されます。正直、この画面がでても何のことかわからないし、あまりにも突然表示されたりするので、
CSRFトークンが有効期限切れの状態でログインしたりした際、ログイン画面へリダイレクトさせる処理をapp/Exceptions/Handler.phpに記述していきます。laravel\app\Exceptions\Handler.php<?php namespace App\Exceptions; use Exception; use Illuminate\Auth\AuthenticationException; use Illuminate\Session\TokenMismatchException; // add use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; class Handler extends ExceptionHandler { // ... /** * Render an exception into an HTTP response. * * @param \Illuminate\Http\Request $request * @param \Exception $exception * @return \Illuminate\Http\Response */ public function render($request, Exception $exception) { // 「the page has expired due to inactivity. please refresh and try again」を表示させない if ($exception instanceof TokenMismatchException) { return redirect('/login')->with('message', 'セッションの有効期限が切れました。再度ログインしてください。'); } return parent::render($request, $exception); } }これで
TokenMismatchExceptionが発生した場合はログイン画面へエラーメッセージとともにリダイレクトさせることができるステータスコード(419)の場合にリダイレクトさせる
ちなみにステータスコードで判定するようにもできるので以下のようにも書けます。
laravel\app\Exceptions\Handler.php<?php namespace App\Exceptions; use Exception; use Illuminate\Auth\AuthenticationException; use Illuminate\Support\ViewErrorBag; // add use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; // add class Handler extends ExceptionHandler { // ... /** * Render the given HttpException. * * @param \Symfony\Component\HttpKernel\Exception\HttpExceptionInterface $e * @return \Symfony\Component\HttpFoundation\Response */ protected function renderHttpException(HttpExceptionInterface $e) { $this->registerErrorViewPaths(); // 「the page has expired due to inactivity. please refresh and try again」を表示させない if ($e->getStatusCode() === 419) { return return redirect('/login'); } if (view()->exists($view = "errors::{$e->getStatusCode()}")) { return response()->view($view, [ 'errors' => new ViewErrorBag, 'exception' => $e, ], $e->getStatusCode(), $e->getHeaders()); } return $this->convertExceptionToResponse($e); } }ただステータスコード
419が必ずしもCSRFトークンの有効期限切れで返しているかわからないので、TokenMismatchExceptionが発生した場合のみログイン画面へリダイレクトさせた方がいいかなと思っていますがどうでしょう?おわり
- もっといい方法あれば教えていただきたいです草々不一
参考URL
- 投稿日:2019-07-19T12:02:12+09:00
Laravel で updateOrCreate を使う際に Unknown column 'id' in 'where clause' でハマった
概要
Laravel の Eloquent が持っている updateOrCreate という関数を使った。
https://readouble.com/laravel/5.7/ja/eloquent.htmlMySQL でも気軽に Upsert 処理ができて便利だと思った。
実装例
App\VeryGoodSystem::updateOrCreate(
['user_id' => 12345],
['is_registered' => true]
);いざ利用してみたところ、下記のようなエラーが出た。
Unknown column 'id' in 'where clause' ...エラーを追うと、 updateOrCreate で実行されている SQL 文に
where `id` is nullという条件が付いていることがわかった。コードを見ても、
idという変数を使っている所は無く、途方に暮れながら調べていたら、良い Q&A を見つけた。(最下部、参考サイト)つまり、 model に primaryKey が設定されていないと default で id という文字列を使って updateOrCreate 用の SQL を作成してしまうようだった。
利用している Model に
$primaryKey = 'user_id'の一行を追加することで解決した。参考サイト
https://laracasts.com/discuss/channels/eloquent/understanding-of-updateorcreate
- 投稿日:2019-07-19T10:19:18+09:00
array_merge_recursiveで文字列が配列になる
array_merge_recursiveではまったのでメモ。
デフォルト値に対してPOSTされてきた値で上書きするって感じで下記の様なコードを書いてみました。
$default = [ 'Model' => [ 'title' => 'DefaultTitle' ] ]; $post = [ 'Model' => [ 'title' => 'PostTitle', 'user_name' => 'Ryuji' ] ]; var_dump(array_merge_recursive($default, $post));期待してる結果は下記のような感じだったんですが…
array(1) { ["Model"]=> array(2) { ["title"]=> string(9) "PostTitle" ["user_name"]=> string(5) "Ryuji" } }結果はこちら
array(1) { ["Model"]=> array(2) { ["title"]=> array(2) { [0]=> string(12) "DefaultTitle" [1]=> string(9) "PostTitle" } ["user_name"]=> string(5) "Ryuji" } }
titleが配列になって "DefaultTitle" と "PostTitle" が入ってきました^^;この例だと
array_mergeで十分だけど、2階層目のキーの有無が増えると、array_mergeだと足りないのよね…このときはCakePHP2だったんで、Hash::mergeつかってやりたいことは実現できたけど、なかったら自前で処理するのをつくらないとダメですかねぇ。
- 投稿日:2019-07-19T05:42:31+09:00
7の倍数
- 投稿日:2019-07-19T02:42:30+09:00
0からAWSでLAMPとLaravel環境構築(Windows)
手順
1.AWSアカウントを作成。
参照:AWS アカウント作成の流れ2.EC2というAmazonのクラウド上の仮想サーバーを構築。
参照:AWS EC2でWebサーバーを構築してみる3.LAMP環境を構築。
参照:チュートリアル: Amazon Linux 2 に LAMP ウェブサーバーをインストールする4.Laravelをインストール。
参照:AWSのEC2を立ち上げてLaravelのログイン機能を動かすまで
AWSでLaravelを立ち上げた1.AWSアカウントを作成
AWS は Amazon Web Services の略で、Amazon のクラウドサーバーを使用できるサービスです。
一年間無料でいろんな機能を試せます。
アカウントの登録は参照(AWS アカウント作成の流れ)に沿って行えばすぐできます。2.EC2構築
AWSにログインすると最初はこの画面が表示されると思います。
右上の地域はリージョンといい、自分の所在地に合わせて選択します。これは利用するデータセンターの場所を意味します。理論上近いほどレスポンスタイムが短いので、近いところを選びましょう。自分の場合は「東京」です。そしたら、左上のサービスからEC2を選択。
左のメニューの「インスタンス」 → 「インスタンス作成」を選択
一番目のAmazon Linux2 AMIを選択。
無料利用枠のt2.microにチェックを入れ、
他の設定は特にいじらずセキュリティグループの設定まで飛ばします。「新しいセキュリティグループを作成する」を選択し、「セキュリティグループ名と「説明」を好きなように入力し、画像のように五つのタイプを追加します。「ソース」のところでIP指定ができます。「任意の場所」を選択するとどこでもアクセスすることができ、「マイIP」を選択すると自分が現在使用しているネットワーク環境のIPでしかアクセスできなくなります。趣味程度の個人利用でしたら任意の場所で問題ありません。
右下の「確認と作成」 → 「起動」を押してから、このように表示されます。「新しいキーペアの作成」でキーペア名を入力。重要ですが、キーペアのダウンロードは必ずしてください。サーバーにアクセスするために必要となります。
「インスタンスの作成」 → 「インスタンスの表示」を順番に進めると、インスタントの画面に戻ります。
インスタンスの状態が running になっていれば作成成功です。
プラスα(オプション)
今作ったインスタンスに固定IPを割り当てることができます。左のメニューから「Elastic IP
」 → 「新しいアドレスの割り当て」 → 「割り当て」 → 「閉じる」で固定IPを一つゲットします。リストからIPを右クリック → 「アドレスの関連付け」で作成したインスタンスを選択し結びつけれます。3.LAMP環境の構築
①インスタンスに接続
サーバーに接続するため、ssh接続できるターミナルTeraTermをダウンロードします。インスタンス画面下の説明から固定IPとっていれば「IPv4 パブリック IP」、とっていなければ「パブリック DNS (IPv4)」をTeraTermのホストに入力して「OK」します。
次にユーザー名に「ec2-user」、秘密鍵に先ほどインスタンスを作るときにダウンロードしたキーペアファイルをセットして「OK」。
サーバーに接続できました。
直接とは関係ないですがコマンドでsudoを打つかどうかについて「root権限で`sudo`を付けた場合と付けない場合の違いに`su`は何の略?」を読めばわかると思います。②EC2のタイムゾーン設定
「Amazon EC2のタイムゾーンを日本時間に変更する方法」でわかりやすく書かれていますが、いくつか補足があります。
/etc/sysconfig/clockにはこのように変更すると書いてありますが、# ZONE="UTC" ZONE="Japan" UTC=true
trueのところをfalseにしないと再起動するときにタイムゾーンがUTCに戻ることがあります。# ZONE="UTC" ZONE="Japan" UTC=flaseここでルート権限を持たないため、
vimで保存するときにきっとこのようなエラーが出ると思います。E45: 'readonly' option is set (add ! to override)この解決法として自分がrootになるか、「[vim]read only のファイルをsudoで強制的に保存する」を参照してください。
オプションとして、「AWSの初期設定でrootパスワードを設定する」。一行目の
sshなんちゃらはすでにTeraTermログイン時にできてますので無視。
lnのオプションの意味は【 ln 】コマンド――ファイルのハードリンクとシンボリックリンクを作るに書いてあります。③LAMP環境構築
AWSの公式チュートリアル「チュートリアル: Amazon Linux 2 に LAMP ウェブサーバーをインストールする」の順序を追えばできます。自分はSQLに慣れているため、オプションの phpMyAdmin のインストールはしていません。phpMyAdmin はデータベースをGUIで管理できるツールです。
4.Laravelのインストール
①Composerをダウンロード
Composerについては「PHP開発でComposerを使わないなんてありえない!基礎編」。
以下ダウンロードコマンドです。$ curl -sS https://getcomposer.org/installer | sudo php $ sudo mv composer.phar /usr/local/bin/composerこれで
composer.pharというファイルが/usr/local/bin/composer/の下に置かれます。
このcomposer.pharファイルをcomposerというコマンドで実行できたら便利なので、composerというコマンドを作ります。alias composer='php /usr/local/bin/composer/composer.phar'ただし、これだけだと再起動するとリセットされて
composerが効かなくなりますので、常に成立するようにルートに存在する.bashrcというファイルに書き込みます。$ cd ~ # ルートに移動 $ ls -la # .bashrcがあるかどうかを確認 $ vi .bashrc # 「alias composer='php /usr/local/bin/composer/composer.phar'」を書き込むそしたらターミナルが起動すると読み込まれる
.bash_profileに.bashrcを参照するようにします。$ vi .bash_profile # 「source ~/.bashrc」を一番下に書き込む②拡張ライブラリをダウンロード
Laravelをダウンロードするのに必要なライブラリーは3つあります。
mbstring、mysqlndとxmlです。$ sudo yum install -y php-mbstring php-mysqlnd php-xml③Laravelをインストール
Laravel をインストールするディレクトリに移動します。自分の場合は
/var/www/の下にしました。$ cd /var/www $ composer create-project --prefer-dist laravel/laravel自分の場合ここで「proc_open(): fork failed errors」というエラーが出ました。「[PHP]Composer使用時に「proc_open(): fork failed errors」エラーが出た時の対処法」を見て解決できたので共有します。
-prefer-distって何ぞやと知りたい方には「composer の–prefer-distってよく使うけど何してる?」へ。④Apacheのドキュメントルートの設定と.htaccessの有効化
$ sudo vi /etc/httpd/conf.d/custom.confに
custom.conf# ドキュメントルート DocumentRoot "/var/www/laravel/public" # .htaccess 有効化 <Directory /var/www/laravel/public> AllowOverride All </Directory>を加えます。
そしたらApacheを再起動してください。$ sudo service httpd restart⑤パーミッションを変更
自分はパーミッションについてまだちんぷんかんぷんで、どの権限をどうすればいいか自分ではわかっていないので、他の方のブログを見たほうがいいかもしれません。基本的にパーミッションが合ってないとシステムにこのファイルに書き込めないよと怒られます。どうやらLaravelの場合は
storageとbootstrapの権限を変更する必要があるらしい。$ cd ~ $ sudo groupadd www $ sudo usermod -a -G www ec2-user $ exit一度ログアウトして再度入り直して、
$ cd /var/www $ sudo chmod -R 777 laravel/storage $ sudo chmod -R 775 laravel/bootstrap/cache $ sudo chown -R root:www /var/wwwこれでLaravelが使えるようになったはず。
- 投稿日:2019-07-19T00:16:28+09:00
Laravel-Excel(Maatwebsite/Excel)CSVの解釈の検証
Laravel-Excel のCSVの解釈の検証
Laravel-Excel(maatwebsite/excel) のcsvインポートの際のcsvの記述の仕方による値の解釈がどうなるのか検証を行いました。検証は下記の
DummyImportクラスインスタンスをExcelファサードのtoArray()の引数として渡し、取得した行の配列の値の解釈を確認します。app/Import/DummyImport.php<?php namespace App\Import; use Maatwebsite\Excel\Concerns\ToModel; use Excel; class DummyImport implements ToModel { public function model(array $row) { return $row; } } //DummyImportインスタンスをExcelファサードの`toArray()`の第一引数として渡す。 //併せて、対象csvファイルへのパスを第二引数として渡す。 $data = Excel::toArray(new DummyImport(), $filepath);検証1:文字リテラルの解釈
case1.csv"a","b","c" a,b,cクオーテーション
""を付けない時、付ける時の違いがあるのか検証しました。tests/Unit/CSVExtractTest.php<?php namespace Tests\Unit; use Excel; use App\Import\DummyImport; use Tests\TestCase; class CSVExtractTest extends TestCase { /** @test */ public function CSV検証_文字列クオーテーションありなし() { $data = Excel::toArray(new DummyImport(), base_path().'/case1.csv'); $this->assertEquals(2, \count($data[0])); //クオーテーションあり $this->assertEquals(3, \count($data[0][0])); $this->assertEquals('a', $data[0][0][0]); $this->assertEquals('b', $data[0][0][1]); $this->assertEquals('c', $data[0][0][2]); //クオーテーションなし $this->assertEquals(3, \count($data[0][1])); $this->assertEquals('a', $data[0][1][0]); $this->assertEquals('b', $data[0][1][1]); $this->assertEquals('c', $data[0][1][2]); } }テスト結果.txtTime: 5.22 seconds, Memory: 16.00 MB OK (1 test, 9 assertions)違いはないようでした。
検証2:カンマ入り文字列の解釈
文字列にカンマの入った
a,aという文字列をインポートする場合はどうなるのか検証してみましたcase2.csv"a,a","b","c" a,a,b,c "a,a",b,c1列目はクオーテーション
""をすべての値に付けました。2列目はクオーテーション""を付けません。(おそらくこれを3カラムと解釈されない。)3列目はa,aにだけクオーテーションを付けました。tests/Unit/CSVExtractTest.php<?php namespace Tests\Unit; use Excel; use App\Import\DummyImport; use Tests\TestCase; class CSVExtractTest extends TestCase { protected $extractedData; public function setUp():void { parent::setUp(); $this->extractedData = Excel::toArray(new DummyImport(), base_path().'/case2.csv'); } /** 中略 */ /** @test */ public function CSV検証_1列目_すべての値にクオーテーションを付ける() { $data = $this->extractedData; //1列目のカラム数は3であること $this->assertEquals(3, \count($data[0][0])); //値の検証 $this->assertEquals('a,a', $data[0][0][0]); $this->assertEquals('b', $data[0][0][1]); $this->assertEquals('c', $data[0][0][2]); } /** @test */ public function CSV検証_2列目_カンマの入った文字列にクオーテーションを付けない() { $data = $this->extractedData; //2列目のカラム数は3であること $this->assertEquals(3, \count($data[0][1])); //値の検証 $this->assertEquals('a,a', $data[0][1][0]); $this->assertEquals('b', $data[0][1][1]); $this->assertEquals('c', $data[0][1][2]); } /** @test */ public function CSV検証_3列目_カンマありのデータにだけクオーテーションを付ける { $data = $this->extractedData; //カラム数は3であること $this->assertEquals(3, \count($data[0][2])); //値の検証 $this->assertEquals('a,a', $data[0][2][0]); $this->assertEquals('b', $data[0][2][1]); $this->assertEquals('c', $data[0][2][2]); } }テスト結果.txtFFF. 4 / 4 (100%) Time: 6.49 seconds, Memory: 16.00 MB There were 3 failures: 1) Tests\Unit\CSVExtractTest::CSV検証_1列目_すべての値にクオーテーションを付ける Failed asserting that 4 matches expected 3. /home/vagrant/code/ttn-1129-laravel/tests/Unit/CSVExtractTest.php:23 2) Tests\Unit\CSVExtractTest::CSV検証_2列目_カンマの入った文字列にクオーテーションを付けない Failed asserting that 4 matches expected 3. /home/vagrant/code/ttn-1129-laravel/tests/Unit/CSVExtractTest.php:35 3) Tests\Unit\CSVExtractTest::CSV検証_3列目_カンマありのデータにだけクオーテーションを付ける Failed asserting that 4 matches expected 3. /home/vagrant/code/ttn-1129-laravel/tests/Unit/CSVExtractTest.php:47 FAILURES! Tests: 4, Assertions: 12, Failures: 3.予想よりもエラーが多かったのですが、arrayのカラム数はファイル内最大のカラム数となるようでした。
カラム数のassertをコメントアウトして実行したところ、予想通り、取得される値は2列目が不正となり、1列目、3列目は有効でした。テスト結果.txtPHPUnit 7.5.13 by Sebastian Bergmann and contributors. .F.. 4 / 4 (100%) Time: 6.23 seconds, Memory: 16.00 MB There was 1 failure: 1) Tests\Unit\CSVExtractTest::CSV検証_2列目_カンマの入った文字列にクオーテーションを付けない Failed asserting that two strings are equal. --- Expected +++ Actual @@ @@ -'a,a' +'a' /home/vagrant/code/ttn-1129-laravel/tests/Unit/CSVExtractTest.php:37検証3:数値リテラル(整数、浮動小数点数)の検証
case3.csv1,-2147483648,2147483647 1.0,2.231224,00030141.213tests/Unit/CSVExtractTest.php<?php namespace Tests\Unit; use Excel; use App\Import\DummyImport; use Tests\TestCase; class CSVExtractTest extends TestCase { /** 中略 */ public function CSV検証_整数、浮動小数点数() { $data = Excel::toArray(new DummyImport(), base_path().'/case3.csv'); $this->assertEquals(2, \count($data[0])); //整数 $this->assertEquals(3, \count($data[0][0])); $this->assertEquals(1, $data[0][0][0]); $this->assertEquals(-2147483648, $data[0][0][1]); $this->assertEquals(2147483647, $data[0][0][2]); //浮動小数点数 $this->assertEquals(3, \count($data[0][1])); $this->assertSame(1.0, $data[0][1][0]); $this->assertSame(2.231224, $data[0][1][1]); $this->assertSame(30141.213, $data[0][1][2]); } }テスト結果.txtPHPUnit 7.5.13 by Sebastian Bergmann and contributors. ...F 4 / 4 (100%) Time: 5.61 seconds, Memory: 16.00 MB There was 1 failure: 1) Tests\Unit\CSVExtractTest::CSV検証_整数、浮動小数点数 Failed asserting that '00030141.213' is identical to 30141.213. /home/vagrant/code/ttn-1129-laravel/tests/Unit/CSVExtractTest.php:88 FAILURES! Tests: 4, Assertions: 24, Failures: 1.00030141.213は文字列として扱うようでした。
検証4:特殊文字を含む場合
エスケープで使うバックスラッシュ
\などを含んだ文字列でcsvファイルから値を取得します。case4.csv@#@!@$!#$,^^^^^32143()_----,\\++====51`5tests/Unit/CSVExtractTest.php<?php namespace Tests\Unit; use Excel; use App\Import\DummyImport; use Tests\TestCase; class CSVExtractTest extends TestCase { /** 中略 */ /** @test */ public function CSV検証_特殊文字を含む場合() { $data = Excel::toArray(new DummyImport(), base_path().'/case4.csv'); $this->assertEquals(1, \count($data[0])); //整数 $this->assertEquals(3, \count($data[0][0])); $this->assertEquals('@#@!@$!#$', $data[0][0][0]); $this->assertEquals('^^^^^32143()_----', $data[0][0][1]); $this->assertEquals('\\\\++====51`5', $data[0][0][2]); } }テスト結果.txtPHPUnit 7.5.13 by Sebastian Bergmann and contributors. ..... 5 / 5 (100%) Time: 5.96 seconds, Memory: 16.00 MB OK (5 tests, 29 assertions)バックスラッシュ
\だけ、php側で、エスケープをちゃんとすることで検証できるようでした。参照
Laravel/Excelのインストール等に関しましては @rito328 さんのこちらのサイトに詳しく書いて頂いておりましたので参考にさせて頂きました。
https://www.ritolab.com/entry/160以上です。


















