- 投稿日:2019-05-23T23:47:58+09:00
require_onceでファイルの読み込み、色々あるけど結局どう書けばいいのか
結論
index.phprequire_once __DIR__.'/foo/A.php';これが一番てっとり早くて、設定による差異もなさそう。
https://php.net/manual/ja/language.constants.predefined.php
そのファイルの存在するディレクトリ。include の中で使用すると、 インクルードされるファイルの存在するディレクトリを返します。 つまり、これは dirname(__FILE__) と同じ意味です。 ルートディレクトリである場合を除き、ディレクトリ名の末尾にスラッシュはつきません。
ディレクトリ構成
/src/をドキュメントルートに指定している想定
src/ foo/ A.php B.php index.php相対パスでの指定
A.phprequire_once 'B.php';index.phprequire_once 'foo/A.php';相対パスでもindex.phpからA.phpを読み込むことは可能ですが、
A.phpで同じく相対パスを使ってB.phpを読み込んでいた場合エラーになります。相対パスで記述した場合はPHPファイルを実行したファイルがある位置からの相対パス、
つまりこの場合であればsrc/foo/B.phpではなく、存在しないsrc/B.phpをよんでいることになります。ドキュメントルートからの指定
index.phprequire_once $_SERVER['DOCUMENT_ROOT'].'/foo/A.php';https://www.php.net/manual/ja/reserved.variables.server.php
現在実行されているスクリプトが存在するドキュメントルート ディレクトリです。サーバーのコンフィグレーションファイルで 定義されています。
$_SERVER['DOCUMENT_ROOT']はApacheの場合httpd.confで設定されています。
ローカルと本番環境など設定によっては差異があることがあります。サーバーのルートからの指定
index.phprequire_once '/var/www/html/src/foo/A.php';ドキュメントルートとサーバーのルートは別物です。
現在は/src/をドキュメントルートに設定しているという想定ですが、
サーバーのルートからパスを指定する場合はドキュメントルートより上のディレクトリも記述しないといけません。
/var/www/html/はサーバーの設定によって異なります。include_pathでの指定
index.phprequire_once 'foo/A.php';https://www.php.net/manual/ja/function.include.php
ファイルのインクルードは、指定されたパスから行います。パスを指定しない場合は、 include_path の設定を利用します。 ファイルが include_path に見つからないときは、include は呼び出し元スクリプトのディレクトリと現在の作業ディレクトリも探します。
相対パスと同じ記述方法ですが、include_pathが設定されている場合、include_pathから先にファイルを探してくれるようです。
include_pathはphp.iniや.htaccess、set_include_path関数などで設定できます。dirname(__FILE__)での指定
__DIR__と同じ意味です。
__DIR__が追加されたのが5.3.0以降なのでそれ以前のバージョンではこちらを使用します。
https://php.net/manual/ja/language.constants.predefined.php
5.3.0 __DIR__ と __NAMESPACE__ が追加されました。 以下余談
include, requireの違い
処理失敗時にエラーを発するか、警告を発するか。
require : エラー(処理がストップする)
include : 警告(処理は続行)https://www.php.net/manual/ja/function.require.php
require_onceとrequireの違い
require_onceは一度しか呼び出さない。
foo.php$foo = 1;bar.php$bar = 1;index.phprequire_once 'foo.php'; $foo ++; var_dump($foo); // 2 /* foo.phpは一度しか呼び出されないので$fooが初期化されない */ require_once 'foo.php'; var_dump($foo); // 2 require 'bar.php'; $bar ++; var_dump($bar); // 2 /* bar.phpがもう一度呼び出されるのでbar.phpが初期化される */ require 'bar.php'; var_dump($bar); // 1オートローダを使う
いちいちrequire_onceを記述するのも面倒なのでオートローダを使った方が良さそう。
オートローダーはspl_autoload_registerを使って自作することもできますが、
Composerを使うのが楽でよさそうです。参考
【PHP】include, requireの安全なパスの書き方と違い
【PHP】include, requireの違いと使い分け
- 投稿日:2019-05-23T23:38:25+09:00
フラットphpをテストする
まえがき
phpunitを用いればphpのテストで困ることはありません。
テスト対象はフラットphp。classもvendorもなく、DBアクセスもありません。
もちろんcomposerも使用していません。テスト対象のphp<?php namespace honya; [$status, $res] = fncHonya(); header('HTTP/1.1 '.$status); header('Content-Type: application/json; charset=utf-8'); echo json_encode($res); function fncHonya(){ // ちょこっとビジネスロジック return [200, ['result'=>'ok']]; }phpunitはフラットphpをテストできない!
初めて知りました。フラットphpで開発したことがなかったので。
テストコードを作る方が面倒でしたが、知恵を絞ってテストできるようにしてみました。元のファイル構成:
app
└ honya.phpテストできるようにしたファイル構成:
app
└ honya.php
└ compser.json
└ phpunit.xml
└ tests
└ HonyaTestClass.php
└ HonyaTest.php
└ fixturesテスト用classを作る
HonyaTestClassを作成し、honya.phpをrequireしたメソッドを作成しました。
ポイントは3点
- namespace
- @runInSeparateProcess
- ob_start、ob_get_clean
テスト用class<?php namespace honya; class HonyaTestClass { private $header = []; private $http_status = null; private $body = null; /** * @runInSeparateProcess */ public function request(){ ob_start(); require 'honya.php'; $this->body = ob_get_clean(); $this->http_status = http_response_code(); $this->header = xdebug_get_headers(); //@TODO php7 xdebug } public function getHttpStatus(){ return $this->http_status; } public function getHeader(){ return $this->header; } public function getBody(){ return $this->body; } }namespace はテスト時に必要と分かりましたが、実際は不要です。
性能に影響がないので入れました。
echo で bodyを返すため、ob_start、ob_get_clean で echo 出力を奪い取っています。
@runInSeparateProcess を付けることでphpunitに邪魔されず、テスト対象の echo だけ取得できます。
header は header_list() で取得できないので(原因不明)、xdebug_get_headers() を使用しています。php5では機能しましたが、php7では機能しません(原因不明)テストを作る
classさえ作ればテストコードは普通です。
HonyaTest.php(テスト本体)<?php namespace honya; require_once 'tests\HonyaTestClass.php'; require_once 'tests\HonyaTestUtil.php'; class HonyaTest extends \PHPUnit\Framework\TestCase { use HonyaTestUtil; /** @runInSeparateProcess */ public function test1() { $body = 'honya body'; $this->init_function(200, $body); $_POST['honya_param1'] = 'honya1'; $_SERVER['REQUEST_URI'] = '/honya'; $clazz = new \honya\HonyaTestClass(); $clazz->request(); $this->assertEquals('honya2 body', $clazz->getBody()); $this->assertEquals('200', $clazz->getHttpStatus()); // $this->assertSame([], $clazz->getHeader()); //@TODO php7 xdebug } }テスト用utilを作る
ポイントは2点
- namespace
- trait
HonyaTestUtil.php()<?php namespace honya; use phpmock\phpunit\PHPMock; trait HonyaTestUtil { use PHPMock; public function init_function($http_status, $body){ $this->getFunctionMock(__NAMESPACE__, 'getenv')->expects($this->any())->willReturn(''); } }getFunctionMock は namespace が空のときエラーになるります。
テスト対象(honya.php)に namespace を入れたのは、そういう訳です。HonyaTestUtil はclassにしていましたが、new でも static でもエラーになるので、trait にしました。
./vendor/bin/phpunit
で、実行できます。
phpunit.xml のデフォルトで autoload.php と テスト対象フォルダを指定されてるためです。
カバレッジも表示できるみたいですが、表示するまでもないので、暇があったらやります。
- 投稿日:2019-05-23T22:55:35+09:00
Laravelで画像ファイルを保存したい
今参加しているプログラミングスクールでの課題で、LaravelでECsiteを作っているのですが、Laravelへの画像の保存に苦戦したので、備忘録ようにメモします
作りたいもの
- Ecsite(の一部)
- 商品の一覧を表示した際に、画像ファイルが保存されるようにしたい
どこに画像を保存するか?
初めはDBにそのまま画像をぶち込もうと思っていたのですが、どうもそれはスマートではないらしい。。。
terateil:データベースに画像を保存するのはありでしょうか?すると、LaravelではStorage/app/public内に保存するのが基本のようです。そして、各々の画像へのパスをDBに保存することにしました。
保存するフォームを作る
今まで、お問い合わせフォームを作っていたので、それを使いまわして画像アップロード画面のひな形を作ります。bladeについては省略です。
具体的には、input(入力画面)->confirm(確認画面)->complete(完了画面)の形にして、input->confirmの際に一度Storage/app/public内のtempディレクトリに仮保存し、confirm->completeの際にStorage/app/public内のproductImageディレクトリに移動します。web.phpRoute::get('/image_input', 'ImageController@getImageInput'); Route::post('/image_confirm', 'ImageController@postImageConfirm'); Route::post('/image_complete', 'ImageController@postImageComplete');image_input.blade.php@section('body') <form action="image_confirm" method="post" enctype="multipart/form-data" id="form"> @csrf ファイル: <input type="file" name="imagefile" value=""/><br /><br /> 商品名:<br /> <input type="text" name="product_name" size="50" value="{{ old('name') }}"/><br /><br /> <input type="submit" name="confirm" id="button" value="確認" /> </form> @endsectionformタグ内で
enctype="multipart/form-dataを指定しないと、controllerでfileメソッドを使ってファイルを取り出そうとしてもnullになります。
image_confirm.blade.php@section('body') <form action="image_complete" method="post"> @csrf <table border="1"> <tr> <td>画像</td> <td><img src="{{ $data['read_temp_path'] }}" width="200" height="130"></td> </tr> <tr> <td>商品名</td> <td>{{ $data['product_name'] }}</td> </tr> </table> <input type="submit" name="action" value="送信" /> </form> @endsection@section('body') <p>商品のアップロードが完了しました</p> @endsectionまた、DBは次のmigrationファイルを基にして作り、Modelも作成しておきます
xxxx_xx_xx_xxxxxx_create_products_table.phppublic function up() { Schema::create('products', function (Blueprint $table) { $table->bigIncrements('product_id'); $table->string('path'); $table->string('product_name'); $table->timestamps(); }); }問題はcontroller...
取り敢えず、フォームから画像と名前を受け取って、画像には一意のファイル名としてtempディレクトリに保存します。また、sessionに保存して、confirm画面から読み込めるようにします。
ImageController.phppublic function getImageInput(){ return view('image_input'); } public function postImageConfirm(ImageUploadRequest $request){ $post_data = $request->except('imagefile'); $imagefile = $request->file('imagefile'); $temp_path = $imagefile->store('public/temp'); $product_name = $post_data['product_name']; $data = array( 'temp_path' => $temp_path, 'product_name' => $product_name, ); $request->session()->put('data', $data); return view('image_confirm', compact('data') );storeメソッドは、引数内のディレクトリに一意のファイル名として保存し、そこへのパスを返します。
画像を読み込むディレクトリ
Laravelの場合、画像を読み込むディレクトリはpublic/storageディレクトリです。
ややこしいのでもう一度書きます。
保存:storage/app/public
読込:public/storage
名前を変えてほしいですね。なので、public/storageから、storage/app/public内を読み込めるよう(シンボリックリンクを張る)にします。php artisan storage:linkこれで、storage/app/public内を覗けるようになりました。
ディレクトリが違えばパスも違う
では、いざconfirm画面を表示! させても画像が表示されません...
それもそのはず、読み込みに行っているパスが
(storage/app/)public/temp/xxx.jpeg
となっているからですね。でも先ほど書いた通り、読み込むのは
(public/)storage/temp/xxx.jpeg
でないといけないですね。
よって、controllerを次のように変えます。ImageController.php$temp_path = $imagefile->store('public/temp'); $read_temp_path = str_replace('public/', 'storage/', $temp_path); //追加 $product_name = $post_data['product_name']; $data = array( 'temp_path' => $temp_path, 'read_temp_path' => $read_temp_path, //追加 'product_name' => $product_name, ); $request->session()->put('data', $data);str_replaceメソッドで、public/をstorage/に置き換えました。
いざ表示させると、無事できました!後は移動させてDBへ保存
次に、confirm->completeにおいて、tempディレクトリからproductImageディレクトリに移動させ、DBに保存します
public function getImageComplete(Request $request) { $data = $request->session()->get('data'); $temp_path = $data['temp_path']; $read_temp_path = $data['read_temp_path']; $filename = str_replace('public/temp/', '', $temp_path); //ファイル名は$temp_pathから"public/temp/"を除いたもの $storage_path = 'public/productimage/'.$filename; //画像を保存するパスは"public/productimage/xxx.jpeg" $request->session()->forget('data'); Storage::move($temp_path, $storage_path); //Storageファサードのmoveメソッドで、第一引数->第二引数へファイルを移動 $read_path = str_replace('public/', 'storage/', $storage_path); //商品一覧画面から画像を読み込むときのパスはstorage/productimage/xxx.jpeg" $product_name = $data['product_name']; $this->productcontroller->path = $read_path; $this->productcontroller->product_name = $product_name; $this->productcontroller->save(); return view('image_complete'); }無事、画像が保存されました!
後は読み込むところで<img src="{{ $path }}" width="200" height="130">とすればOKです!
参考にしたサイト
Laravel学習帳:画像アップロード(基本)
Qiita:Laravel5.6でファイルアップロードの実装と躓いたところまとめ
Qiita:[Laravel] ユーザーのアイコン画像を投稿、表示させる機能の実装したのでメモ(画像の保存場所は?シンボリックリンクって?)
- 投稿日:2019-05-23T20:20:25+09:00
vs code insiders のクイックスタートを色々な言語で試してみた。
vs code insidersにIDEの未来の姿を見たので、勉強を兼ねて構築手順をまとめてみました。
クイックスタートの言語毎で若干差異があるようで、かじった事のある言語を試してみました。
vs code insidersそのものの詳しい説明については他のわかりやすい記事を参照してください。
簡単に言うと、今までは開発環境と実際の動く環境は別々で、トラブルが起こりやすい状況でのプログラミングが普通だったんですが、実際の動く環境でプログラミングができる。を提供するのがvs code insidersです。2019-05-23時点では以下の言語のクイックスタート(以下チュートリアル)があります。
https://code.visualstudio.com/docs/remote/containers
- node
- python
- go
- java
- dotnetcore
- php
- rust
- cpp
この中でnode、python、go、phpを今回試していきます。
事前準備
チュートリアルを始める前に、git や vs code insiders&extention(remote development)、docker等をインストールしてください。
dockerはshared driveの設定も忘れずに。チュートリアル ダウンロード
任意のディレクトリで以下のコマンドを実行
shgit clone https://github.com/Microsoft/vscode-remote-try-node git clone https://github.com/Microsoft/vscode-remote-try-python git clone https://github.com/Microsoft/vscode-remote-try-go git clone https://github.com/Microsoft/vscode-remote-try-phpチュートリアルの順番について
説明しやすさの観点から go → node → php → python の順番で進めます。
go
- vs code insidersを立ち上げて任意のディレクトリにダウンロードした
vscode-remote-try-go
を開く- 右下に「Folder contains〜」というポップアップが出るので「Reopen in Container」のボタンを押す
- 「Installing Dev Container [details]〜」に切り替わる
- しばらく待ち ※進捗状況は[detail]から
- 左下の緑の枠が「Dev Container: GO」になったら環境構築終了
- メニューの表示→ターミナルを開いて、
go run server.go
を実行Server listening on port 9000
が出力されればwebサーバ立ち上げ完了- http://localhost:9000/ にアクセス
出力文字を変えたい場合は
server.go
の"Hello remote world!"
を任意の文字列に変更し、ターミナルからCTRL+c で停止した後、再度go run server.go
を実行してページをリロードすると反映されていると思います。node
環境構築はディレクトリ
vscode-remote-try-node
を開いた後はgoと途中まで一緒(上記4まで)なので割愛します。
5. 左下の緑の枠が「Dev Container: Node.js Sample」になったら環境構築終了
6. 表示→ターミナルを開いて、node server.js
を実行
7.Running on http://0.0.0.0:3000
が出力されればwebサーバ立ち上げ完了
8. http://localhost:3000/ にアクセス出力文字を変えたい場合は server.js の対象箇所を変更できます。
goと同様に停止後→再実行で反映されます。PHP
1〜5 まで割愛
6. 表示→ターミナルを開いて、php -S localhost:8000
を実行
7. F1ボタンを押してRemote-Containers: Forward Port from Container〜
を選択後、「Forward 8000」をクリック
8. http://localhost:8000/ にアクセスphpはgo、node の手順+ポート転送の手順が必要となります。
出力文字を変えたい場合は index.phpを変更します。
また、変更にサーバの再起動は必要なく、ページのリロードのみで反映されます。python
1〜5まで割愛
6 以降では、デフォルトの設定では動かなかった&ポート番号(9000)がgoとカブるので以下の変更をします。.devcontainer/devcontainer.json"appPort": 9000, ↓ "appPort": 5000,.vscode/devcontainer.json"appPort": 9000, ↓ "appPort": 5000,app.py#以下をファイル末尾に追加 if __name__ == "__main__": app.run(debug=True, host='0.0.0.0', port=5000)表示→ターミナルを開いて、
python app.py
を実行出力文字を変えたい場合は static/index.htmlを変更します。
また、変更にサーバの再起動は必要なく、ページのリロードのみで反映されます。
※goとnodeも別ファイルとしてindex.htmlを読み込むように変更すればサーバ再起動は必要ありません。
- 投稿日:2019-05-23T20:02:43+09:00
PHPでXML形式のAPIレスポンスを受け取る際の注意事項
XML形式でレスポンスを返却するAPIに対して、PHP側で連想配列への変換を行う際には、通常
// curlの実行 $url = 'http://www.xxxxxxxxxx.yy.zz/getFruits/'; $curl = curl_init($url); $xml = curl_exec($curl); // 受け取ったXMLレスポンスをPHPの連想配列へ変換 $xmlObj = simplexml_load_string($xml); $json = json_encode($xmlObj); $response = json_decode($json, true);このようなフローを踏むことになるが、上記処理を行うとXMLの特性である
同名要素を複数持てる
という性質に対応した際に問題が発生する。パターン1:
<?xml version="1.0" encoding="utf-8"?> <data> <fruits> <name>apple</name> <price>100</price> </fruits> </data> // PHP変換後 $response = array('fruits' => array('name' => 'apple', 'price' => '100' ) );パターン2:
<?xml version="1.0" encoding="utf-8"?> <data> <fruits> <name>apple</name> <price>100</price> </fruits> <fruits> <name>orange</name> <price>80</price> </fruits> </data> // PHP変換 $response = array('0' => array('fruits' => array('name' => 'apple', 'price' => '100' ) ), '1' => array('fruits' => array('name' => 'orange', 'price' => '80' ) ) );パターン1のように、同名要素が存在しない場合は、連想配列に変換されるが
パターン2のように、同名要素が複数存在する場合は、配列が作られた上でその配下に格納されてしまい、参照の仕方が変わってきてしまう。したがって自分は以下のような対応を行い、データが1種類しか返却されないパターンでも必ず配列になるように対応をした
function addNumberToArray($arr) { // 連想配列の時は配列へ変更 if (!empty($arr) && array_values($arr) !== $arr) { $arr = array($arr); } return $arr; } $fruits = addNumberToArray($response['fruits']); foreach ($fruits as $fruit) { echo $fruit['name'] . 'は' . $fruit['price'] . '円です'; }こうすることで同名要素が一つの場合でも複数の場合でも同様の対応を行うことができた
- 投稿日:2019-05-23T19:13:03+09:00
PHPで非同期+プロセス管理? PHP-FPMより15倍速いというPHP-PMというモノを知った(PHP-fpmじゃないよ!)
ref: https://tsh.io/blog/php-pm-guide-getting-started-with-the-process-manager/先日、色々調べ物をしていたら、ReactPHPという変なのを見つけました。
https://reactphp.org/ここで言うReactはJavascriptのReact.jsじゃないです。Reactパターン?スタイル?のReactです。(ReactJSも元はPHPのHTMLコンポーネントライブラリのXHPがベースらしいんですが https://qiita.com/ytake/items/2ee2c0e10c6ef6f040fa )
PHPで非同期でマルチプロセスでってやつです。驚いたことにPHPで書かれています。
正直、「コレPHPで書くか?」って思ったんですが、面白そうだったので色々調べたらPHP-PMというものを見つけました。PPM - PHP Process Manager
https://github.com/php-pm/php-pm
PPMと略すみたいです。
ReactPHPを使って、SymfonyやLaravelが動くPHPのmiddleware(PSR-15)として実装されている感じです。SymfonyのHttpKernelのAdapterとして動作するとのことです。なので、nginxはPPMのプロキシとして動作します。
PPMは実行されると8080番ポートとかでずっとListenし続け、PPMがPHPを子プロセスとしてcliで動かしてプロセス管理をするとの事で、利用するphp.iniはcli用の設定になります。なので、利用するためにはPCNTLが必要であり、configureオプション
--enable-pcntl
が必要になります。
https://www.php.net/manual/ja/book.pcntl.phpNginx + PHP-fpmの15倍速いらしい
メモリリークは健在
公式ページでは、主な課題に「メモリリーク!メモリリーク!メモリリーク! まあ、プロセス再起動されるからきっと大丈夫だよ」的な事が書いてあり、引用元の記事でも
PHP-PM could cause big memory leaks (there’s probably some issue with restarting workers); it consumed all of my memory and crashed my PC; it happened twice,
と「メモリリーク凄くてPCクラッシュしたわ」的な事が書いてあるので、ここは注意が必要そうです。
まとめ
正直、「えー!?本当に速くなんの?」という疑念が振り払えないし、PHPでプロセス制御するってのに感覚的な恐怖を覚えます。
メモリリークもPCクラッシュするほどって話だし、まだまだ発展途上なのかなぁという感じです。が、きちんと検証せずに感情だけで判断してはダメなので、近いうちに色々試してみようと思います。
ちなみに、PHPで非同期処理ってのだとSwooleってのがあり、こっちはC++で書かれていてPECLモジュールにもなっているので、感覚的にはこっちの方が安心できる。
https://qiita.com/gorogoroyasu/items/44119f8b2ba725859018
- 投稿日:2019-05-23T16:40:36+09:00
Dockerでlaravelの環境構築
Dockerを使用したlaravel環境構築
laradock
を使用することで簡単にlaravelの環境構築をすることができるので、以下に手順をまとめる。開発環境
MacOS Mojave
既にDocker
Git
はMacに導入済として下記記述します。laradockのダウンロード
Gitを使用して、任意のフォルダにlaradockをダウンロードします。
git clone https://github.com/Laradock/laradock.git // laradockへ移動 cd laradock // 公式ページの記載通り、下記コマンドを入力 cp env-example .envMysqlのバージョンを指定(現行最新版の8だと、通常とは違う認証になり、詰まる可能性大。指定がなければ、5.7を使用したほうが無難)
// .envを開き、"MYSQL_VERSION=latest" を以下のように変更 MYSQL_VERSION=5.7コンテナの作成
開発に必要なプログラムを指定し、コンテナを作成。なお、プログラムを指定しないとすべてのコンテナを作成しようとするため、時間がかかります。
通常のlaravel開発であれば、下記コマンドの指定で問題ないかと思います。docker-compose up -d nginx mysql workspace phpmyadmin終了後、
http://localhost
にアクセスすると、404 Not Found
が表示されます。
これにより、Nginxに無事アクセスできたことが確認できます。laravelアプリの作成
コンテナの
workspace
内にて、laravelアプリを作成します。// docker ps にて、workspaceのコンテナID確認後、下記コマンドでコンテナ内に入る docker-compose exec -it workspaceのコンテナID bash // コンテナに入り、"/var/www$"にて、下記コマンドを実行。バージョンは5.5以外でも変更できます。 composer create-project laravel/laravel sample --prefer-dist "5.5.*"これによって、
sample
というアプリファイルが作成されます。
次に、laradockディレクトリの.env
に、このアプリを作成したことを伝えるため、下記のように記述します。### Paths ################################################# # Point to the path of your applications code on your host APP_CODE_PATH_HOST=../sample設定を反映させるため、dockerを再起動させます。
// 停止 docker-compose stop // 再起動。以後は、nginxとmysqlのみを指定すればよい docker-compose up -d nginx mysql再度ブラウザで
http://localhost
にアクセスするとlaravelの画面が表示されます。MySQLとの接続
MySQLコンテナと、laravelのDB設定を合わせます。
sample
フォルダ内の.env
ファイルを開き、下記のように記述。
この内容はlaradockフォルダの.env
内のMySQLの記述と合わせたものになります。// laravelアプリ内の.envファイル DB_CONNECTION=mysql DB_HOST=mysql DB_PORT=3306 DB_DATABASE=default DB_USERNAME=default DB_PASSWORD=secret参考:laradockフォルダ
.env
のMySQL記述内容### MYSQL ################################################# MYSQL_VERSION=5.7 MYSQL_DATABASE=default MYSQL_USER=default MYSQL_PASSWORD=secret MYSQL_PORT=3306 MYSQL_ROOT_PASSWORD=root MYSQL_ENTRYPOINT_INITDB=./mysql/docker-entrypoint-initdb.d再度、
workspace
コンテナに入り、migrateを実行php artisan migrateMySQLコンテナに入り、テーブルが確認できれば完了です。
mysql -u default -p -h 127.0.0.1 show tables from default参照
Laravel & Docker 環境構築 with Laradock
Laradockを使ったLaravel開発環境構築のやさしい解説
Laradock公式サイト
- 投稿日:2019-05-23T14:52:48+09:00
いまさらLaravel4 Tips:Artisan::addしたくない
概要
commands クラス作成する度に、app/start/artisan.php に Artisan::add 追加するのめんどくさいな~と思って、commands ディレクトリ配下のphpファイル見て自動で追加することにしました。
もっとちゃんと考えて書けば namespace とかも ちゃんと取り よいか書き方あるんだと思いますが 取り急ぎで必要だったのでご勘弁ください。
artisan.php<?php $command_files = File::glob(app_path().'/commands/*.php'); if ($command_files !== false) { foreach($command_files as $file){ $fp = fopen($file, 'r'); $class = $buffer = ''; $i = 0; while (!$class) { if (feof($fp)) break; $buffer .= fread($fp, 512); if (preg_match('/class\s+(\w+)(.*)?\{/', $buffer, $matches)) { $class = $matches[1]; break; } } Artisan::add(new $class); } }namespace とか取らないなら phpファイルの中身見なくてもファイル名でいいじゃんとか今更思ってますが...。
- 投稿日:2019-05-23T13:53:06+09:00
php-master-changes 2019-05-22
今日は opcache 最適化のバグ修正、curl_multi_select()で 1 秒未満のタイムアウト指定が 0 になっていた問題の修正、unixODBC の検出の pkg-config への移行、spl で arg_info がドキュメントと乖離していた部分があったのの修正、テストの修正、mysqli.allow_local_infile が off の際に LOAD DATA LOCAL INFILE しようとすると出るエラーメッセージの修正があった!
2019-05-22
nikic: Fix null check in sccp add_array_elem chain handling
- https://github.com/php/php-src/commit/30f1b172625030c78d564ceede46e7490152fcb4
- [7.3~]
- ext/opcache で、SCCP 最適化器の null チェックを修正
nikic: Don't evaluate functions with partial array arguments
- https://github.com/php/php-src/commit/97ba6b0d8bbb20b0d4a4a0c950b582f6cfeeea27
- [7.3~]
- ext/opcache で、SCCP 最適化器の partial array の扱いを修正
rlerdorf: Fix precedence issue causing sub-second timeouts to be 0 in
- https://github.com/php/php-src/commit/7b42cdf95ee91b723e7df51ac96f880de51f4591
- [7.2~]
- ext/curl で、curl_multi_select() の際に 1 秒未満のタイムアウト指定が式中のキャストの優先度問題で 0 になっていた問題の修正
- rasmus のおっさんが言ってた奴だ
hughmcmaster: Use PKG_CHECK_MODULES to detect unixODBC
- https://github.com/php/php-src/commit/9df3e097b88533dd9abae4360500c849054dc410
- ext/odbc で、unixODBC の検出を pkg-config へ移行
kukulich: Fixed some arg infos to match documentation
- https://github.com/php/php-src/commit/d6c0c5ef8e90b26b8cf1632be1baa379405d0ba9
- [7.4~]
- ext/spl で、arg_info がドキュメントと乖離していた部分があったのを修正
nikic: Fix bug #78034
- https://github.com/php/php-src/commit/ff4b0ce0e8d582e4b8f6c44270a77f511d28bacd
- [7.4~]
- ext/opcache で、最適化器のバグにより pecl が動かなくなっていた問題の修正
dstogov: .text segment may be not the first one
- https://github.com/php/php-src/commit/7c99589be210eac023bf780263ed6ebcddf76a16
- [7.4~]
- ext/opcache で、PHP のコードを Huge Page へリマップする最適化の際にコードセグメントが先頭にあるという雑な仮定をしていたのを修正
- opcache.huge_code_pages の実装はじめて見たけどこういう奴だったかー、なるほど
nikic: Use a different URL in bug44811.phpt
- https://github.com/php/php-src/commit/3a0de243c389af40c703e0ef018d8f95f6eab563
- [7.2~]
- ext/soap で、テストの参照 URL がスラドだったのを php.net へ修正
nikic: Mark bug44811.phpt as an online test
- https://github.com/php/php-src/commit/b162c8f55a3d92f611febbcc14014eb2ca3244ac
- [7.4~]
- ext/soap で、外部アクセスするテストケースをオンラインテストとしてスキップできるよう修正
cmb69: Fix test case for cURL 7.65.0
- https://github.com/php/php-src/commit/62fe6ba20c229bb6ffd910f1b494a310c950cef6
- [7.2~]
- ext/curl で、cURL 7.65.0 用にテストこけの修正
SjonHortensius: Fix #77956 - When mysqli.allow_local_infile = Off, return a client error
- https://github.com/php/php-src/commit/96404eb8e223bde0f5f697987a81acb640cc539f
- [7.2~]
- ext/mysqli で、mysqli.allow_local_infile が off の際に LOAD DATA LOCAL INFILE しようとすると出るエラーメッセージの修正
- 投稿日:2019-05-23T08:03:27+09:00
PHPの標準関数を使ってユニーク(一意)なトークン(文字列)を生成する
PHPの標準関数のみでユニークなトークンを作りたかったので、メモとして残します。
目的
メールアドレス認証時に使用するアクティベーションキー用のトークンを発行したく、
実行する度に被らないランダムな文字列を取得するのが目的です。TL;DR
uniqid(bin2hex(random_bytes(1)))環境
PHP7系
乱数に使えそうな関数を探す
uniqid
uniqid ([ string $prefix = "" [, bool $more_entropy = FALSE ]] ) : stringマイクロ秒単位の現在時刻にもとづいた、接頭辞つきの一意な ID を取得します。
この関数は、戻り値の一意性を保証するものではありません。uniqid() // 5ce3d9f085632 uniqid() // 5ce3d9f154c7a uniqid() // 5ce3d9f25823a13桁の16進数の文字列が返ってくるようです。
現在時刻に基づいてるので実行するたびにカウントアップされていくようです。
uniqid
には第一引数で接頭辞を付けられます。uniqid('ucan-') // ucan-5ce3dabb38549 uniqid('ucan-') // ucan-5ce3dabbe1c38 uniqid('ucan-') // ucan-5ce3dabc5407c接頭辞を付けられるのは便利だったのですが、
固定文字列を付けてしまうと結局一意性は保証されません。dechex
10 進数を 16 進数に変換する
dechex ( int $number ) : string
$number
で指定した符号なし整数値を 16 進数表現した文字列を返します。dechex(0) // 0 dechex(100) // 64 dechex(255) // ffrandom_int
暗号学的に安全な疑似乱数整数を生成する。
random_int ( int $min , int $max ) : int
$min
〜$max
の間で偏りのない結果が重要な場合に使用するのに適した暗号化された乱数整数を生成します。random_int(0, 255) // 4 random_int(0, 255) // 158 random_int(0, 255) // 184乱数を生成する
16進数2桁(0 〜 ff)の乱数を生成して接頭辞を付ける。
uniqid(dechex(random_int(0, 255))) // 865ce3dddb0e35b uniqid(dechex(random_int(0, 255))) // 85ce3dddb13e1d uniqid(dechex(random_int(0, 255))) // b25ce3dddb198dc乱数を生成する(固定桁数)
もし桁数を固定したい場合は
sprintf
を使って0埋めすると良さそうかな?uniqid(sprintf('%02x', random_int(0, 255))) // 4e5ce3dd8d7e2de uniqid(sprintf('%02x', random_int(0, 255))) // 0a5ce3dd8d83477 uniqid(sprintf('%02x', random_int(0, 255))) // 4f5ce3dd8d8925d2019.05.23 追記
@suin さんから
random_bytes
もオススメのコメントいただきました!random-bytes
random_bytes - 暗号学的に安全な疑似乱数バイトを生成する
random_bytes ( int $length ) : stringsalt、鍵、または初期化ベクトルを生成するときなど、暗号用途に適した任意の長さの暗号ランダムバイトの文字列を生成します。
random_bytes(1)
とすると1byteのバイナリ文字列が返ります。
バイナリ文字列から16進数にbin2hex
関数で変換すれば00
〜ff
を取得できます。uniqid(bin2hex(random_bytes(1))) // 085ce642e0803c3 uniqid(bin2hex(random_bytes(1))) // 555ce642e2cb9fa uniqid(bin2hex(random_bytes(1))) // eb5ce642e4632152019.05.24 追記
@go12lim さんから
uniqid
の第二引数使うとシンプルに書けるとアドバイスいただきました?♂️uniqid('', true) // "5ce7b766c4b586.26307700" uniqid('', true) // "5ce7b767d85ab4.09025400" uniqid('', true) // "5ce7b7687dd943.84230183"これが一番シンプルで良さそうです!
ドット付きが気にならなければこれで良さそう!参考
- 投稿日:2019-05-23T00:58:28+09:00
LaravelでRequestのプロパティを加工する方法いろいろ
Requestのプロパティを加工したい
「Modelのミューテータを使えばいいじゃん!」
て言われるかもしれないけどまぁRequestの状態でとりあえず色々やりたいみたいな、ね。
ありますよね。プロパティをなかったことにしたい
例えば$request->divisionというプロパティをなかったことにしたい場合はこう。
$request->offsetUnset('division');フィールド名(文字列)をぶち込めば消えてくれます。
ちなみにunsetしてもだめだったのでこれ一択かと。(というかオブジェクトのプロパティ消すのにunsetは使えないのか?)プロパティを上書きしたい
フィールド名をKeyに持つ連想配列で上書きできます。
というか存在しないフィールド名を入れると新たなプロパティが作れちゃいます。$request->merge([ 'start_time' => $start.':'.'00', 'end_time' => $end.':'.'00', ]);replaceなんていうパラメータを一回空にしてからmergeするメソッドもあるみたいですね。(要検証)
おわりに
Requestクラスの中身のぞいてたんですけどまだまだワクワクするようなメソッドいっぱいありましたので機会があったら随時更新していきます。
というかRequestをこうやって加工しまくるの設計的にはどうなんですかね。。
- 投稿日:2019-05-23T00:19:27+09:00
php 5.6 から 7.2 に上げ phpunit を動かす
php7.2, zend で phpunit
php 5.6 の時に動いていた phpunit
php 7.2 したらエラーが…(´;◞౪◟; )
https://github.com/sebastianbergmann/comparator/pull/30/commits/f4ec922b3e514ae27d2c9693bc68222a93ceab34rlerdorf committed on 29 Jan 2017
(7.1 で ArgumentCountErrorの追加があったけどこれは違いそうな…↓だよなぁ…7.2 関係あったのか...?)
http://www.objective-php.net/basic/interfacephp 7.2 に互換性がある一番低いものかつ
修正入ってそうなので
phpunit 6 にSupport ended on February 1, 2019
https://phpunit.de/supported-versions.html
phpunit 6.0 から名前空間化されていて zend 死亡(古すぎぃ…
https://qiita.com/mt-kage/items/7630484c571680df1140phpunit 5 ならいけるはず (7.2 互換性ないけど...)
修正も入ってるはずSupport ended on February 2, 2018
https://phpunit.de/supported-versions.html
うっうごいた…( ◜௰◝ )