20190709のPHPに関する記事は13件です。

[PHP]ヘッダーの上に隙間が空く問題

はじめに

PHPファイルでヘッダーをつくっていて、上に隙間が空いたので解消方法を探った。

わかったこと

❶ キャッシュが溜まっている可能性
❷ phpのinclude(['hoge']);関数が影響を及ぼしてる可能性
❸ 単純にcssでtop: 0;をあててみる

メモ

環境

  • PHPファイルにHTMLとCSSを使用している。

解消方法の検証

❶ キャッシュが溜まっている可能性

  キャッシュを一週間分消したが効果なし

❷ phpのinclude(['hoge']);関数が影響を及ぼしてる可能性

  文字種類をUTF-8からUTF-8Nに変更することで解消できるとのことだったが効果なし

❸ 単純にcssでtop: 0;をあててみる

  隙間が解消されて解決に至った。

気づき

  • 単純にcssで消すことができた。
    • include(['hoge'])が影響を及ぼしていたのは間違いないようだった。

参考サイト

https://okwave.jp/qa/q8630179.html
http://kagan.hatenablog.com/entry/2014/08/09/190812

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【PHP7.4】PHP7.4では変数に型指定できる & 菱形継承っぽいものができる

PHPのすごい開発者Nikita Popovが書いたTyped Properties and more: What's coming in PHP 7.4?というスライドを見ていたらなにやら面白かったので、適当に紹介してみる。

変数の型指定

PHP7.4ではプロパティに型指定できるようになりましたが、実はプロパティではない只の変数にも型指定することができます。

class Dummy{
    public int $id = 42;
}
$dummy = new Dummy();

$id = & $dummy->id;

$id = 10; // OK
$id = 'not an id'; // Uncaught TypeError

ええ…

なんかもう普通にint $id = 42とか書けるようにしたほうがいい気もしないでもないですが、構文解析とかの都合で難しいのでしょう。

なんにせよ、これで変数の型指定もできるようになってしまいました。
このまま書くと非常にもったり感がありますが、きっと簡単に使えるライブラリが出てくることでしょう。

菱形継承

似たような方法でプロパティの菱形継承っぽいこと(交差型)も可能です。

class A{}

class B extends A{
    public ?Traversable $a;
}
class C extends A{
    public ?Countable $a;
}

$b = new B();
$c = new C();
$a =& $b->a;
$a =& $c->a;

$a = new RecursiveArrayIterator (); // OK
$a = new MultipleIterator(); // Uncaught TypeError: Cannot assign MultipleIterator

RecursiveArrayIteratorはTraversableとCountableをimplementsしているので代入可能ですが、MultipleIteratorはCountableをimplementsしていないので代入不可能です。
ということで菱形継承が可能になりました。

どんなときに役立つのか、よくわかりませんが。

親クラスには書けない

上記は親クラスに何も書かれていなかったので、本来の菱形継承ではありません。

親クラスでプロパティの型を指定した場合、子クラスでその制限を変更することはできません。
すなわち、以下のコードは残念ながら動きません。

動かない
class A{
    public Traversable $a;
}
class B extends A{
    public OuterIterator $a; // Fatal error: Type of B::$a must be Traversable
}

メソッドの型宣言は子クラスで狭めることができますが、プロパティはPHP7.4α1の時点では狭めることができません。
メソッドと動作を合わせるのであればこの書き方も許容されるべきですが、はたして修正されるでしょうか?
だめなままなのかな?

これが許可されるのであれば、以下のように自然な?形の菱形継承も可能になります。

動かない
class A{
    public ?Iterator $a;
}

class B extends A{
    public ?OuterIterator $a;
}
class C extends A{
    public ?RecursiveIterator $a;
}

$b = new B();
$c = new C();
$a =& $b->a;
$a =& $c->a;

$a = new RecursiveArrayIterator(); // OK
$a = new MultipleIterator(); // Uncaught TypeError: Cannot assign MultipleIterator

書けるようになったからといってどうするのかわかりませんが。

ジェネリクス

スライドを見ていたら、意外な構文が出てきました。

01.png

似非ジェネリクスではなく、本物のジェネリクスの導入を考えているみたいです。

まだ動かない
interface Event{}

class SpecificEvent implements Event{}

interface EventHandler<E: Event>{
  public function handle(E $e);
}

class SpecificEventHandler implements EventHandler<SpecificEvent>{
  public function handle(SpecificEvent $e){}
}

RFCもありませんし(Generic Types and Functionsは構文が異なる)、まだ思いつき段階といったところでしょうが、このひとNikitaですからね。
PHP8でジェネリクスが導入されていた、なんてことになったとしても驚きはないですね。

感想

変数の型指定は有用ですね。
定義方法さえ簡単になれば、あとパフォーマンスが極端に落ちるなどの問題がなければ、普通に使ってもよさそうです。
ただPHPの場合、stringを返す組み込み関数が普通にfalseを返してきたりするので、全てを置き換えるのはちょっと辛そうです。

菱形継承はそもそも役に立つ場面を知らないのでなんとも言えません。

ジェネリクスはどうなんですかね、PHPでそこまで必要なんですかね。
確かに配列要素の型を限定したいことは頻繁にありますが、しかし、あらゆるオブジェクトに型指定が欲しいとまではあまり思ったことがないですね。
今でもArrayAccessやらを使えば一応できますしね。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

なんちゃってオンラインターミナル

なんちゃってオンラインターミナル

プロジェクトによってはFTP接続しかできないといった環境にたまに参画することもあります。
修正の影響範囲調査、バージョン情報などちょっとしたこともファイルのダウンロードやサーバの管理をしている会社への問い合わせなど時間の無駄を排除すべく最低限のことができるオンラインターミナルを記載します。

webconsole.php
<?php
$command = "";
$commandResult = "";
if (isset($_POST['command']) && $_POST['command'] != "") {
    $command = $_POST['command'];
    $result = shell_exec($command);
    if ($result != null) {
        $commandResult = $result;
    } else {
        $commandResult = "実行結果はありません。。。";
    }
}
$html = <<< EOM
<!doctype html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>オンラインたーみなる</title>
<script>
</script>
</head>
<body>
<header>
<h1>オンラインたーみなる</h1>
</header>
<div>
<form action="webconsole.php" method="post">
<input type="text" id="command" name="command" required size="10" value="{$command}" placeholder="コマンドを入力してください。">
<button type="submit" value="ボタン">ボタンの内容</button>
</form>
<div>
<pre>{$commandResult}</pre>
</div>
</div>
<footer>
<address>Copyright(C) Dsuke,Allright Reserved.</address>
</footer>
</body>
</html>
EOM;

echo $html;

このソースだけでも事足りますが多少はデザインはしておきたいところです。
00.jpg  →  01.jpg

少しやる気を出してデザインした結果が以下です。

webconsole.php
<?php
$command = "";
$commandResult = "";
if (isset($_POST['command']) && $_POST['command'] != "") {
    $command = $_POST['command'];
    $result = shell_exec($command);
    if ($result != null) {
        $commandResult = $result;
    } else {
        $commandResult = "実行結果はありません。。。";
    }
    $commandResult = "<div class='box'><pre>{$commandResult}</pre></div>";
}
$html = <<< EOM
<!doctype html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>オンラインたーみなる</title>
<style type="text/css">
<!--
#header {
    position:relative;
    margin:0 10px;
    padding:10px 10px 10px 30px;
    font:bold 22px/1.2 Arial, Helvetica, sans-serif;
    color:#666;
    text-align: center;
    background:#ccc;
    border-top:#ccc solid 1px;
    border-right:#999 solid 1px;
    border-bottom:#999 solid 1px;
    border-left:#ccc solid 1px;
    text-shadow:1px 1px 0 rgba(255,255,255,1);
    box-shadow:
        0 0 0 1px rgba(255,255,255,0.5) inset;
    background-image: -webkit-gradient(linear, left top, left bottom,
            from(             rgba(220, 220, 220, 1.0)), 
            color-stop(0.25, rgba(240, 240, 240, 1.0)),
            color-stop(0.30, rgba(235, 235, 235, 1.0)),
            color-stop(0.36, rgba(240, 240, 240, 1.0)),
            color-stop(0.50, rgba(235, 235, 235, 1.0)),
            color-stop(0.80, rgba(215, 215, 215, 1.0)),
            to(                 rgba(210, 210, 210, 1.0))
            );
    background-image: -webkit-linear-gradient(top,
            rgba(220, 220, 220, 1.0), 
            rgba(240, 240, 240, 1.0) 25%,
            rgba(235, 235, 235, 1.0) 30%,
            rgba(240, 240, 240, 1.0) 36%,
            rgba(235, 235, 235, 1.0) 50%,
            rgba(215, 215, 215, 1.0) 80%,
            rgba(210, 210, 210, 1.0)
            );
    background-image: -moz-linear-gradient(top,
            rgba(220, 220, 220, 1.0), 
            rgba(240, 240, 240, 1.0) 25%,
            rgba(235, 235, 235, 1.0) 30%,
            rgba(240, 240, 240, 1.0) 36%,
            rgba(235, 235, 235, 1.0) 50%,
            rgba(215, 215, 215, 1.0) 80%,
            rgba(210, 210, 210, 1.0)
            );
    background-image: -o-linear-gradient(top,
            rgba(220, 220, 220, 1.0), 
            rgba(240, 240, 240, 1.0) 25%,
            rgba(235, 235, 235, 1.0) 30%,
            rgba(240, 240, 240, 1.0) 36%,
            rgba(235, 235, 235, 1.0) 50%,
            rgba(215, 215, 215, 1.0) 80%,
            rgba(210, 210, 210, 1.0)
            );
    background-image: linear-gradient(to bottom,
            rgba(220, 220, 220, 1.0), 
            rgba(240, 240, 240, 1.0) 25%,
            rgba(235, 235, 235, 1.0) 30%,
            rgba(240, 240, 240, 1.0) 36%,
            rgba(235, 235, 235, 1.0) 50%,
            rgba(215, 215, 215, 1.0) 80%,
            rgba(210, 210, 210, 1.0)
            );
}
#header:before {
    content:" ";
    position:absolute;
    top:0;
    left:15px;
    width:0;
    height:100%;
    border-left:#ccc solid 1px;
}
#header:after {
    content:" ";
    position:absolute;
    top:0;
    left:16px;
    width:0;
    height:100%;
    border-right:#eee solid 1px;
}
.cmd_input {
    position: relative;
    width: 90%;
    margin: 40px 3%;
}
.cmd_input input[type='text'] {
    font: 15px/24px sans-serif;
    box-sizing: border-box;
    width: 100%;
    letter-spacing: 1px;
    padding-left: 1em;
    color: #ffffff;
    background-color: #000000;
}
.cmd_input input[type='text']:focus {
    outline: none;
}
.effect {
    padding: 7px 14px;
    transition: 0.4s;
    border: 1px solid #000000;
    background: transparent;
    color: #ffffff;
    background-color: #000000;
}
.effect ~ .focus_line:before,
.effect ~ .focus_line:after {
    position: absolute;
    top: -1px;
    left: 50%;
    width: 0;
    height: 2px;
    content: '';
    transition: 0.4s;
    background-color: #00ff00;
}
.effect ~ .focus_line:after {
    top: auto;
    bottom: 0;
}
.effect ~ .focus_line i:before,
.effect ~ .focus_line i:after {
    position: absolute;
    top: 50%;
    left: 0;
    width: 2px;
    height: 0;
    content: '';
    transition: 0.6s;
    background-color: #00ff00;
}
.effect ~ .focus_line i:after {
    right: 0;
    left: auto;
}
.effect:focus ~ .focus_line:before,
.effect:focus ~ .focus_line:after,
.cmd_input.ef ~ .focus_line:before,
.cmd_input.ef ~ .focus_line:after {
    left: 0;
    width: 100%;
    transition: 0.4s;
}
.effect:focus ~ .focus_line i:before,
.effect:focus ~ .focus_line i:after,
.cmd_input.ef ~ .focus_line i:before,
.cmd_input.ef ~ .focus_line i:after {
    top: -1px;
    height: 100%;
    transition: 0.6s;
}
.effect ~ label {
    position: absolute;
    z-index: -1;
    top: 10px;
    left:30px;
    width: 100%;
    transition: 0.3s;
    letter-spacing: 0.5px;
    color: #00ff00;
}
.effect:focus ~ label,
.cmd_input.ef ~ label {
    font-size: 18px;
    top: -20px;
    left: 0;
    transition: 0.3s;
    color: #000000;
}
button.button {
    font-size: 1.0em;
    font-weight: bold;
    padding: 5px 15px;
    background-color: #c0c0c0;
    color: #191970;
    border: 2px solid #000000;
}

button.button:hover {
    background-color: #000000;
    color: #00ff00;
}
.box {
    padding: 8px 19px;
    margin: 2em 0;
    color: #2c2c2f;
    background: #cde4ff;
    border-top: solid 5px #00ff00;
    border-bottom: solid 5px #00ff00;
    background-color: #000000;
}
.box pre {
    margin: 0; 
    padding: 0;
    color: #ffffff;
}
footer {
    font-size: 80%;
    width: 99%;
    text-align: center;
    padding-top: 10px;
    padding-bottom: 10px;
    background-color: #313131;
    position: absolute;
    bottom: 0;
}
footer address {
    color: #ffffff;
    letter-spacing: 5px;
    font-style: normal;
}
-->
</style>
</head>
<body>
<header>
<h1 id="header">オンラインたーみなる</h1>
</header>
<form action="webconsole.php" method="post">
<div class="cmd_input">
<input class="effect" type="text" id="command" name="command" value="{$command}" placeholder="">
<label>コマンドを入力してください。</label>
<span class="focus_line"><i></i></span>
</div>
<center><button class="button" type="submit" value="実行">実行</button></center>
</form>
{$commandResult}
<footer>
<address>Copyright(C) Dsuke,Allright Reserved.</address>
</footer>
</body>
</html>
EOM;

echo $html;

02.jpg  →  03.jpg

見れるレベルにはなったかと思います。(だれかデザインしてくれ)

最後に

・バリデーションなど行っていないため各自実装してください
・適当に流用してください
・いい感じのデザイン求む(ください)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Carbonを使って投稿経過時間を表示する(Laravel)

About Carbon

Carbonについての説明は下記の記事に詳しく書かれています。

PHPで日付時刻処理を書くならCarbonを使うべき
phpの便利な日付、時刻オブジェクト Carbon を使用する。平成、令和などの和暦を表示させる
全217件!Carbonで時間操作する実例

概要

過去に作ったモジュールについて記事を書いてます。
instgramなどの投稿に、投稿から「〇〇分前」などと表示される時間経過の部分を作ります。
画像の「9分前」、「1秒前」の部分のことです。
image.png

コード

bladeテンプレートの投稿コンテンツにこれを書くだけでできます。

index.blade.php
<?php   //時間の差分を求める
$postedAt = new \Carbon\Carbon($message->created_at);
$now = \Carbon\Carbon::now();
$secondsSincePosted = $postedAt->diffInSeconds($now);
if($secondsSincePosted > 59){
    $minutesSincePosted = $postedAt->diffInMinutes($now);
    if($minutesSincePosted > 59){
        $hoursSincePosted = $postedAt->diffInHours($now);
        if($hoursSincePosted > 23){
            $daysSincePosted = $postedAt->diffInDays($now);
            if($daysSincePosted > 6){
                $yearsSincePosted = $postedAt->diffInYears($now);
                if($yearsSincePosted > 0){
                    echo $postedAt->format("Y年n月j日");
                }else{
                    echo $postedAt->format("n月j日");
                }
            }else{
                echo $daysSincePosted.'日前';
            }
        }else{
            echo $hoursSincePosted.'時間前';
        }
    }else{
        echo $minutesSincePosted.'分前';
    }
}else{
    echo $secondsSincePosted.'秒前';
}
?>

まとめ

Carbonはいいぞ。

Githubにも上げてます。
jdkfx/posted-date

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHP Parse error: syntax error, unexpected T_VARIABLE in

単純な記号ミス、打ち間違えなどによるエラー。
今回はコメントアウトの//が抜けてたため、指定行の一つ手前の行が原因で
エラーが発生した模様

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel キーワード検索 複数

はじめに

Laravelアプリにて、複数条件の検索機能を実装しました!
文字とカテゴリーの2つで検索出来る仕様です!

始め(修正前)はコントローラー/モデルで下記のように、条件毎でメソッドを分け記述していました。(メソッド名は気にせず)

QuestionsController.php(修正前)
class QuestionsController extends Controller
{
    private $question;
    private $category;

    public function __construct(Question $question, Category $category)
    {
        $this->question = $question;
        $this->category = $category;
    }

   public function index(Request $request)
   {
        //カテゴリー一覧を表示するため、カテゴリーモデルでデータを連想配列で取得するメソッド
        $categoryNames = $this->category->カテゴリー名取得メソッド();

        $keyword    = $request->input('キーワード');
        $categoryId = $request->input('カテゴリー');

        if (isset($keyword) && isset($categoryId)) {
            $questions = $this->question->なんちゃらメソッド1($keyword, $categoryId);
        } elseif (isset($keyword)) {
            $questions = $this->question->なんちゃらメソッド2($keyword);
        } elseif (isset($categoryId)) {
            $questions = $this->question->なんちゃらメソッド3($categoryId);
        } else {
            $questions = $this->question->all();
        }

        return view('question.index', compact(['questions', 'categoryNames']));
    }
}

モデル

questiion.php(修正前)
class Question extends Model
{
    public function なんちゃらメソッド1($keyword, $categoryId)
    {
        return $this->with(['紐づくデータ'])->where('title', 'LIKE', '%' . $keyword . '%')
                                         ->where('category_id', '=', $categoryId)
                                         ->get();
    }

    public function なんちゃらメソッド2($keyword)
    {
        return $this->with(['紐づくデータ'])->where('title', 'LIKE', '%' . $keyword . '%')->get();
    }

    public function なんちゃらメソッド3($categoryId)
    {
        return $this->with(['紐づくデータ'])->where('category_id', '=', $categoryId)->get();
    }
}

今回は条件が2つなので上記の記述量で収まっていますが、検索条件が増えた場合、メソッドと条件分岐をその都度書き足す必要が出てきます。
めんどくさいですし、コントローラがファットになってしまいます。

複数条件での検索を探す中で、クロージャやorWhereなど色々出てきましたが、わからず。。
最終的に下記の記述に書き直しました!

QuestionsController.php(修正後)
class QuestionsController extends Controller
{

   <--- 略 --->

   public function index(Request $request)
    {
        $categoryNames = $this->category->カテゴリー名取得メソッド();

        $questions     = $this->question->なんちゃらメソッド($request);

        return view('question.index', compact(['questions', 'categoryNames']));
    }
}

モデル

Question.php(修正後)
class Question extends Model
{
    public function なんちゃらメソッド($request)
    {
        $keyword    = $request->input('キーワード');
        $categoryId = $request->input('カテゴリー');
        $query      = $this->with(['紐づくデータ', '紐づくデータ']);

        if (isset($keyword)) {
            $query->where('title', 'LIKE', '%' . $keyword . '%');
        }

        if (isset($categoryId)) {
            $query->where('category_id', '=', $categoryId);
        }

        return $query->get();
    }
}

inputでの値の抽出もモデルに記述し、なるべくコントローラーのコードを減らしました!
eagerロードで紐づく値を取得したものを$query変数に代入し、条件が入力されていればその条件にあったSQLの処理が走ります!

このように書けば、メソッド毎に処理を追うこともなくなり、条件が増えた場合の追加が楽、可読性向上などのメリットがあると思います!

改善点あればご教示お願い致します!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel 検索機能 複数条件

はじめに

Laravelアプリにて、複数条件の検索機能を実装しました!
文字とカテゴリーの2つで検索出来る仕様です!

始め(修正前)はコントローラー/モデルで下記のように、条件毎でメソッドを分け記述していました。(メソッド名は気にせず)

QuestionsController.php(修正前)
class QuestionsController extends Controller
{
    private $question;
    private $category;

    public function __construct(Question $question, Category $category)
    {
        $this->question = $question;
        $this->category = $category;
    }

   public function index(Request $request)
   {
        //カテゴリー一覧を表示するため、カテゴリーモデルでデータを連想配列で取得するメソッド
        $categoryNames = $this->category->カテゴリー名取得メソッド();

        $keyword    = $request->input('キーワード');
        $categoryId = $request->input('カテゴリー');

        if (isset($keyword) && isset($categoryId)) {
            $questions = $this->question->なんちゃらメソッド1($keyword, $categoryId);
        } elseif (isset($keyword)) {
            $questions = $this->question->なんちゃらメソッド2($keyword);
        } elseif (isset($categoryId)) {
            $questions = $this->question->なんちゃらメソッド3($categoryId);
        } else {
            $questions = $this->question->all();
        }

        return view('question.index', compact(['questions', 'categoryNames']));
    }
}

モデル

questiion.php(修正前)
class Question extends Model
{
    public function なんちゃらメソッド1($keyword, $categoryId)
    {
        return $this->with(['紐づくデータ'])->where('title', 'LIKE', '%' . $keyword . '%')
                                         ->where('category_id', '=', $categoryId)
                                         ->get();
    }

    public function なんちゃらメソッド2($keyword)
    {
        return $this->with(['紐づくデータ'])->where('title', 'LIKE', '%' . $keyword . '%')->get();
    }

    public function なんちゃらメソッド3($categoryId)
    {
        return $this->with(['紐づくデータ'])->where('category_id', '=', $categoryId)->get();
    }
}

今回は条件が2つなので上記の記述量で収まっていますが、検索条件が増えた場合、メソッドと条件分岐をその都度書き足す必要が出てきます。
めんどくさいですし、コントローラがファットになってしまいます。

複数条件での検索を探す中で、クロージャやorWhereなど色々出てきましたが、わからず。。
最終的に下記の記述に書き直しました!

QuestionsController.php(修正後)
class QuestionsController extends Controller
{

   <--- 略 --->

   public function index(Request $request)
    {
        $categoryNames = $this->category->カテゴリー名取得メソッド();

        $questions     = $this->question->なんちゃらメソッド($request);

        return view('question.index', compact(['questions', 'categoryNames']));
    }
}

モデル

Question.php(修正後)
class Question extends Model
{
    public function なんちゃらメソッド($request)
    {
        $keyword    = $request->input('キーワード');
        $categoryId = $request->input('カテゴリー');
        $query      = $this->with(['紐づくデータ', '紐づくデータ']);

        if (isset($keyword)) {
            $query->where('title', 'LIKE', '%' . $keyword . '%');
        }

        if (isset($categoryId)) {
            $query->where('category_id', '=', $categoryId);
        }

        return $query->get();
    }
}

inputでの値の抽出もモデルに記述し、なるべくコントローラーのコードを減らしました!
eagerロードで紐づく値を取得したものを$query変数に代入し、条件が入力されていればその条件にあったSQLの処理が走ります!

このように書けば、メソッド毎に処理を追うこともなくなり、条件が増えた場合の追加が楽、可読性向上などのメリットがあると思います!

改善点あればご教示お願い致します!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Smartyでエスケープしてかつ”nl”を改行する

探したけど、これがなかった。

{$project_name|escape|nl2br}

PS:今更感あるかも?

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

採番したUniqueIdをHtmlに含めてはいけない

採番したUniqueIdをHtmlに含めてはいけない

先日レガシーシステムでトラブルにぶつかったので。

TL;DR

  • Safariなど一部のブラウザはキャッシュがやたら強いので、採番した一意IDをHTML上の要素として渡すと過去に採番したものを持ってきてしまう可能性がある
  • クエリパラメータでキャッシュの利用を抑制したり、jsで取得するなどcacheに影響されない工夫が必要

遭遇した事象

phpを利用した申し込みシステムにおいて、毎回新規に採番されるはずのtokenが重複した場合にのみ発生するエラーがたまに発生していました。
tokenはランダム32桁の文字列+生成時刻のエポックミリ秒のため、重複することはほぼあり得ません。

tokenの出所

token自体は申し込み画面に入るタイミングでサーバーサイドで採番され、
Html上のhiddenなinputとしてブラウザ側に渡されていました。
ヘッダにno cacheはついているので、基本的に毎回新たに採番されます。

戻るボタンではない

当初は戻るボタン関連の問題かと思ったのですが、
ログに出てきたエラー時のtokenの日付を見る限り、採番後数日経ってからエラーが発生したケースもありました。
単純に申し込み後に戻ってもう一度押してしまったわけではなさそうです。

ブラウザに依存している

基本的に問題が発生しているのはiphoneのSafari。
ただし、常に発生しているわけではない。

原因

iphoneのsafariで2回目の申し込みをした場合、
1回目の申し込みのキャッシュが残っており同一番号で重複申請してしまっていた。

iphoneのSafariのcache機構はやたらと強力で、
Headerにちょっとno cacheを加えたくらいではcacheから読み込んでくるようです。

参考:
https://www.ituki-yu2.net/entry/iPhone_no_cache

対応

レガシーシステムで仕様が不明確だったので、一旦遷移時にクエリパラメータを付けて無理やりキャッシュを利用しないように対応しました。
ただ、本来はキャッシュされる可能性のある部分を使って一意識別子を渡すこと自体を本来は避けるべきです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vagrantのphpを7.2にあげる

前提

VCCW + Vagrant
ubuntu16.04.1
PHP 7.0 (多分デフォルトではPHP7.0が走っているはず)

手順

(1)Vagrant 起動

$ vagrant up
$ vagrant ssh

(2)リポジトリのインストール

$ sudo apt install software-properties-common
$ sudo add-apt-repository ppa:ondrej/php
$ sudo apt-get update

(3)PHP7.2&主要モジュールをインストール

$ sudo apt-get install php7.2 php7.2-fpm php7.2-mysql php7.2-mbstring php7.2-zip php7.2-xml libapache2-mod-php7.2

(4)確認

$ php -v
vagrant@maedag:~$ php -v
PHP 7.2.18-1+ubuntu16.04.1+deb.sury.org+1 (cli) (built: May  3 2019 09:23:41) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.2.18-1+ubuntu16.04.1+deb.sury.org+1, Copyright (c) 1999-2018, by Zend Technologies

PHP7.2になっている。

! 注意
ただしソフト側で実行されるPHPが切り替わっていないことが多い(下記スクショ)。
img2.png

(5)上記の場合、下記コマンドを実行

$ sudo apt install libapache2-mod-php7.2 #Apacheのphpモジュール 使いたいバージョンに適宜書き換えて
$ sudo a2dismod php7.0 #Apacheの旧phpモジュールのバージョンをdisable
$ sudo a2enmod php7.2 #Apacheの新phpモジュールのバージョンをenable
$ sudo service apache2 restart #apache再起動

(6)完了を確認!

img1.png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AmazonLinux2でLaravelの開発環境構築

AWSでLaravelの開発環境を構築して行きたいと思います。

前提条件として、
すでにAWSでアカウントは作成済みとしています。
また、簡単なWEBアプリケーションは作成したことがある方を対象としています

EC2の起動

まずは、AWSのコンソールからEC2を起動します。
「インスタンスの作成」をクリックすると、Amazon マシンイメージ(AMI)の選択画面になるので、Amazon Linux 2 AMI (HVM),SSD Volume Type を「選択」します。

次にインスタンスタイプの選択画面になるので、好きなインスタンスタイプを選択します。t2.microが無料利用枠の対象なので、利用できる方はこちらのタイプが良いかと思います。
私は開発環境での利用なので、今回 t3.nano を選択しました。

インスタンスの詳細の設定については、基本的には自由に設定できますが、よくわからなければ一旦全てデフォルトのままでも問題ないかと思います。
私は、そこまで頻繁に利用しない開発環境ということもあるので、スポットインスタンスのリクエストにチェックを入れて、費用を安く抑えています。スポットインスタンスは、費用を安く抑えられる反面、連続稼働を保証していないので、本番環境ではお勧めできませんので注意ください。

ストレージの追加も任意ですが、ルートの8GiBのみで進みます。

セキュリティグループの設定は、一旦最小限のセキュリティグループを作成します。

タイプ プロトコル ポート範囲 ソース
SSH TCP 22 マイIP (ご自身の接続IP)
HTTP TCP 80 カスタム 0.0.0.0/0,::/0

ターミナルへのログインのために、SSHのポートをご自身のIPで設定。
HTTPは、どこからでも閲覧可能なように設定。自分しか確認できないようにしたい場合は、HTTPのソースについてもマイIPを設定してください。

最後に、ログイン用のキーを生成して終了です。

EC2の初期設定

EC2が起動したら、ec2-userとしてログインしてみましょう。
作成したキーを .ssh/ 以下に配置しておきます。

ssh ec2-user@ec2-**-**-**-***.ap-northeast-1.compute.amazonaws.com -i ./.ssh/(秘密キー)

Laravelをセットアップする前に、ざっとEC2の設定を行います。

とりあえず、パッケージを最新に更新

$ sudo yum update -y

ec2-userのままでも良いですが、実際に利用するユーザーを作成
ユーザー名をいつも利用しているユーザー名を利用してください。説明では munakata として進めます。

$ sudo su -
# useradd munakata
# passwd munakata
# usermod -G wheel munakata

munakata に sudo権限を付与します。

# visudo

root以下に追加

visudo
## Allow root to run any commands anywhere
root    ALL=(ALL)       ALL
munakata    ALL=(ALL)       ALL

munakataのホームディレクトリ(/home/munakata) 以下の
.ssh/authorized_keys に公開鍵をセット。

すでにご自身の公開鍵はお持ちかと思いますが、まだない方は作成してください。
SSHキー等で検索すれば、いくつか情報が出てくるかと思います。

一応、権限を記載しておきます。

権限 パス
700 ~/.ssh
600 ~/.ssh/authorized_keys

これで、munakataユーザーでログインする準備は完了です。
一度ログアウトして、実際に新しいユーザーでログインしてみましょう。

ssh munakata@ec2-**-**-**-***.ap-northeast-1.compute.amazonaws.com -i ./.ssh/(munakataの秘密キー)

ローカライズ設定を行います。

タイムゾーンを日本時間にセット

/etc/sysconfig/clock
$sudo vim /etc/sysconfig/clock

ZONE="Asia/Tokyo"
UTC=false

反映には再起動が必要なので、とりあえず日本時間にセット

$ sudo cp /usr/share/zoneinfo/Japan /etc/localtime

日本語設定

/etc/sysconfig/i18n
$ sudo vim /etc/sysconfig/i18n

LANG=ja_JP.UTF-8

ここまでで、ざっとEC2の初期設定が完了です。

必要なパッケージのインストール

ここからは、AmazonLinux2でLaravelを構築するために必要なパッケージをインストールしていきます。
なるべく特殊なことはせず、ある程度AWSで用意された標準的なもので構築したいと思います。

WEBサーバーとして、apache2.4 、PHPのバージョンは、PHP7.3 を使用します。

いきなりですが、AmazonLinux2で、yumを利用してPHPをインストールするとPHP5になってしまいます。
AmazonLinuxでは、yum install php72 でPHP7.2をインストールできたのですが、AmazonLinux2には用意されていません。
その代わりに、Extra Library が用意されているようです。
Extra Library は、amazon-linux-extras で利用可能です。

php7.3をインストールしてみます。

$ sudo amazon-linux-extras php7.3

一緒に必要なパッケージもインストールされます

php-cli.x86_64 7.3.6-1.amzn2.0.1 @amzn2extra-php7.3
php-common.x86_64 7.3.6-1.amzn2.0.1 @amzn2extra-php7.3
php-fpm.x86_64 7.3.6-1.amzn2.0.1 @amzn2extra-php7.3
php-json.x86_64 7.3.6-1.amzn2.0.1 @amzn2extra-php7.3
php-mysqlnd.x86_64 7.3.6-1.amzn2.0.1 @amzn2extra-php7.3
php-pdo.x86_64 7.3.6-1.amzn2.0.1 @amzn2extra-php7.3

確認してみましょう。

$ php -v 

amazon-linux-extras でパッケージをインストールすると、拡張モジュールに関しては、yumを使って適切なパッケージをインストールしてくれるようになります。便利ですね!

実際にインストール可能な拡張モジュールを確認してみましょう。

$ sudo yum list php* | grep php7.3

必要な拡張モジュールをインストールしていきます。必要に応じて各自検討ください。
php-xmlは、Laravelインストール時に、phpunitのインストールに必要になるようなので、事前にインストールしておきましょう。

$sudo yum install php-mbstring php-pecl-memcached php-gd php-apcu php-xml

次に、apache2.4をインストールします。

AmazonLinuxの場合は、2.4系を入れる場合は、 httpd24 でしたが、AmazonLinux2の場合は、httpd で、2.4系になるようです。

$ sudo yum install httpd

起動します。

$ sudo systemctl start httpd

コンソール上には何も出力されないので、実際に動いているか確認します。
下記のコマンドで、active (running) とか表示されているはずです。

$ sudo systemctl status httpd

実際にWEBブラウザから確認してみます。

起動したEC2に、パブリックDNSが割り振られているかと思うので、そのURLで確認すると、Apacche2.4のTestPageが表示されるかと思います。

IPv4 パブリックIPでも確認可能です。

ElasticIPを紐付けた方は、そちらのIP、もしくはRoute53で設定したドメインで確認してください。

PHPの設定

この時点で、Laravelのインストール自体は可能なのですが、PHP、Apacheの細かい設定もしていきましょう。
PHPの設定は、 /etc/php.ini で行います。

設定した値を確認できるように、phpinfoの表示ページを作成しておきましょう。

設定内容は、各自調整してください。
私がよく変更する箇所は、この辺です。

php.ini
# HTTPヘッダにPHPのバージョンを記載しない(一応セキュリティ的にOffにしておいたほうが良い)
# expose_php = On
expose_php = Off

# メモリ上限を引き上げる(結構デフォルトのメモリは少なめなので増やしておくことが多い)
# memory_limit = 128M
memory_limit = 256M


# POST送信の許容サイズを引き上げる
# post_max_size = 8M
post_max_size = 16M

# アップロードファイルの許容サイズを引き上げる(スマホの写真のサイズが大きくなっているので、2Mだとほぼ画像投稿できないので増やす)
# upload_max_filesize = 2M
upload_max_filesize = 16M

# timezoneの設定
# date.timezone =
date.timezone = Asia/Tokyo

設定を反映します。

モジュール版のPHPの場合、通常httpdを再起動すると、php.iniの内容が反映されるのですが、AmazonLinux2で、PHP7.3とhttpd2.4を構築した場合、デフォルトでSever APIが FPM/FastCGI となるため、httpdでは、php.iniの設定が反映されず、php-fpmの再起動が必要となります。

php-fpmについて詳しく知りたい方は、「php-fpm」等のキーワードでお調べください。

$ sudo systemctl restart php-fpm

Laravelインストール

DocumentRootにLaravelを配置することも可能なのですが、開発環境として構築するので、今回はVirtualHostの機能を利用して、ホームディレクトリに、htmlディレクトリを作成して、その配下にLaravelプロジェクトを配置します。

まずは、Composerをインストール

curl  -sS https://getcomposer.org/installer | php

composer.phar がダウンロードされるので、composer のコマンドで実行できるように、PATHが通っている場所へ移動させます。

sudo mv composer.phar /usr/local/bin/composer

これで composer が利用できるようになったので、Laravelをインストールします。

$ cd ~/html/
$ composer create-project --prefer-dist laravel/laravel blog

これで、blogというLaravelプロジェクトが構築されます。
ただし、今回利用している t3.nano などのインスタンスタイプだと、メモリが足らずにインストールの途中に下記のエラーが出てしまいます。

mmap() failed: [12] Cannot allocate memory

そこで、ハードディスクにswap領域を作成して、メモリ不足を補います。

最初に、現状確認

$ free
              total        used        free      shared  buff/cache   available
Mem:         470512      145504      118000         104      207008      290656

とりあえず、1G程度用意すればLaravelのインストールは可能なのでswapを作成します。

$ sudo dd if=/dev/zero of=/swapfile bs=1M count=1024
$ sudo chmod 600 /swapfile
$ sudo mkswap /swapfile
$ sudo swapon /swapfile

再度、freeコマンドでSwapが追加されていれば、OKです。

$ free
              total        used        free      shared  buff/cache   available
Mem:         470512      145504      118000         104      207008      290656
Swap:       1048572       27904     1020668

これで、やっと準備が整ったので、再度

$ composer create-project --prefer-dist laravel/laravel blog

あとは、Laravelのドキュメントに記載がある通りに設定をしていきます。

$ cd ~/html/blog
$ composer update
$ chmod -R 777 bootstrap/cache
$ chmod -R 777 storage
$ php artisan key:generate

基本的には、設定ファイルは、.envになりますが、開発環境専用にする場合は、下記のようにリネームします。

$ mv .env .env.development

Apache VirtualHost 設定

最後に、ApacheのVirtualHost設定を行います。

Virtual Hostの記述は、自動で設定が読み込まれる /etc/httpd/conf.d 配下にファイルを作成して記述します。
ファイル名は任意ですが、vhost.confで作成します。

$ sudo su -
# cd /etc/httpd/conf.d
# vim vhost.conf

一旦必要な記述を記載しますが、Virtual Hostの詳しい記述方法については、他で調べてみてください。
アクセス予定のドメインは、blog.munakata.net を仮定しています。適宜変更ください。

vhost.conf
<VirtualHost *:80>
    DocumentRoot /home/munakata/html/blog/public
    ServerName blog.munakata.net
    ServerAlias blog.munakata.net
    <Directory "/home/munakata/html/blog/public">

        #.htaccessを利用可能にする
        AllowOverride All

        # Laravelで利用する環境変数を development に設定
        SetEnv APP_ENV development

        #アクセス許可
        Require all granted


    </Directory>
</VirtualHost>

httpd再起動

$ sudo systemctl restart httpd

Route53で、設定したドメインを紐付けるか、ご自身のマシンのhostsを設定して、ブラウザでアクセスしてみてください。
Laravelのトップページが表示されていれば、一旦完了です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vueをマウントできなくて奮闘

プログラミング歴3か月くらいの初心者です、自分のメモ用。

bladeファイル内になどを記載して、コンポーネントを挿入しても

app.js:38008 [Vue warn]: Failed to mount component: template or render function not defined.

found in

---> <コンポーネント名>
<Root>

上記のエラーが発生する。

app.jsにもしっかり記載している。

Vue.component('my-component', require('./components/MyComponent.vue'));

いろいろな記事を見て、webpack.config.jsに追記だの devコマンドを実行したかだのいろいろ対処法が
書かれていたがどれでも解決できないところ以下の記事を見つけた。

https://stackoverflow.com/questions/49138501/vue-warn-failed-to-mount-component-template-or-render-function-not-defined-i

どうやら app.jsで

Vue.component('my-component', require('./components/MyComponent.vue').default);

最後に.defaultを追記するだけでした。(意味は知らない)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

php-master-changes 2019-07-08

今日は exif の修正、argon2i(d) のパスワードハッシュを必要な場合 sodium から使うようにする修正、ビルドシステムのリファクタリング、ZEND_ASSIGN_DIM_OP の記述修正、com_dotnet の TsHashTable 関連の race 修正、INPUT_SESSION と INPUT_REQUEST の削除、libmagic のパッチ更新、_JIT のデバッグ用ディスアセンブラが FreeBSD / NetBSD で PHP バイナリの ELF シンボルを読む際の処理修正、base_convert() 等の基数変換関数へ無効な文字列を渡した際に deprecation notice を吐くようにする修正、スローパスで EG(exception) のチェックを遅延させるようにする修正、Mac 用のテスト修正、ドキュメントの更新、ReflectionReference::getRefcount() を実装する修正があった!

2019-07-08

smalyshev: Simplify expression and remove the possibility of div by 0

sgolemon: Provide argon2i(d) password hashing from sodium when needed

petk: Remove some unused variables

dstogov: Fixed opcode description

  • https://github.com/php/php-src/commit/1305d9c0d26c167c4cb0abcd78a5c804ad96a292
  • [7.4~]
  • ZEND_ASSIGN_DIM_OP の OP2 のタイプを修正
  • UNUSED のオペランドを何らかの形で利用する際の区別に THIS とか NEXT とか CLASS_FETCH とかを雰囲気で付けてるように見える、が、どんな時にどれ使うのかがイマイチ分からず(CLASS_FETCH は op.num をクラスフェッチで使うんだなというのは見てて分かる)
  • たぶん zend_hash_next_index_insert() につながる配列への auto_increment 使った要素追加とかそういう系に使われることの記述なのかな、という気はしている

petk: Simplify PHP_CHECK_PDO_INCLUDES calls

cmb69: Fix TsHashTable related race conditions

cmb69: Implement FR #77230: Support custom CFLAGS and LDFLAGS from environment

nikic: Remove INPUT_SESSION and INPUT_REQUEST

petk: Update libmagic patch

devnexen: JIT: Reading php binary symbols list on FreeBSD

petk: Remove C89 checks for signal.h and strerror

exussum12: Deprecate passing invalid character to base_convert etc

nikic: Remove redundant variable declaration

dstogov: Delay EG(exception) check on slow path

nikic: Make busy wait busier

petk: Refactor genif.sh

petk: Remove APACHE symbol

petk: Catch up with recent changes [ci skip]

nikic: Add ReflectionReference::getRefcount()

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む