[PHP]Laravel Valet を使った簡単なローカル環境構築

PHP のローカル環境構築行うには様々な方法がありますが、Laravel Valet を使うと複雑な設定なしに簡単に環境を構築できます。
Laravel が開発しているものですが、Laravel フレームワーク以外にも、CakePHP 3、WordPress、Symfony を始めとするほとんどの主要なフレームワークや静的HTMLファイルがサポートされています。

ここでは Mac に Valet をインストールし、サイトを立ち上げるまでを説明していきます。

PHP のインストール

まず前提として新しい PHP がインストールされている必要があるため、それらをインストールするために Homebrew を使います。
Homebrew がインストールされていない場合は下記のようにしてインストールします。

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

次に PHP をインストールします。すでにインストール済みの場合は飛ばして下さい。

brew update
brew install homebrew/php/php71

次に PHP へのパスを通します。「~/.bash_profile」に次の行を追記して下さい。

export PATH="$(brew --prefix homebrew/php/php71)/bin:$PATH"

即時反映させたい場合は「source ~/.bash_profile」で反映されます。

Valet のインストール

Valet のインストールは Composer を使って行います。こちらもインストールされていない場合は次のコマンドでインストールして下さい。

curl -sS https://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer

先程の ~/.bash_profile ファイルに Composer で使う実行ファイルのためのパスを通します。

export PATH="$PATH:$HOME/.composer/vendor/bin"

保存後、必要に応じて source コマンドで反映させて下さい。次に Valet をインストールします。

composer global require laravel/valet
valet install

Valet のインストールを終えたら、プロジェクトの親フォルダを指定します。1つ1つのプロジェクトのフォルダではなく、それらの複数のプロジェクトが格納されている親のフォルダを指定します。ここでは例として「~/Sites」を指定しします。

cd ~/Sites
valet park

valet park コマンドを実行したときのフォルダが Valet と紐付けられ、「http://フォルダ名.test」でアクセスできるようになります。

例えば hello フォルダを作って index.html ファイルを設置した場合、「http://hello.test」でその HTML ファイルが表示されます。

Laravel フレームワークのように公開フォルダとして public がサブディレクトリとして用意してある場合でも特に問題なく表示できました。独自フレームワークなどで任意の公開フォルダを指定したい場合、link コマンドで割り当てることもできます。

cd ~/Sites/my-project/web
valet link project-name

このように好きな名前(ここではproject-name)を現在のディレクトリに割り当てると「http://project-name.test」で「~/Sites/my-project/web」が表示されるようになります。
もとに戻したい場合は「valet unlink app-name」のようにします。

また、ドメイン名の *.test では不都合がある場合、valet domain コマンドで変更できます。

valet domain app

このようにすると *.app でアクセスできるようになります。

TLS を使って暗号化するには「valet secure」コマンドを使います。これにより指定したプロジェクトが「https://〜」でアクセスできるようになります。解除するには「valet unsecure」でもとに戻せます。

valet secure app-name

その他のコマンド

その他にも基本的なコマンドとして下記のものなどが用意されています。

valet forget park コマンドで登録したパスを解除する。
valet paths park コマンドで登録されているパスの確認。
valet restart Valet デーモンの再起動
valet start Valet デーモンの開始
valet stop Valet デーモンの停止
valet uninstall Valet デーモンのアンインストール

[PHP]数字に序数詞をつけて 1st, 2nd 3rd のように出力する

序数のルールは1の位が 1 であれば 1st、2 であれば 2nd、3 であれば 3rd となり、それ以外は th をつけます。
ただし、10の位が 1 の場合はすべて th がつきます。

特定の桁を取得する場合は剰余(10で割った余り)を利用すると簡単です。

以下のコードは 1〜30 の数字を序数に変換して表示するサンプルです。

<?php
for($i = 1; $i <= 30; $i++){
    echo ordinalNumber($i) . "\n";
}

function ordinalNumber( $num ){
    $n = $num % 10;
    $t = floor($num / 10) % 10;
    
    if($t === 1){
        return $num . "th";
    } else {
        switch($n) {
            case 1:
                return $num . "st";
            case 2:
                return $num . "nd";
            case 3:
                return $num . "rd";
            default:
                return $num . "th";
        }
    }
}

[PHP]料金表のようなものをテキストだけで表現する

商品名と価格、氏名と年齢などのように左右に分かれる表を PHP を使って出力する例です。
スペースを使って文字を埋めているので等幅フォントを使えば数値部分だけ右寄せしたように見せることができます。
指定した文字数を超えた場合は自動的に改行されるのでテキストメールのように1行の長さが決まっている場合に便利だと思います。
引数は (文字列1, 文字列2, 左の文字数, 右の文字数, 区切り文字) となっています。

たまねぎ        400円
牛肉          1,200円
魚沼産コシヒ  2,780円
カリ 4kg             
プチトマト      300円
<?php
function textTable($text1, $text2, $length1, $length2, $spacing=' '){
    
    $result = '';
    $text1 = breakString($text1, $length1);
    $text2 = breakString($text2, $length2);
    $lines1 = preg_split('/\R/', $text1);
    $lines2 = preg_split('/\R/', $text2);
    $lineCount1 = count($lines1);
    $lineCount2 = count($lines2);

    $maxLines = max($lineCount1, $lineCount2);
    for($i = 0; $i < $maxLines; $i++){
        $line1 = isset($lines1[$i]) ? $lines1[$i] : '';
        $line2 = isset($lines2[$i]) ? $lines2[$i] : '';
        $pad1 = str_repeat(' ', $length1 - mb_strwidth($line1));
        $pad2 = str_repeat(' ', $length2 - mb_strwidth($line2));

        $result .= $line1 . $pad1 . $spacing;
        $result .= $pad2 . $line2;

        $result .= PHP_EOL;
    }
    
    return $result;
}

function breakString($text, $length, $eol=PHP_EOL, $encoding=null){
    if( ! $encoding) $encoding = mb_internal_encoding();
    $textLen = mb_strlen($text, $encoding);
    $chars = [];
    $width = 0;
    $result = '';
    for($i = 0; $i < $textLen; $i++){
        $char = mb_substr($text, $i, 1, $encoding);
        
        if($width + mb_strwidth($char, $encoding) > $length){
            $result .= $eol . $char; 
            $width = mb_strwidth($char, $encoding);
        } else {
            $result .= $char;
            $width += mb_strwidth($char, $encoding);
        }
    }
    
    return $result;
}

$items = [
    ['たまねぎ', '400円'],
    ['牛肉', '1,200円'],
    ['魚沼産コシヒカリ 4kg', '2,780円'],
    ['プチトマト', '300円']
];
?>
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <pre style="font-family: 'Osaka-mono', 'Osaka-等幅', 'MS ゴシック', monospace;"><?php
        foreach($items as $item){
            $result = textTable($item[0], $item[1], 12, 8);
            echo htmlspecialchars($result, ENT_QUOTES, 'UTF-8');
        }
    ?></pre>
</body>
</html>