20191101のPHPに関する記事は10件です。

Laravel6.0 で バリデーションをサーバ側とクライアント側(bootstrap4 + jquery validate)で行ってみたメモ

概要

前回は一覧と作成ができることを確認した。
今回は、bootstrap4とjquery validationを使ったフロントのバリデーションも行った。

Form用ライブラリのインストール

bladeでFormを扱うのが楽になるライブラリを導入した。

composer require laravelcollective/html

Laravelでのバリデーション

migration用ファイルの作成

今回作成するマスタのテーブルを作成するモデルを作成。

<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateCouponsTable extends Migration
{
    public function up()
    {
        Schema::create('coupons', function (Blueprint $table) {
            $table->string('id');
            $table->integer('type')->default(config('const.Coupons.TYPE_GET', 1))->comment('1:取得, 2:使用');
            $table->string('name');
            $table->integer('point')->default(0);
            $table->boolean('is_display')->default(true);
            $table->timestamp('created_at')->useCurrent();
            $table->timestamp('updated_at')->default(DB::raw('CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP'));

            $table->primary('id');
        });
    }

    public function down()
    {
        Schema::dropIfExists('coupons');
    }
}

モデルの作成

以下の主キーに関する設定を行わないと、string型のidをHTMLで表示するときに0になる。

app/Models/Coupon.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;

class Coupon extends Model
{
    protected $keyType = 'string';
    public $incrementing = false; 
}

ルーティングの設定

routes/web.php
    Route::put('/tag/{tag}','Admin\TagController@update');


+    Route::get('/coupon','Admin\CouponController@index');
+    Route::post('/coupon','Admin\CouponController@store');
+    Route::put('/coupon/{coupon}','Admin\CouponController@update');
+    Route::delete('/coupon/{coupon}','Admin\CouponController@destroy');

コントローラの設定

indexではページネーションの設定を行っている。
storeではサーバサイドのバリデーションを作成時に行っている。
idがキーなので、一意であることを確認している。
updateでは上記のバリデーションは不要。
チェックボックスのデータはチェックがないときはnullになるので、
チェックがあるときの値と比較を行ってbool値をDBに格納するようにした。

app/Http/Controllers/Admin/CouponController.php
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\Coupon;
use Illuminate\Http\Request;

class CouponController extends Controller
{
    public function index()
    {
        $coupons = Coupon::orderBy('updated_at', 'DESC')->paginate(config('const.Paginator.PER_PAGE'));
        return view('admin/coupons', [
            'coupons' => $coupons,
            'types' => [ config('const.Coupons.TYPE_GET', 1) => '取得', 
                         config('const.Coupons.TYPE_USE', 2) => '使用']
        ]);
    }

    public function store(Request $request)
    {
        // bail:最初のバリデーションに失敗したら、残りのバリデーションルールの判定を停止
        $validatedData = $request->validate([
            'id' => 'bail|required|unique:coupons|max:255',
            'name' => 'bail|required|max:255',
            'point' => 'required|integer',
            'type' => 'required|integer'
        ]);

        $coupon = new Coupon();
        $coupon->id = $request->id;
        $coupon->name = $request->name;
        $coupon->point = $request->point;
        $coupon->type = $request->type;
        $coupon->is_display = $request->is_display === '1';
        $coupon->save();

        return redirect('/coupon');
    }

    public function update(Request $request, Coupon $coupon)
    {
        $validatedData = $request->validate([
            'name' => 'bail|required|max:255',
            'point' => 'required|integer',
            'type' => 'required|integer'
        ]);

        $coupon->name = $request->name;
        $coupon->point = $request->point;
        $coupon->type = $request->type;
        $coupon->is_display =  $request->is_display === '1';
        $coupon->save();

        return redirect('/coupon');
    }
    public function destroy(Coupon $coupon)
    {
        $coupon->delete();

        return redirect('/coupon');
    }
}

View

長いので非表示
resources/views/admin/coupon.blade.php
@extends('layouts.app')
@section('title') クーポン管理 @endsection
@section('admin')
  <li class="nav-item"><a class="nav-link" href="{{ url('/admin') }}">管理者ダッシュボード</span></a></li>
@endsection

@section('content')
    <div id="editModal" class="modal fade" tabindex="-1" role="dialog">
    <form id="edit-form" action="dummy{{--jsで置き換え--}}" method="POST">
        @csrf
        @method('PUT')
        <div class="modal-dialog" role="document">
          <div class="modal-content">
            <div class="modal-header">
              <h5 class="modal-title">編集</h5>
              <button type="button" class="close" data-dismiss="modal" aria-label="閉じる">
                <span aria-hidden="true">&times;</span>
              </button>
            </div>{{-- /.modal-header --}}
            <div class="modal-body">
                {{-- クーポン名 --}}
                <div class="form-group row">
                    <label for="edit-coupon-name" class="col-sm-3 col-form-label">クーポン名</label>

                    <div class="col-sm-6">
                        <input type="text" name="name" id="edit-coupon-name" class="form-control" value="{{ old('coupon') }}" required>
                        <div class="valid-feedback">
                            入力済み!
                        </div>
                    </div>
                </div>
                {{-- クーポン種別 --}}
                <div class="form-group row">
                    <label for="edit-coupon-type" class="col-sm-3 col-form-label">クーポン種別</label>

                    <div class="col-sm-6">
                          {{Form::select('type', $types, old('coupon')) }}
                    </div>
                </div>
                {{-- クーポン値 --}}
                <div class="form-group row">
                    <label for="edit-coupon-point" class="col-sm-3 col-form-label"></label>

                    <div class="col-sm-6">
                        <input type="number" name="point" id="edit-coupon-point" class="form-control" value="{{ old('coupon', 0) }}" required>
                    </div>
                </div>
                {{-- 表示フラグ --}}
                <div class="form-group row form-check">
                    <div class="col-sm-6">
                        {{Form::checkbox('is_display', true, true, ['class' => 'form-check-input', 'id'=>'edit-coupon-is_display'])}}
                        <label for="edit-coupon-is_display" class="form-check-label">表示</label>
                      </div>
                </div>
            </div>{{-- /.modal-body --}}
            <div class="modal-footer">
              <button type="button" class="btn btn-secondary" data-dismiss="modal">閉じる</button>
              <button type="submit" class="btn btn-primary">変更を保存</button>
            </div>{{-- /.modal-footer --}}
          </div>{{-- /.modal-content --}}
        </div>{{-- /.modal-dialog --}}
      </form>
    </div>{{-- /.modal --}}

    {{-- 削除モーダル--}}
    <div id="deleteModal" class="modal fade" tabindex="-1" role="dialog">
        <form id="delete-form" action="dummy" method="POST">
          @csrf
          @method('DELETE')
          <div class="modal-dialog" role="document">
            <div class="modal-content">
              <div class="modal-header">
                <h5 class="modal-title">削除</h5>
                <button type="button" class="close" data-dismiss="modal" aria-label="閉じる">
                  <span aria-hidden="true">&times;</span>
                </button>
              </div>{{-- /.modal-header --}}
              <div class="modal-body">
                <mark id="delete-item-name">{{-- 削除アイテム名 --}}</mark>を削除しますよろしいですか
              </div>{{-- /.modal-body --}}
              <div class="modal-footer">
                <button type="button" class="btn btn-secondary" data-dismiss="modal">閉じる</button>
                <button type="submit" class="btn btn-danger">削除</button>
              </div>{{-- /.modal-footer --}}
            </div>{{-- /.modal-content --}}
          </div>{{-- /.modal-dialog --}}
        </form>
      </div>{{-- /.modal --}}

    {{-- ここからメイン --}}
    <main class="container">
        <div class="col-sm-offset-2 col-sm-8">
            <div class="card">
                <div class="card-header">新しいクーポン</div>
                <div class="card-body">
                    {{-- バリデーションエラーの表示 --}}
                    @include('common.errors')

                    {{-- 新クーポンフォーム --}}
                    <form id="create-form" action="{{ url('coupon')}}" method="POST">
                        @csrf
                        {{-- クーポンID --}}
                        <div class="form-group row">
                            <label for="coupon-id" class="col-sm-3 col-form-label" >クーポンID</label>

                            <div class="col-sm-6">
                                <input type="text" name="id" id="coupon-id" class="form-control" aria-describedby="idHelpBlock" value="{{ old('coupon') }}" required>
                                <small id="idHelpBlock" class="form-text text-muted">IDは半角英数字と-_で重複しないものを入力してください</small>
                            </div>
                        </div>

                        {{-- クーポン名 --}}
                        <div class="form-group row">
                            <label for="coupon-name" class="col-sm-3 col-form-label">クーポン名</label>

                            <div class="col-sm-6">
                                <input type="text" name="name" id="coupon-name" class="form-control" value="{{ old('coupon') }}" required>
                                <div class="valid-feedback">
                                    入力済み!
                                </div>
                            </div>
                        </div>
                        {{-- クーポン種別 --}}
                        <div class="form-group row">
                            <label for="coupon-type" class="col-sm-3 col-form-label">クーポン種別</label>

                            <div class="col-sm-6">
                                 {{Form::select('type', $types, old('coupon')) }}
                            </div>
                        </div>
                        {{-- クーポン値 --}}
                        <div class="form-group row">
                            <label for="coupon-point" class="col-sm-3 col-form-label"></label>

                            <div class="col-sm-6">
                                <input type="number" name="point" id="coupon-point" class="form-control" value="{{ old('coupon', 0) }}" required>
                            </div>
                        </div>
                        {{-- 表示フラグ --}}
                        <div class="form-group row form-check">
                            <div class="col-sm-6">

                                {{Form::checkbox('is_display', true, true, ['class' => 'form-check-input', 'id'=>'coupon-is_display'])}}
                                <label for="coupon-is_display" class="form-check-label">表示</label>
                              </div>
                        </div>
                        {{-- クーポン追加ボタン --}}
                        <div class="form-group row">
                            <div class="col-sm-offset-3 col-sm-6">
                                <button type="submit" class="btn btn-primary">
                                    <i class="fa fa-btn fa-plus"></i> クーポン追加
                                </button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>

            @if (count($coupons) > 0)
                <div class="card">
                    <div class="card-header">クーポン一覧</div>
                    <div class="card-body">
                        <table class="table table-striped coupon-table">
                            {{-- テーブルヘッダ --}}
                            <thead>
                                <tr>
                                    <th>ID</th>
                                    <th>クーポン</th>
                                    <th></th>
                                    <th>種別</th>
                                    <th>表示</th>
                                    <th>更新日時</th>
                                    <th>{{-- 更新 --}}&nbsp;</th>
                                    <th>{{-- 削除 --}}&nbsp;</th>
                                </tr>
                            </thead>
                            {{-- テーブル本体 --}}
                            <tbody>
                              @foreach ($coupons as $coupon)
                                <tr>
                                    <td class="table-text">
                                        <div>{{ $coupon->id }}</div>
                                    </td>
                                  <td class="table-text">
                                      <div>{{ $coupon->name }}</div>
                                  </td>
                                  <td class="table-text">
                                      <div>{{ $coupon->point }}</div>
                                  </td>
                                  <td class="table-text">
                                      <div>{{ $types[$coupon->type]  }}</div>
                                  </td>
                                  <td class="table-text">
                                      <div>{{ $coupon->is_display ? '表示' : '隠す'  }}</div>
                                  </td>
                                  <td class="table-text">
                                      <div>{{ $coupon->updated_at->format('Y/m/d H:i:s')  }}</div>
                                  </td>
                                  <td>
                                    <button type="button" class="btn" data-toggle="modal" data-target="#editModal" 
                                            data-action="{{ url('coupon/' . $coupon->id) }}" data-name="{{$coupon->name}}" data-point="{{$coupon->point}}"
                                            data-is_display="{{$coupon->is_display}}" data-type="{{$coupon->type}}"
                                    >
                                    <i class="fa fa-btn fa-edit"></i>
                                  </button>
                                  </td>
                                  <td>
                                    <button type="button" class="btn btn-danger" data-toggle="modal" data-target="#deleteModal" 
                                      data-action="{{ url('coupon/' . $coupon->id) }}" data-name="{{$coupon->name}}"
                                    >
                                      <i class="fa fa-btn fa-trash"></i> 
                                    </button>
                                  </td>
                                </tr>
                              @endforeach
                            </tbody>
                        </table>
                    </div>
                </div>
            @endif
            {{ $coupons->links() }}
        </div>
    </div>
@endsection

@section('scripts')
<script src="https://cdn.jsdelivr.net/npm/jquery-validation@1.19.1/dist/jquery.validate.min.js" integrity="sha256-sPB0F50YUDK0otDnsfNHawYmA5M0pjjUf4TvRJkGFrI=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery-validation@1.19.1/dist/additional-methods.min.js"></script>
<script src="https://ajax.aspnetcdn.com/ajax/jquery.validate/1.19.1/localization/messages_ja.js"></script>
<script src="{{ mix('js/admin/coupon/index.js') }}"></script>
@endsection

前回やっていないのは、ページング用のタグをいれたことくらいか。

            @endif
+            {{ $coupons->links() }}
        </div>
    </div>
@endsection

クライアントサイドのバリデーション

ライブラリの追加

viewに以下を追記。
今回は一意のチェックをjquery-validationのremoteで行うので、jqueryをslimではないものにしている。
TypeError: undefined is not an object (evaluating 'b.apply'). Exception occurred when checking element , check the 'remote' method.のようなエラーがslimだと出てしまう。
また、正規表現でのチェックをpatternで行うので、additional-methodsライブラリも追加している。

resouces/views/admin/coupon.blade.php
@section('scripts')
<script src="https://cdn.jsdelivr.net/npm/jquery-validation@1.19.1/dist/jquery.validate.min.js" integrity="sha256-sPB0F50YUDK0otDnsfNHawYmA5M0pjjUf4TvRJkGFrI=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery-validation@1.19.1/dist/additional-methods.min.js"></script>
<script src="https://ajax.aspnetcdn.com/ajax/jquery.validate/1.19.1/localization/messages_ja.js"></script>
<script src="{{ mix('js/admin/coupon/index.js') }}"></script>
@endsection

トランスパイル設定

webpack.mix.js
+ mix.ts('resources/ts/admin/coupon/index.ts', 'public/js/admin/coupon').version();

typescript用の設定の追加

@types/jquery.validationはバージョンが1.16で止まっており、最新は1.19であったため使わない。
コンパイルを通すために以下の設定をおこなった。

tsconfig.json
{
    "compilerOptions": {
        "outDir": "./built/",

        // 省略


+        "typeRoots": ["./resources/ts/types", "node_modules/@types"]
    },

    "include": ["resources/ts/**/*"]
}
resouces/ts/types/index.d.ts
interface JQuery {
    validate(options: any): JQuery;
}
interface JQueryStatic {
    validator: any;
}

バリデーションの設定

検証失敗/成功時に、bootstrap4のクラスを設定するようにしている。

resources/ts/admin/coupon/index.ts
import { ModalEventHandler } from 'bootstrap';

$.validator.setDefaults({
    debug: false, // trueの場合、デバッグモードになりフォームは送信されない
    onkeyup: false, // 有効の場合はkeyupの度にremoteが走ってしまうため。。
    success: null,
    validClass: 'valid-feedback',
    errorClass: 'invalid-feedback',
    errorElement: 'span',
    errorPlacement: function(error: JQuery, element: JQuery) {
        error.addClass('invalid-feedback');
        element.closest('.form-group').append(error);
    },
    highlight: function(element: HTMLElement, errorClass: string, validClass: string) {
        $(element).addClass('is-invalid');
    },
    unhighlight: function(element: HTMLElement, errorClass: string, validClass: string) {
        $(element).removeClass('is-invalid');
    }
});
const $createForm: JQuery<HTMLFormElement> = $('#create-form');
$createForm
    .submit(event => {
        // bootstrap4のカスタムバリデーション
        const form = event.target;
        if (form.checkValidity() === false) {
            event.preventDefault();
            event.stopPropagation();
        }
        form.classList.add('was-validated');
    })
    .validate({
        rules: {
            id: {
                required: true,
                remote: '/api/coupon/unique',
                pattern: '[a-zA-Z0-9_-]+' // patternを使うにはadditonalの読み込みが必要
            },
            name: { required: true },
            point: { required: true, number: true }
        },
        messages: {
            id: {
                remote: '既に使われているIDです',
                pattern: '半角英数字と-_を使用できます'
            }
        }
    });

// 編集
$('#editModal').on('show.bs.modal', function(event: ModalEventHandler<HTMLElement>) {
    const target = event.relatedTarget;
    if (target === undefined) {
        return;
    }
    const $button = $(target); // モーダル切替えボタン
    const action = $button.data('action'); // data-* 属性から情報を抽出
    const name = $button.data('name');
    const point = $button.data('point');
    const type = $button.data('type');
    const is_display = $button.data('is_display') === 1;

    const $modal = $(this);
    $modal.find('#edit-coupon-name').val(name);
    $modal.find('#edit-coupon-type').val(type);
    $modal.find('#edit-coupon-point').val(point);
    $modal.find('#edit-coupon-is_display').prop('checked', is_display);
    $modal.find('#edit-form').attr('action', action);
});

// HTML5標準のエラーメッセージのカスタマイズ
$('#edit-coupon-name').on('invalid', e => {
    const nameInput = e.target as HTMLInputElement;
    if (nameInput.value === '') {
        nameInput.setCustomValidity('名前を入力してください。');
    }
});

// 削除
$('#deleteModal').on('show.bs.modal', function(event: ModalEventHandler<HTMLElement>) {
    const target = event.relatedTarget;
    if (target === undefined) {
        return;
    }
    const $button = $(target); // モーダル切替えボタン
    const action = $button.data('action'); // data-* 属性から情報を抽出
    const name = $button.data('name');

    const $modal = $(this);
    $modal.find('#delete-item-name').text(name);
    $modal.find('#delete-form').attr('action', action);
});

サーバ側でのチェック

jquery.validateのremoteで呼び出され、true/falseを返すAPIを作る。
バリデーションに失敗したらfalseを帰すようにする。

ルーティング設定

routes/api.php
+ Route::get('/coupon/unique','Actions\CouponAction@unique');

コントローラ

app/Http/Controllers/Actions/CouponAction.php
<?php
namespace App\Http\Controllers\Actions;
use App\Http\Controllers\Controller;
use App\Models\Coupon;
use Illuminate\Http\Request;

class CouponAction extends Controller
{
    /**
     * 存在していなければtrue。存在していればfalseを返す
     */
    public function unique(Request $request)
    {
        $result = true;
        if ($request->has('id')) {
            $result = ! Coupon::where('id', '=', $request->query('id'))->exists();
        }
        return response()->json($result);
    }
}

ここまでのソース

参考

Laravel 6.0 バリデーション
jQuery Validation
jQuery Validation Plugin が使いやすくておすすめ
jsdelivr
Laravel 6.0 Blade テンプレート
Laravel のフロントエンドに TypeScript を導入する
Laravel mix の Vue.js を TypeScript にしていく
jquery-validation
【Laravel】Model を save すると、そのインスタンスの id が 0 になることがある
'Bootsrap 4.0.0 stable' causes 'Uncaught TypeError: Cannot read property 'apply' of undefined.'
jQuery Validation サーバーに通信しての値の検証(remote)
jquery.validate.js のエラーメッセージ表示制御にハマる
jQuery Validation を Twitter Bootstrap と組み合わせて使う
validate and bootstrap4
BootStrap4 でフロントエンド完結の password 一致のバリデーションを実現する
novalidate を付与する。html5 検証と validate は同時に使用できない。
大量の Input タグがあるページで jquery validation の Submit がどえらい遅いのは options.success のせいだったかもしれない。
jQuery Validate Plugin の解説と Validate 日本語環境用 Plugin と jQuery Form Plugin との連携
mdn:input
チェックボックスを作成する
php:date
jQuery Validation Plugin を使用した時、フォームが検証済みになった時にボタンを有効にする
LaravelCollective Form ファサード チートシート

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

Apache で PHP と http2 を両方利用するための MPM の選択

おことわり

当方は専門家ではなく、自身の経験や Google に頼った結果を基にこの記事を書いています。誤りが含まれる可能性が大いにありますので、この記事の内容は参考程度に留めるようお願いします。また誤りを発見された場合はお手数をおかけしますが編集リクエストよりご指摘いただけると幸いです。

MPM の種類

Apache には現在 prefork worker event の3つの MPM が存在する。それぞれの違いについては こちら などを参考にされたし。

それぞれの対応

MPM の種類 PHP の利用 http2 の利用
prefork ◯ (mod_php) ×
worker △ (※)
event ◯ (fpm)

(※) マルチスレッドでの問題あり。こちら

以上より、Apache で PHP と http2 を同時に利用するならば MPM は event が良いことになる。

おまけ

apache で event を利用するのであれば nginx や h2o で良いのではないでしょうか。

(追記) Wordpress のために Apache 使ってたの忘れてた。Wordpress を nginx に対応させるか Apache の event で妥協するか……。

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

Moodle 3.7 マニュアル - アップグレード概要

原文

アップグレード概要

Moodl の最新で最高のバージョンの素敵な機能を次の 4つの簡単なステップでを楽しみましょう。

ステップ1: あなたのサーバで Moodle 3.7 が動作するか確かめる

(注: 3.7 にアップグレードするには、少なくとも Moodle 3.2 にアップグレードする必要があります。)

Site administration > Server > Environment に行ってください。

ステータスは全て OK ですか? 素晴らしい!では、ステップ 2 に、
何か問題がありますか? サーバのソフトウェア(PHP のような)をもっと最近のバージョンにアップグレードする必要があるかもしれません。

ステップ2: 準備しよう!

いつもの大きなアップグレードのように、あなたのデータ、あるいはあなたが追加済みのカスタムコードに何か問題があった時のために、常に "ロールバック" に備えるべきです。

A test install
テストインストール
本番サイトのコピーを作成し、アップグレードを練習することを高く推奨します。そのようにすることで、修正する事が必要な問題に遭遇した時でも、あなたのメインサイトへの影響を避けられます。

常にバックアップをとる
本番インスタンスをアップグレードするときに、万が一の時のために、確実に全てをコピーしてください。詳細なインストラクションの全体は、こちらです(原文Site backup)。

ステップ3: Moodle コードを置き換える

ここでは、あなたのサーサーバの Moodle コードをあなたがダウンロードしたバージョンのものに置き換えます。

プラグインをチェックする
あなたがインストールしたどんなプラグインも、あなたのあたらしい Moodle バージョンのために置き換えられます。プラグインに、アップデートバージョンがなかったら、あなたのサイトをアップグレードする前に、そのプラグインをアンインストールする必要があります。

ステップ4: アップグレードを実行しよう!

アップグレードを、管理者ページを訪問することで(原文visiting the admin page)はじめましょう。

もし大きなサイトを運営しているのなら、これは数時間かかるかもしれません。したがって、コマンドラインによるアップグレード(原文upgrading via command line)を推奨します。

どんな調子ですか?

はい - うまくいきました!
素晴らしい!Moodle 3.7 のプロセスを繰り返してください、そして、(原文Installation help forum)に、あなたの成功体験を Moodle コミュニティと共有しましょう!
いいえ - エラーとなりました
心配せずに。エキスパートに助けてもらいましょう。(原文 Installation help forum)で質問すると、どんなエラーに関しても説明してくれます。

参照

Upgrading アップグレードプロセスの全ての詳細な説明
Upgrading FAQ

カテゴリ:インストール

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

Laravel5.8の環境をDockerで構築する(忙しいあなたに)

忙しいあなたにチャチャっとDocker for Laravel

参考

Laravelの環境をDockerで構築するチュートリアル

概要

上で載せたDokcer for Laravelの記事がクソ有能なのでめっちゃ見させてもらってるけど、
パッて使いたい時に説明読むのしんどいので自分用まとめ記事です。

自分用なので大分言葉足りずだと思います。

環境

  • Laravel5.8
  • PHP7.3
  • MySQL57

ディレクトリ構造

appがLaravelディレクトリ

スクリーンショット 2019-11-01 17.13.05.png


docker-compose.yml

  • web:ports:が被らないようにする
  • mysql:ports:が被らないようにする
docker-compose.yml
version: '3'
services:
  web:
    image: nginx:1.15.6
    ports:
      - "8030:80"
    depends_on:
      - app
    volumes:
      - ./docker/web/default.conf:/etc/nginx/conf.d/default.conf
      - .:/var/www/html
  app:
    build: ./docker/php
    depends_on:
      - mysql
    volumes:
      - .:/var/www/html
  mysql:
    image: mysql:5.7
    environment:
      MYSQL_DATABASE: default
      MYSQL_USER: default
      MYSQL_PASSWORD: secret
      MYSQL_ROOT_PASSWORD: secret
    ports:
      - "3306:3306"
    volumes:
      - mysql-data:/var/lib/mysql
volumes:
  mysql-data:

Dockerfile

Dockerfile
FROM php:7.3-fpm

# install composer
RUN cd /usr/bin && curl -s http://getcomposer.org/installer | php && ln -s /usr/bin/composer.phar /usr/bin/composer
RUN apt-get update \
&& apt-get install -y \
git \
zip \
unzip \
vim

RUN apt-get update \
    && apt-get install -y libpq-dev \
    && docker-php-ext-install pdo_mysql pdo_pgsql

WORKDIR /var/www/html

npm使うなら以下を追記

RUN curl -sL https://deb.nodesource.com/setup_11.x | bash -
RUN apt-get install -y nodejs
RUN npm install npm@latest -g

default.conf

default.conf
server {
    listen 80;

    root  /var/www/html/app/public;
    index index.php index.html index.htm;

    access_log /var/log/nginx/access.log;
    error_log  /var/log/nginx/error.log;

    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }

    location ~ \.php$ {
          fastcgi_split_path_info ^(.+\.php)(/.+)$;
          fastcgi_pass   app:9000;
          fastcgi_index  index.php;

          include        fastcgi_params;
          fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
          fastcgi_param  PATH_INFO $fastcgi_path_info;
      }
}

実行

docker-compose up -d

何かを変更したら

docker-compose restart

Laravelインストール

上記の手順を全て終えたら仮想環境に入る

docker-compose exec app bash

Laravel5.8をComposerを使用してインストール

Laravelプロジェクト名を変更する際は最後の app 部分を任意の名前に変更する

composer create-project --prefer-dist laravel/laravel=5.8.* app

Laravel設定

DB_をdocker-compose.ymlで設定したものに変更する

.env
APP_NAME=Laravel
APP_ENV=local
APP_KEY=base64:KjL3igybtFcsPzAjU5B6WFXzMcuA3O8N5S4nA+pdGyg=
APP_DEBUG=true
APP_URL=http://localhost

LOG_CHANNEL=stack

DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=default
DB_USERNAME=default
DB_PASSWORD=secret

BROADCAST_DRIVER=log
CACHE_DRIVER=file
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120

REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379

MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null

AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=

PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1

MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"

完了

スクリーンショット 2019-11-01 18.03.00.png

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

PHPで緯度経度から8分の1メッシュコードを取得する

PHPで8分の1メッシュコードを取得する関数を作成しました

function calculateMeshCode($lon, $lat){
  $p = floor(($lat * 60) / 40);
  $a = fmod($lat * 60.0, 40);
  $q = floor($a / 5);
  $b = fmod($a, 5);
  $r = floor(($b * 60) / 30);
  $c = fmod($b * 60, 30);
  $s = floor($c / 15);
  $d = fmod($c, 15);
  $t = floor($d / 7.5);
  $e = fmod($c, 7.5);
  $tt = floor($e / 3.75);

  $u = floor($lon - 100);
  $f = $lon - 100 - $u;
  $v = floor(($f * 60) / 7.5);
  $g = fmod($f * 60, 7.5);
  $w = floor(($g * 60) / 45);
  $h = fmod($g * 60, 45);
  $x = floor($h / 22.5);
  $i = fmod($h, 22.5);
  $y = floor($i / 11.25);
  $j = fmod($h, 11.25);
  $z = floor($j / 5.625);

  $m = ($s * 2) + ($x + 1);
  $n = ($t * 2) + ($y + 1);
  $o = ($tt * 2) + ($z + 1);

  $mesh = "" . $p . $u . $q . $v . $r . $w . $m . $n . $o;

  return $mesh;
}

逆に取得したメッシュコードをmapboxに描画するやり方は地域メッシュコードから緯度経度を取得してMapboxにポリゴンを描画に記載しています。

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

【WordPress】ACFを使用し、チェックリストとテキストエリアの内容を足した文章を、特定の文字数以降は省略して表示する

なにこれ?

個人的なメモ。
ACFで作った花名をチェックリストで選択し、リストにない花名が合った場合は「、」の後に「その他の花名テキスト」を表示。
PCの時のみ、2行を超えたら「…」で省略。
しっかり自分で書いたの初めてかもしれないので、見ちゃった人は生暖かい目で見て・・・でも間違ってたら教えて下さい。

コード

ファイル名.php
<?php
    $flowers_used_name = get_field('flowers_used_name');
    $flowers_used_name = implode('、', $flowers_used_name);
    $flowers_other_name = get_field('flowers_other_name');

    //文字列
    $flowers_used_and_other = $flowers_used_name.'、'.$flowers_other_name;
    $flowers_used = $flowers_used_name;
    $flowers_other = $flowers_other_name;
    //文字数の上限
    $limit = 41;

    if(!wp_is_mobile() && get_field('flowers_other_name') && mb_strlen($flowers_used_and_other) > $limit){
        //PCで、その他の花名の入力があって、文字数が上限を超える場合 
        $txt = mb_substr($flowers_used_and_other,0,$limit);
        echo $txt."…";
    }elseif(!wp_is_mobile() && !get_field('flowers_other_name') && mb_strlen($flowers_used) > $limit){
        //PCで、その他の花名の入力がなくて、文字数が上限を超える場合 
        $txt = mb_substr($flowers_used,0,$limit);
        echo $txt."…";
    }elseif(!wp_is_mobile() && get_field('flowers_other_name') && mb_strlen($flowers_used_and_other) <= $limit){
        //PCで、その他の花名の入力があって、文字数が上限を超えない場合 
        echo $flowers_used_and_other;
    }elseif(!wp_is_mobile() && !get_field('flowers_other_name') && mb_strlen($flowers_used_and_other) <= $limit){
        //PCで、その他の花名の入力がなくて、文字数が上限を超えない場合 
        echo $flowers_used;
    }else{
        echo $flowers_used_and_other;
    }
?>

リンク

参考サイト

PHPで文字数を制限し、超過分を『…』に置き換えるコード | Webコーダーdaimaの備忘録
[Wordpress/php] implodeで連結した配列要素の区切り文字(連結文字)を指定する | KERENOR { ケレンオール }
PHP入門:echoの使い方 | サービス | プロエンジニア

ちなみに昨日プロゲートやってif周りを復習してた。
シンプルなWebサイトを作ろう PHPコース | プログラミングの入門なら基礎から学べるProgate[プロゲート]

Codex

関数リファレンス/wp is mobile - WordPress Codex 日本語版

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

LAMP環境をソースインストールする(PHP5.6.40編)

  • PHP (バージョン5.6.40)をソースからインストールします。

    • 前回のURL(ApacheのソースインストールのURL:https://qiita.com/Cch4n/items/38d72278b629e7eaf16a)
      前回に引き続きPHPをソースからインストールします。途中、再インストール等していますので、一発でソースインストールしたい方は一度すべて目を通していただけますと幸いです。
    • PHPの依存関係にあるライブラリのインストール

      参考にしたURL:http://php.net/manual/en/install.unix.apache2.php

      公式のURL:http://php.net

      • libxml2

        XMLを解析・操作するC言語のライブラリです。

        公式のURL:http://www.xmlsoft.org/

        カレントディレクトリは/usr/local/srcです。

        ソースファイルをダウンロードし、展開します。

        $ pwd
        /usr/local/src
        $ sudo wget ftp://xmlsoft.org/libxml2/libxml2-2.9.2.tar.gz
        

        展開します。

        $ sudo tar xzvf libxml2-2.9.2.tar.gz
        $ cd libxml2-2.9.2
        

        コンパイル、インストールします。

        $ cd libxml2-2.9.2
        $ sudo ./configure
        

        configureコマンドの結果、エラーが発生しました。

        libxml.c:3909: error: 'PyObject' undeclared (first use in this function)
        libxml.c:3909: error: 'module' undeclared (first use in this function)
        libxml.c:3915: warning: implicit declaration of function 'Py_InitModule'
        libxml.c:3915: warning: nested extern declaration of 'Py_InitModule'
        libxml.c:3915: error: 'libxmlMethods' undeclared (first use in this function)
        

        Pythonがインストールされていないことが原因で発生しているエラーのようです。

        本課題に限りpythonのサポートが必要なさそうなので、configureコマンド実行時のオプション--with-pythonをnoにして実行します。

        $ sudo ./configure --with-python=no
        $ sudo make
        $ sudo make install
        
    • PHPインストール

      ソースファイルをダウンロードし、展開します。

      カレントディレクトリは、/usr/local/srcです。

      $ pwd
      /usr/local/src
      $ sudo wget http://jp2.php.net/get/php-5.6.40.tar.gz/from/this/mirror
      

      展開します。

      $ sudo tar xzvf mirror
      $ cd php-5.6.40/
      
      

      PHPをインストールします。configureコマンド実行時、--with-apxs2オプションによってApacheのインストールディレクトリを指定します。

      指定が無いとPHPをApacheで使用することができません。

      また、-with-libxml-dirオプションによって依存ライブラリであるlibxmlのインストールディレクトリを指定ます。

      $ sudo ./configure --with-apxs2=/usr/local/httpd/bin/apxs --with-libxml-dir=/opt/libxm12-2.9.2
      

      コンパイル、インストールします。

      $ sudo make
      $ sudo make test
      $ sudo make install
      
    • PHP再インストール

      次の問題であるMySQLインストール完了後、再度PHPをインストールしました。

      上記configureコマンドのオプションだと後にssl通信、wordpress,mysql等でPHPを利用できません。phpizeを用いてモジュールを追加しようとしたのですが、かなりつまってしまいましたので、PHPを再コンパイルし、再インストールします。

      • 中間ファイルとインストールフォルダ消去

        カレントディレクトリは/usr/local/src/php-5.6.40です。

        $ sudo make clean
        $ sudo rm -r /usr/local/php
        
      • 必要であるライブラリ群のインストール

        まずphpモジュール用のディレクトリを作り、そこに関連するソースファイルをダウンロードします。
        カレントディレクトリは/usr/local/srcです。

        $ pwd
        /usr/local/src
        $ sudo mkdir phpmodule
        $ cd phpmodule
        

        phpmoduleディレクトリを作成しました。必要なプログラムをphpmodule下でダウンロードし、インストールします。

        • JPEG
          JPEGのエンコード、デコードを行うためのライブラリです。

          URL:http://www.ijg.org/

          カレントディレクトリは、/usr/local/src/phpmoduleです。

          同名のフォルダがないことを確認し、ソースファイルをダウンロード、展開します。

          $ pwd
          /usr/local/src/phpmodule
          $ sudo wget http://www.ijg.org/files/jpegsrc.v9c.tar.gz
          

          展開します。

          $ sudo tar xvzf jpegsrc.v9c.tar.gz
          $ cd jpeg-9c/
          

          configureコマンドの後、makeコマンドよりコンパイル、make installコマンドよりインストールします。

          $ sudo ./configure
          $ sudo make
          $ sudo make install
          
        • FreeType

          フォントエンジンを実装したライブラリです。フォント関連の様々な操作をサポートします。

          URL:https://www.freetype.org/

          カレントディレクトリは、/usr/local/src/phpmoduleです。

          ソースファイルをダウンロードし、展開します。

          $ pwd
          /usr/local/src/phpmodule
          $ sudo wget https://download.savannah.gnu.org/releases/freetype/freetype-2.9.tar.gz
          

          展開します。

          $ sudo tar xvzf freetype-2.9.tar.gz
          $ cd freetype-2.9
          

          configureコマンドの後、makeコマンドよりコンパイル、make installコマンドよりインストールします。

          $ sudo ./configure
          $ sudo make
          $ sudo make install
          

          phpから参照できるようにシンボリックリンクを作成します。

          $ sudo ln -s /usr/local/include/freetype2 /usr/local/include/freetype
          
        • libPNG

          画像データ形式のPNGエンコード・デコードを行うライブラリです。

          公式URL:http://www.libpng.org/pub/png/libpng.html

          カレントディレクトリは、/usr/local/src/phpmoduleです。

          ソースファイルをダウンロード、展開します。

          $ pwd
          /usr/local/src/phpmodule
          $ sudo wget --trust-server-names https://downloads.sourceforge.net/project/libpng/libpng16/1.6.34/libpng-1.6.34.tar.gz?r=http%3A%2F%2Fwww.libpng.org%2Fpub%2Fpng%2Flibpng.html&ts=1511065314&use_mirror=jaist
          
          

          展開します。

          $ sudo tar xvzf libpng-1.6.34.tar.gz
          

          展開されていることを確認します。

          $ cd libpng-1.6.34
          

          Makefileをscriptsディレクトリからリネームしてコピーします。

          $ sudo cp scripts/makefile.linux Makefile
          

          prefixを指定すると必要なライブラリのPathが見つからなくなるようなのでLDFLAGSによってライブラリのPathを指定します。

          $ sudo ./configure --prefix=/usr/local LDFLAGS="-L/usr/local/lib -lz"
          $ sudo make
          $ sudo make install
          
        • zlib

          データの圧縮および伸張を行うためのライブラリです。

          公式URL:https://www.zlib.net/

          カレントディレクトリは、/usr/local/src/phpmoduleです。

          同名のフォルダがないことを確認し、ソースファイルをダウンロード、展開します。

          $ pwd
          /usr/local/src/phpmodule
          $ sudo wget http://zlib.net/zlib-1.2.11.tar.gz
          

          展開します。

          $ sudo tar xvzf zlib-1.2.11.tar.gz
          $ cd zlib-1.2.11
          

          configureコマンドの後、makeコマンドよりコンパイル、make installコマンドよりインストールします。

          $ sudo ./configure
          $ sudo make
          $ sudo make install
          
        • m4

          autoconfの依存ライブラリです。

          公式URL:https://www.gnu.org/software/m4/

          カレントディレクトリは、/usr/local/src/phpmoduleです。

          ソースファイルをダウンロード、展開します。

          $ pwd
          /usr/local/src/phpmodule
          $ sudo wget http://ftp.gnu.org/gnu/m4/m4-1.4.18.tar.gz
          

          展開します。

          $ sudo tar xvzf m4-1.4.18.tar.gz
          $ cd m4-1.4.18
          

          カレントディレクトリを展開フォルダに移し、configureコマンドの後、makeコマンドよりコンパイル、make installコマンドよりインストールします。

          $ cd m4-1.4.18/
          $ sudo ./configure
          $ sudo make
          $ sudo make install
          
        • autoconf

          configureスクリプトの自動生成ツールです。

          公式URL:https://www.gnu.org/software/automake/

          カレントディレクトリは、/usr/local/src/phpmoduleです。
          同名のフォルダがないことを確認後、ソースファイルをダウンロードし、展開します。

          $ pwd
          /usr/local/src/phpmodule
          $ sudo wget http://ftp.gnu.org/gnu/autoconf/autoconf-2.69.tar.gz
          $ find autoconf-2.69.tar.gz 
          autoconf-2.69.tar.gz
          

          展開します。

          $ sudo tar xvzf autoconf-2.69.tar.gz
          $ cd autoconf-2.69

          カレントディレクトリを展開フォルダに移し、configureコマンドの後、makeコマンドよりコンパイル、make installコマンドよりインストールします。

          $ cd autoconf-2.69/
          $ sudo ./configure
          $ sudo make
          $ sudo make install
          
        • libiconv

          異なる文字コード間の相互変換を行う標準APIです。

          公式URL:https://www.gnu.org/software/libiconv/

          カレントディレクトリは、/usr/local/src/phpmoduleです。

          ソースファイルをダウンロードし、展開します。

          $ pwd
          /usr/local/src/phpmodule
          $ sudo wget https://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.15.tar.gz
          

          展開します。

          $ sudo tar xvzf libiconv-1.15.tar.gz
          $ cd libiconv-1.15
          

          カレントディレクトリを展開フォルダに移し、configureコマンドの後、makeコマンドよりコンパイル、make installコマンドよりインストールします。

          $ cd libiconv-1.15/
          $ sudo ./configure
          $ sudo make
          $ sudo make install
          
        • libGD

          GDはイメージを動的に操作するライブラリです。

          公式URL:https://libgd.github.io/

          カレントディレクトリは、/usr/local/src/phpmoduleです。

          ソースファイルをダウンロード、展開します。

          $ pwd
          /usr/local/src/phpmodule
          $ sudo wget https://github.com/libgd/libgd/releases/download/gd-2.2.5/libgd-2.2.5.tar.gz
          

          展開します。

          $ sudo tar xvzf libgd-2.2.5.tar.gz
          

          展開されていることを確認します。

          $ cd libgd-2.2.5
          

          カレントディレクトリを展開フォルダに移し、Makefileをscriptsディレクトリからリネームしてコピーします。

          $ cd libgd-2.2.5/
          $ sudo cp scripts/makefile.linux Makefile
          

          configureコマンド実行時のオプション--withで、png、freetype、jpeg、xpm、libconvのインストールされているフォルダを指定します。
          その後、makeコマンドよりコンパイル、make installコマンドよりインストールします。

          $ sudo ./configure 
                  --with-png=/usr/local 
                --with-freetype=/usr/local 
                  --with-jpeg=/usr/local 
                  --with-xpm=/usr 
                  --with-libiconv-prefix=/usr/local
          $ sudo make
          $ sudo make install
          
        • cURL

          さまざまなプロトコルを用いてデータを転送するライブラリとコマンドラインツールを提供します。

          公式URL:https://curl.haxx.se/

          カレントディレクトリは、/usr/local/src/phpmoduleです。

          ソースファイルをダウンロード、展開し、カレントディレクトリを展開先フォルダへ移動させます。

          $ pwd
          /usr/local/src/phpmodule
          $ sudo wget https://curl.haxx.se/download/curl-7.58.0.tar.gz
          

          展開します。

          $ sudo tar xvzf curl-7.58.0.tar.gz
          

          LDFLAGSによってライブラリのPathを、CPPFLAGSによってプリプロセッサのPathを指定します。

          $ CPPFLAGS="-I/usr/local/ssl/include" LDFLAGS="-L/usr/local/ssl/lib"
          

          configureコマンド時のオプション --enable-http --enable-cookies によりhttpとcookieがサポートされるようにします。またzlib、ssl、libssh2、のインストールされているディレクトリを指定します。

          $ sudo ./configure 
                  --enable-http 
                  --enable-cookies 
                  --with-zlib=/usr/local 
                  --with-ssl=/usr/local/ssl 
                  --with-libssh2=/usr/local
          

          makeコマンドよりコンパイル、make installコマンドよりインストールします

          $ sudo make
          $ sudo make install
          

      PHPのインストールにもどります。

      カレントディレクトリは、/usr/local/src/php-5.6.40です。

      configureコマンド実行時、オプション--with-apx2でApacheのインストールディレクトリ下のapxsディレクトリを指定し、PHPをApacheで使用できるように
      します。

      日本語フォントを扱うためにオプション--enable-gd-jis-convをつけます。

      gd,freetype,jpeg,zlib,libxml,xpm,curl,opensslのインストールディレクトリを指定します。

      PHPでmysqlを使用できるように、オプション--with-mysql-sockよりソケットファイルのPathを指定します。
      また、後の課題にてmysqli関数やpdo関数使用するため、オプション--with-pdo-mysql --with-mysqliオプションでmysqlのインストールディレクトリを指
      定します。

      $ sudo ./configure  
      --with-apxs2=/usr/local/httpd/bin/apxs
      --with-gd=/usr/local
      --with-freetype-dir=/usr/local/src/phpmodule/freetype-2.7
      --with-jpeg-dir=/usr/local/lib --with-png-dir=/usr/local
      --with-zlib-dir=/usr
      --with-libxml-dir=/usr/local
      --enable-gd-jis-conv
      --with-curl=/usr/local
      --with-openssl=/usr/local/ssl
      --with-xpm-dir=/usr
      --with-mysqli=/usr/local/mysql/bin/mysql_config
      --with-pdo-mysql=/usr/local/mysql
      --with-mysql-sock=/tmp/mysql.sock
      --with-iconv-dir=/usr/local
      

      makeコマンドよりコンパイル、make installコマンドよりインストールします。

      $ sudo make
      $ sudo make install
      

      PHPのモジュールを読み込めるよう設定がなされているかApacheの設定ファイルから確認します。

      $ pwd
      /usr/local/httpd/conf
      $ vim httpd.conf
      #一部抜粋、下記の表記があることを確認する。
      LoadModule php5_module        modules/libphp5.so
      
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LAMP環境をソースインストールする(PHP5.6.40)

  • PHP (バージョン5.6.40)をソースからインストールします。
    前回に引き続きPHPをソースからインストールします。途中、再インストール等していますので、一発でソースインストールしたい方は一度すべて目を通していただけますと幸いです。

    • PHPの依存関係にあるライブラリのインストール

      参考にしたURL:http://php.net/manual/en/install.unix.apache2.php

      公式のURL:http://php.net

      • libxml2

        XMLを解析・操作するC言語のライブラリです。

        公式のURL:http://www.xmlsoft.org/

        カレントディレクトリは/usr/local/srcです。

        ソースファイルをダウンロードし、展開します。

        $ pwd
        /usr/local/src
        $ sudo wget ftp://xmlsoft.org/libxml2/libxml2-2.9.2.tar.gz
        

        展開します。

        $ sudo tar xzvf libxml2-2.9.2.tar.gz
        $ cd libxml2-2.9.2
        

        コンパイル、インストールします。

        $ cd libxml2-2.9.2
        $ sudo ./configure
        

        configureコマンドの結果、エラーが発生しました。

        libxml.c:3909: error: 'PyObject' undeclared (first use in this function)
        libxml.c:3909: error: 'module' undeclared (first use in this function)
        libxml.c:3915: warning: implicit declaration of function 'Py_InitModule'
        libxml.c:3915: warning: nested extern declaration of 'Py_InitModule'
        libxml.c:3915: error: 'libxmlMethods' undeclared (first use in this function)
        

        Pythonがインストールされていないことが原因で発生しているエラーのようです。

        本課題に限りpythonのサポートが必要なさそうなので、configureコマンド実行時のオプション--with-pythonをnoにして実行します。

        $ sudo ./configure --with-python=no
        $ sudo make
        $ sudo make install
        
    • PHPインストール

      ソースファイルをダウンロードし、展開します。

      カレントディレクトリは、/usr/local/srcです。

      $ pwd
      /usr/local/src
      $ sudo wget http://jp2.php.net/get/php-5.6.40.tar.gz/from/this/mirror
      

      展開します。

      $ sudo tar xzvf mirror
      $ cd php-5.6.40/
      
      

      PHPをインストールします。configureコマンド実行時、--with-apxs2オプションによってApacheのインストールディレクトリを指定します。

      指定が無いとPHPをApacheで使用することができません。

      また、-with-libxml-dirオプションによって依存ライブラリであるlibxmlのインストールディレクトリを指定ます。

      $ sudo ./configure --with-apxs2=/usr/local/httpd/bin/apxs --with-libxml-dir=/opt/libxm12-2.9.2
      

      コンパイル、インストールします。

      $ sudo make
      $ sudo make test
      $ sudo make install
      
    • PHP再インストール

      次の問題であるMySQLインストール完了後、再度PHPをインストールしました。

      上記configureコマンドのオプションだと後にssl通信、wordpress,mysql等でPHPを利用できません。phpizeを用いてモジュールを追加しようとしたのですが、かなりつまってしまいましたので、PHPを再コンパイルし、再インストールします。

      • 中間ファイルとインストールフォルダ消去

        カレントディレクトリは/usr/local/src/php-5.6.40です。

        $ sudo make clean
        $ sudo rm -r /usr/local/php
        
      • 必要であるライブラリ群のインストール

        まずphpモジュール用のディレクトリを作り、そこに関連するソースファイルをダウンロードします。
        カレントディレクトリは/usr/local/srcです。

        $ pwd
        /usr/local/src
        $ sudo mkdir phpmodule
        $ cd phpmodule
        

        phpmoduleディレクトリを作成しました。必要なプログラムをphpmodule下でダウンロードし、インストールします。

        • JPEG
          JPEGのエンコード、デコードを行うためのライブラリです。

          URL:http://www.ijg.org/

          カレントディレクトリは、/usr/local/src/phpmoduleです。

          同名のフォルダがないことを確認し、ソースファイルをダウンロード、展開します。

          $ pwd
          /usr/local/src/phpmodule
          $ sudo wget http://www.ijg.org/files/jpegsrc.v9c.tar.gz
          

          展開します。

          $ sudo tar xvzf jpegsrc.v9c.tar.gz
          $ cd jpeg-9c/
          

          configureコマンドの後、makeコマンドよりコンパイル、make installコマンドよりインストールします。

          $ sudo ./configure
          $ sudo make
          $ sudo make install
          
        • FreeType

          フォントエンジンを実装したライブラリです。フォント関連の様々な操作をサポートします。

          URL:https://www.freetype.org/

          カレントディレクトリは、/usr/local/src/phpmoduleです。

          ソースファイルをダウンロードし、展開します。

          $ pwd
          /usr/local/src/phpmodule
          $ sudo wget https://download.savannah.gnu.org/releases/freetype/freetype-2.9.tar.gz
          

          展開します。

          $ sudo tar xvzf freetype-2.9.tar.gz
          $ cd freetype-2.9
          

          configureコマンドの後、makeコマンドよりコンパイル、make installコマンドよりインストールします。

          $ sudo ./configure
          $ sudo make
          $ sudo make install
          

          phpから参照できるようにシンボリックリンクを作成します。

          $ sudo ln -s /usr/local/include/freetype2 /usr/local/include/freetype
          
        • libPNG

          画像データ形式のPNGエンコード・デコードを行うライブラリです。

          公式URL:http://www.libpng.org/pub/png/libpng.html

          カレントディレクトリは、/usr/local/src/phpmoduleです。

          ソースファイルをダウンロード、展開します。

          $ pwd
          /usr/local/src/phpmodule
          $ sudo wget --trust-server-names https://downloads.sourceforge.net/project/libpng/libpng16/1.6.34/libpng-1.6.34.tar.gz?r=http%3A%2F%2Fwww.libpng.org%2Fpub%2Fpng%2Flibpng.html&ts=1511065314&use_mirror=jaist
          
          

          展開します。

          $ sudo tar xvzf libpng-1.6.34.tar.gz
          

          展開されていることを確認します。

          $ cd libpng-1.6.34
          

          Makefileをscriptsディレクトリからリネームしてコピーします。

          $ sudo cp scripts/makefile.linux Makefile
          

          prefixを指定すると必要なライブラリのPathが見つからなくなるようなのでLDFLAGSによってライブラリのPathを指定します。

          $ sudo ./configure --prefix=/usr/local LDFLAGS="-L/usr/local/lib -lz"
          $ sudo make
          $ sudo make install
          
        • zlib

          データの圧縮および伸張を行うためのライブラリです。

          公式URL:https://www.zlib.net/

          カレントディレクトリは、/usr/local/src/phpmoduleです。

          同名のフォルダがないことを確認し、ソースファイルをダウンロード、展開します。

          $ pwd
          /usr/local/src/phpmodule
          $ sudo wget http://zlib.net/zlib-1.2.11.tar.gz
          

          展開します。

          $ sudo tar xvzf zlib-1.2.11.tar.gz
          $ cd zlib-1.2.11
          

          configureコマンドの後、makeコマンドよりコンパイル、make installコマンドよりインストールします。

          $ sudo ./configure
          $ sudo make
          $ sudo make install
          
        • m4

          autoconfの依存ライブラリです。

          公式URL:https://www.gnu.org/software/m4/

          カレントディレクトリは、/usr/local/src/phpmoduleです。

          ソースファイルをダウンロード、展開します。

          $ pwd
          /usr/local/src/phpmodule
          $ sudo wget http://ftp.gnu.org/gnu/m4/m4-1.4.18.tar.gz
          

          展開します。

          $ sudo tar xvzf m4-1.4.18.tar.gz
          $ cd m4-1.4.18
          

          カレントディレクトリを展開フォルダに移し、configureコマンドの後、makeコマンドよりコンパイル、make installコマンドよりインストールします。

          $ cd m4-1.4.18/
          $ sudo ./configure
          $ sudo make
          $ sudo make install
          
        • autoconf

          configureスクリプトの自動生成ツールです。

          公式URL:https://www.gnu.org/software/automake/

          カレントディレクトリは、/usr/local/src/phpmoduleです。
          同名のフォルダがないことを確認後、ソースファイルをダウンロードし、展開します。

          $ pwd
          /usr/local/src/phpmodule
          $ sudo wget http://ftp.gnu.org/gnu/autoconf/autoconf-2.69.tar.gz
          $ find autoconf-2.69.tar.gz 
          autoconf-2.69.tar.gz
          

          展開します。

          $ sudo tar xvzf autoconf-2.69.tar.gz
          $ cd autoconf-2.69

          カレントディレクトリを展開フォルダに移し、configureコマンドの後、makeコマンドよりコンパイル、make installコマンドよりインストールします。

          $ cd autoconf-2.69/
          $ sudo ./configure
          $ sudo make
          $ sudo make install
          
        • libiconv

          異なる文字コード間の相互変換を行う標準APIです。

          公式URL:https://www.gnu.org/software/libiconv/

          カレントディレクトリは、/usr/local/src/phpmoduleです。

          ソースファイルをダウンロードし、展開します。

          $ pwd
          /usr/local/src/phpmodule
          $ sudo wget https://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.15.tar.gz
          

          展開します。

          $ sudo tar xvzf libiconv-1.15.tar.gz
          $ cd libiconv-1.15
          

          カレントディレクトリを展開フォルダに移し、configureコマンドの後、makeコマンドよりコンパイル、make installコマンドよりインストールします。

          $ cd libiconv-1.15/
          $ sudo ./configure
          $ sudo make
          $ sudo make install
          
        • libGD

          GDはイメージを動的に操作するライブラリです。

          公式URL:https://libgd.github.io/

          カレントディレクトリは、/usr/local/src/phpmoduleです。

          ソースファイルをダウンロード、展開します。

          $ pwd
          /usr/local/src/phpmodule
          $ sudo wget https://github.com/libgd/libgd/releases/download/gd-2.2.5/libgd-2.2.5.tar.gz
          

          展開します。

          $ sudo tar xvzf libgd-2.2.5.tar.gz
          

          展開されていることを確認します。

          $ cd libgd-2.2.5
          

          カレントディレクトリを展開フォルダに移し、Makefileをscriptsディレクトリからリネームしてコピーします。

          $ cd libgd-2.2.5/
          $ sudo cp scripts/makefile.linux Makefile
          

          configureコマンド実行時のオプション--withで、png、freetype、jpeg、xpm、libconvのインストールされているフォルダを指定します。
          その後、makeコマンドよりコンパイル、make installコマンドよりインストールします。

          $ sudo ./configure 
                  --with-png=/usr/local 
                --with-freetype=/usr/local 
                  --with-jpeg=/usr/local 
                  --with-xpm=/usr 
                  --with-libiconv-prefix=/usr/local
          $ sudo make
          $ sudo make install
          
        • cURL

          さまざまなプロトコルを用いてデータを転送するライブラリとコマンドラインツールを提供します。

          公式URL:https://curl.haxx.se/

          カレントディレクトリは、/usr/local/src/phpmoduleです。

          ソースファイルをダウンロード、展開し、カレントディレクトリを展開先フォルダへ移動させます。

          $ pwd
          /usr/local/src/phpmodule
          $ sudo wget https://curl.haxx.se/download/curl-7.58.0.tar.gz
          

          展開します。

          $ sudo tar xvzf curl-7.58.0.tar.gz
          

          LDFLAGSによってライブラリのPathを、CPPFLAGSによってプリプロセッサのPathを指定します。

          $ CPPFLAGS="-I/usr/local/ssl/include" LDFLAGS="-L/usr/local/ssl/lib"
          

          configureコマンド時のオプション --enable-http --enable-cookies によりhttpとcookieがサポートされるようにします。またzlib、ssl、libssh2、のインストールされているディレクトリを指定します。

          $ sudo ./configure 
                  --enable-http 
                  --enable-cookies 
                  --with-zlib=/usr/local 
                  --with-ssl=/usr/local/ssl 
                  --with-libssh2=/usr/local
          

          makeコマンドよりコンパイル、make installコマンドよりインストールします

          $ sudo make
          $ sudo make install
          

      PHPのインストールにもどります。

      カレントディレクトリは、/usr/local/src/php-5.6.40です。

      configureコマンド実行時、オプション--with-apx2でApacheのインストールディレクトリ下のapxsディレクトリを指定し、PHPをApacheで使用できるように
      します。

      日本語フォントを扱うためにオプション--enable-gd-jis-convをつけます。

      gd,freetype,jpeg,zlib,libxml,xpm,curl,opensslのインストールディレクトリを指定します。

      PHPでmysqlを使用できるように、オプション--with-mysql-sockよりソケットファイルのPathを指定します。
      また、後の課題にてmysqli関数やpdo関数使用するため、オプション--with-pdo-mysql --with-mysqliオプションでmysqlのインストールディレクトリを指
      定します。

      $ sudo ./configure  
      --with-apxs2=/usr/local/httpd/bin/apxs
      --with-gd=/usr/local
      --with-freetype-dir=/usr/local/src/phpmodule/freetype-2.7
      --with-jpeg-dir=/usr/local/lib --with-png-dir=/usr/local
      --with-zlib-dir=/usr
      --with-libxml-dir=/usr/local
      --enable-gd-jis-conv
      --with-curl=/usr/local
      --with-openssl=/usr/local/ssl
      --with-xpm-dir=/usr
      --with-mysqli=/usr/local/mysql/bin/mysql_config
      --with-pdo-mysql=/usr/local/mysql
      --with-mysql-sock=/tmp/mysql.sock
      --with-iconv-dir=/usr/local
      

      makeコマンドよりコンパイル、make installコマンドよりインストールします。

      $ sudo make
      $ sudo make install
      

      PHPのモジュールを読み込めるよう設定がなされているかApacheの設定ファイルから確認します。

      $ pwd
      /usr/local/httpd/conf
      $ vim httpd.conf
      #一部抜粋、下記の表記があることを確認する。
      LoadModule php5_module        modules/libphp5.so
      
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

保存版 JavaScript <=> PHP の文字列操作対応リスト

フロントエンドとバックエンドにおいては分業が当たり前のこのご時世ですが、僕はちょうどお互い半々で仕事を頂けているので備忘録も兼ねて対応表を作成しました。

普段自分が担当している分野の反対側を扱わなくてはならなくなったときや、一人でフロント・バック両方開発するとき、もしくは暇つぶしにどうぞ。

※目次・各項目に書いてあるコードは JavaScript, PHP の順です。

追加・結合

結合 'hoge'+'fuga', 'hoge'.'fuga'

sample.js
'hoge'+'fuga';
//'hogefuga'
sample.php
'hoge'.'fuga';
//'hogefuga'

最も基本的かつよく使う文字列を繋げる処理ですが、この時点で JavaScript と PHP の差を感じます。

普段 JavaScript を使用している開発者には違和感を感じる「.」での連結ですが、これは PHP が Perl に影響を受けて開発されたことによるものと思われます。
PHP 公式マニュアル: PHP の歴史

PHP でも数値の加算には「+」を使うのですが、個人的には数値の加算なのか文字列の連結なのかを明示的に指定できるので便利に感じています。そもそも変数の型は安全に把握しておくべきですが……。

なお、JavaScript には concat() も用意されていますが、MDN でも説明されている通り、パフォーマンス的によろしくないので普通に「+」を使用した方が良いでしょう。

追加 'hoge'+='fuga', 'hoge'.='fuga'

sample.js
let str = 'hoge';
str += 'fuga';
//'hogefuga'
sample.php
$str = 'hoge';
$str .= 'fuga';
//'hogefuga'

どちらも結合時に使用した演算子に「=」を付けることで追加を行うことができます。

ところで、文字列を追加するときには上記の方法以外にも、

sample.js
let str = 'hoge';
str = str+'fuga';
sample.php
$str = 'hoge';
$str = $str.'fuga';

という書き方がありますが、結果は同じでも JavaScript 側のみ、下の方が処理速度が速い傾向にあるようです。

指定した文字数まで特定の文字で埋める(末尾へ追加) 'hoge'.padEnd(10, 'e'), str_pad('hoge', 10, 'e')

sample.js
'hoge'.padEnd(10, 'e');
//'hogeeeeeee'
sample.php
str_pad('hoge', 10, 'e');
//'hogeeeeeee'

どちらも計10文字になるまで 'hoge' の末尾に 'e' を追加を追加し、結果 'hogeeeeeee' を得るコードです。

この後も同じようなコードが沢山登場しますが、PHP 使いからすると、PHP では関数の引数として文字列を仕込むのに対し、JavaScript では文字列にメソッドが生えているのに違和感を感じるところですね。

JavaScript の文字列は大抵「String グローバルオブジェクト」というものを継承しているので、PHP のインスタンスのようにメソッドが生えているのです。

MDN: String

どちらも指定した文字数より元の文字数の方が長い場合、元の文字列がそのまま返されます。文字数までカットされるわけではないので注意しましょう。

ちなみに padEnd() は IE で動かないので使用する場合は Polyfill をお忘れなく。
MDN: String.prototype.padEnd()

指定した文字数まで特定の文字で埋める(先頭へ追加) 'hoge'.padStart(10, 'h'), str_pad('hoge', 10, 'h', STR_PAD_RIGHT)

sample.js
'hoge'.padStart(10, 'e');
//'eeeeeehoge'
sample.php
str_pad('hoge', 10, 'e', STR_PAD_LEFT);
//'eeeeeehoge'

JavaScript は別のメソッドを使用することになるのに対し、PHP では str_pad() 関数の第四引数に STR_PAD_LEFT を指定することで先頭への追加を行えます。

先の例では省略されていた str_pad() 関数の第四引数ですが、実はデフォルト値として STR_PAD_RIGHT 定数が定義されているので文字列が末尾に追加されていたのです。

なお、STR_PAD_LEFT などの定数は PHP が自動的に設定する定数で、特に開発者が定義することなく安心して使えます。
PHP マニュアル: 定義済み定数(文字列)

例によって padStart() は IE で動かないので使用する場合は Polyfill をお忘れなく。

同じ文字を指定回数結合した文字列を生成 'hoge'.repeat(10), str_repeat('hoge', 10)

sample.js
'hoge'.repeat(10);
//'hogehogehogehogehogehogehogehogehogehoge'
sample.php
str_repeat('hoge', 10);
//'hogehogehogehogehogehogehogehogehogehoge'

同じ文字列を指定回数結合した文字列を生成する関数です。どちらも指定回数に 0 を指定すると空文字を返します。

例によって repeat() は IE で動かないので使用する場合は Polyfill をお忘れなく。MDN によると Android でも動かないとのことです。
MDN: String.prototype.repeat()

判定・情報取得

文字数取得 'hoge'.length, mb_strlen('hoge')

sample.js
'hoge'.length;
//4
sample.php
mb_strlen('hoge');
//4

JavaScript 側はクラス風に言えばメソッドではなくプロパティなので () は不要です。

PHP で文字列操作をしていると頻繁に登場する「mb_○○○」系の関数ですが、「mb_」が付いていない関数とはマルチバイト文字を考慮するかしないかの違いがあります。

たとえば mb_strlen('ほげ') は「2」を返すのに対し、 strlen('ほげ') は「6」を返します。これは  strlen('ほげ') が返すのが、正確には文字数ではなくバイト数なのが原因です。

英語圏では絵文字でも使わない限り特に意識せずにコーディングしても影響なさそうですが、文字数を主眼に操作を行う場合は意識して「mb_○○○」系の関数を使用するようにしましょう。

特定の文字が現れる位置を取得する 'hoge'.indexOf('og'), strpos('hoge', 'og')

sample.js
'hoge'.indexOf('og');
//1
sample.php
strpos('hoge', 'og');
//1

どちらも先頭を「0」として数え始めるので「'hoge'」の中にある「'og'」の位置は「1」となります。

両者の決定的な差は検索結果が無かった場合の返り値で、indexOf() の場合は -1strpos() の場合は false です。
これについては次項で詳しく説明します。

特定の文字が含まれているか判定する 'hoge'.indexOf('og') !== -1, strpos('hoge', 'og') !== false

直感的には、「文字列中に特定の文字列が存在するか」を判定する際には正規表現を使う方法が考え付くと思います。
しかし、JavaScript でも PHP でもこれを判定する最速の方法は前項で説明した関数の返り値を使用する方法です(もちろん、静的な文字列ではなく、正規表現における . 等を表現する場合などは正規表現を使用することになります)。

そのためそれぞれのメソッド・関数が「一致無し」の場合に返す値を利用するのですが indexOf() の場合は -1strpos() の場合は false になるので、それを === で比較します。

注意すべきは PHP 側で、strpos()0 を返す場合があり、これは緩い比較では false と同義になってしまう falsy な値であるためしっかり === false で判定しないと意図しない挙動となってしまいます。

正規表現にマッチするか判定する 'hoge'.match(/^h.+e$/), preg_match('\A^h.+e\z/', 'hoge')

sample.js
'hoge'.match(/^h.+e$/);
//['hoge', index: 0, input: 'hoge']
sample.php
preg_match('\A^h.+e\z/', 'hoge');
//1

プログラミングをするなら避けて通れない正規表現ですが、JavaScript ・ PHP の両者にももちろん正規表現を扱うメソッド・関数が用意されています。

ただし、PHP 側では文字列を正規表現として扱うのに対し、JavaScript では RegExp オブジェクトを使用します。
上記サンプル中、PHP 側の正規表現は文字列なのに対し、JavaScript 側はクオーテーションで囲われていない正規表現を使用している点に注目してください。
これは JavaScript においては / で括った文字は RegExp リテラルとして扱われることを表しています。

PHP 側では文字列を表すクォーテーションの中で、さらに正規表現を / で括っていますが、これは「preg_○○○」系の関数では必須となるデリミタとなります。
JavaScript では / 固定ですが、PHP では / に限らず @ や {} なども使用できます。 URL 等を扱う場合はデリミタに / を使用すると正規表現中の / をエスケープする手間が発生するため、正規表現中に出現しない文字をデリミタに使用したほうが良いでしょう。
PHP マニュアル: PCRE はじめに

マッチすることを判定するだけなら両者とも if() の中に入れれば用をなしますが、返り値は全く異なります。

.match() はマッチした場合に様々な情報が入った配列を返します。

グローバル (g) フラグの有無によって内容が変わる Array を返します。マッチが見つからなかった場合は null を返します。
g フラグがある場合、キャプチャグループを除いた、正規表現にマッチしたすべての結果を返します。
g フラグがない場合、最初のマッチとそれに対するキャプチャグループのみを返します。この場合、返される要素には下記の「追加されるプロパティ」が存在します。
MDN: String.prototype.match()

マッチしなかった場合は null を返すため、if() での判定が行えるわけですね。

対して preg_match() ではマッチした場合は 1、マッチしなかった場合は 0 を返します(エラー時は false)。
特定の文字列を抜き出すためにマッチ系のメソッド・関数を使用する場合、.match() では返り値の配列が使用できますが、上記のとおり preg_match() の返り値はその用途に使用できません。

この場合は第三引数に変数を仕込むと参照渡しでマッチ内容の配列が挿入されます。

matches を指定した場合、検索結果が代入されます。\$matches[0] にはパターン全体にマッチしたテキストが代入され、 $matches[1] には 1 番目のキャプチャ用サブパターンにマッチした 文字列が代入され、といったようになります。

PHP マニュアル: preg_match

ところで PHP 側で登場している \A\z ですが、何故 ^$ を使用していないかというとセキュリティ的に問題があるからです。
正規表現をセキュリティに関わる処理に使用しているかどうかは実装次第ですが、PHP で正規表現を扱う場合は基本的に ^$ を使用しないクセを付けておいた方が無難かと思われます。
徳丸浩の日記: 正規表現によるバリデーションでは ^ と $ ではなく \A と \z を使おう

置換・削除・整形

両端の空白を削除する ' hoge '.trim(), trim(' hoge ')

sample.js
'        hoge        '.trim();
//'hoge'
sample.php
trim('        hoge        ');
//'hoge'

メソッドなのか関数なのかという違い以外は同じノリで使える両者ですが、実は PHP 側は追加の引数が指定可能です。

sample.php
trim('ふがふがふがhogeふがふがふが', 'ふが');
//'hoge'

デフォルトでは空白文字を除去する trim() 関数ですが、第二引数を指定した場合はその文字を両端から削除します。便利ですね。

先頭か末尾の空白を削除する ' hoge'.trimStart() or 'hoge '.trimEnd(), ltrim(' hoge') or rtrim('hoge ')

sample.js
'        hoge'.trimStart();
//'hoge'

'hoge        '.trimEnd();
//'hoge'
sample.php
ltrim('        hoge');
//'hoge'

rtrim('hoge        ');
//'hoge'

名前が違いますが、どちらも同じものが用意されています。

例によって PHP 側では第二引数に任意の文字列を指定可能です。

大文字化・小文字化 'HOGE'.toLowerCase() or 'hoge'.toUpperCase(), strtolower('HOGE') or strtoupper('hoge')

sample.js
'HOGE'.toLowerCase();
//'hoge'

'hoge'.toUpperCase();
//'HOGE'
sample.php
strtolower('HOGE');
//'hoge'

strtoupper('hoge');
//'HOGE'

どちらも指定したアルファベットを大文字化、または小文字化します。

日本の制作現場ではレアケースですが、JavaScript 側でトルコ語を扱う場合は注意が必要です。
JavaScriptの文字列を全部小文字/大文字化する

なお、PHP 側には文字列全体ではなく先頭文字だけを変換対象とする lcfirst()ucfirst() が存在します。
さらに日本語圏では中々ユースケースがなさそうですが、文章中の単語の先頭を大文字化する ucwords() なんて関数も存在します。

特定の文字を置換する 'hoge'.replace('g', 'p'), str_replace('g', 'p', 'hoge')

sample.js
'hoge'.replace('g', 'p');
//'hope'
sample.php
str_replace('g', 'p', 'hoge');
//'hope'

文字列置換と言えば正規表現ですが、静的な文字列を検索して置換する場合、JavaScript では .replace() で共通なのに対し PHP では str_replace() を使用します。
後述する preg_replace() を使用するより遥かに処理速度が速いので積極的にこちらを使用するようにしましょう。
なお、str_replace() の第一引数には配列が使用できるので、静的な文字列であれば複数でも str_replace() が使用できます。

sample.php
str_replace(array('h', 'g'), 'p', 'hoge');
//'pope'

正規表現で置換する 'hoooooooooooge'.replace(/o+/g, 'o'), preg_replace('/o+/', 'o', 'hoooooooooooge')

sample.js
'hoooooooooooge'.replace(/o+/g, 'o');
//'hoge'
sample.php
preg_replace('/o+/', 'o', 'hoooooooooooge');
//'hoge'

.replace() はそのまま正規表現を仕込めますが、PHP 側では str_replace() ではなく preg_replace() を使用することになります。

.replace() の第二引数には置換する文字列を指定しますが、実は文字列ではなく関数を指定して、更に複雑な置換を行うこともできます。

MDN: String.prototype.replace() 引数としての関数の指定

同じようなことを PHP 側で実現するためには preg_replace() ではなく preg_replace_callback() が用意されているのでそちらを使用しましょう。

PHP マニュアル: preg_replace_callback

指定した範囲の文字だけ切り抜く 'hogehugapiyo'.slice(0, 4), mb_substr('hogehugapiyo', 0, 4)

sample.js
'hogehugapiyo'.slice(0, 4);
//'hoge'
sample.php
mb_substr('hogehugapiyo', 0, 4);
//'hoge'

意外と使う範囲指定の抜き出し処理は両者似たノリで扱うことができます。
どちらも開始位置を指定している引数(上記例では0)を負の数にすると末尾から処理をスタートさせる挙動となります。

変換

文字列中で変数展開する `${hoge}`, "$hoge"

sample.js
const hoge = 'ほげ'
`${hoge}`;
//'ほげ'
sample.php
$hoge = 'ほげ';
"$hoge";
//'ほげ'

JavaScript は ES2015 以降限定ですが、バッククォートで括られた範囲の ${} 内は変数が展開されます。

対して PHP ではダブルクオーテーションで括られた文字列内では自動で変数展開が行われます。
従って、パフォーマンスの観点から PHP で文字列を扱う場合は変数展開の行われないシングルクオーテーションを使用することをお勧めします。

数値を三桁ごとに「,」で区切った文字列にする new Intl.NumberFormat().format(3500), number_format(3500)

sample.js
new Intl.NumberFormat().format(3500)
//'3,500'
sample.php
number_format(3500);
//'3,500'

存在を知らなかった頃は専用関数を作成していたものですが、多用するからなのか、両者ともに専用のメソッド・関数が存在します。

デフォルトは両者三桁のカンマ区切りですが、フランスでの表記等、独特の区切り方にも対応しているので実装の際はマニュアルを参照してみてください。

MDN: Intl.NumberFormat.prototype.format
PHP マニュアル: number_format

JSON エンコード JSON.stringify({hoge: 'ほげ', fuga: 'ふが', piyo: 'ぴよ'}), json_encode(array('hoge ' => 'ほげ', 'fuga' => 'ふが', 'piyo' => 'ぴよ'))

sample.js
JSON.stringify({hoge: 'ほげ', fuga: 'ふが', piyo: 'ぴよ'});
//'{"hoge":"ほげ","fuga":"ふが","piyo":"ぴよ"}'
sample.php
json_encode(array('hoge ' => 'ほげ', 'fuga' => 'ふが', 'piyo' => 'ぴよ'));
//{"hoge":"\u307b\u3052","fuga":"\u3075\u304c","piyo":"\u3074\u3088"}

API を中心に据えた開発が主流となりつつある現代において、ますます重要になってきている JSON ですが、もちろん両言語でサポートされています。
JavaScript と PHP では連想配列の振る舞いが全く別ですが、JSON に変換する分には同じノリで扱えるので困ることはないでしょう。
もちろんストレートな配列を仕込んでも OK です。

なお、JSON.stringify() は第二・第三引数を指定して出力内容を人間用に成型して見やすくすることができます。デバックの際に活用しましょう。
GUNMA GIS GEEK: JSON.stringifyの第2引数を使って出力結果(JSON)を整形する

JSON デコード JSON.parse('{"hoge":"ほげ","fuga":"ふが","piyo":"ぴよ"}'), json_decode('{"hoge":"ほげ","fuga":"ふが","piyo":"ぴよ"}', true)

sample.js
JSON.parse('{"hoge":"ほげ","fuga":"ふが","piyo":"ぴよ"}');
//{hoge: 'ほげ', fuga: 'ふが', piyo: 'ぴよ'}
sample.php
json_decode('{"hoge":"ほげ","fuga":"ふが","piyo":"ぴよ"}', true);
//array ( 'hoge' => 'ほげ', 'fuga' => 'ふが', 'piyo' => 'ぴよ', )

json_decode('{"hoge":"ほげ","fuga":"ふが","piyo":"ぴよ"}');
//stdClass::__set_state(array( 'hoge' => 'ほげ', 'fuga' => 'ふが', 'piyo' => 'ぴよ', ))

エンコードがあれば当然デコードがありますが、json_decode() は第二引数に true を指定すると連想配列、省略した場合は PHP のデフォルトクラスである stdClass のインスタンスとなります。
個人的には後から操作しやすい連想配列にして使用することが多いですが、メソッドなどを定義する場合は第二引数を省いておいたほうが良いでしょう。

配列との組み合わせ

文字列を特定の文字で区切って配列にする 'hoge,fuga,piyo'.split(','), explode(',', 'hoge,fuga,piyo')

sample.js
hoge,fuga,piyo'.split(',');
//['hoge','fuga','piyo']
sample.php
explode(',', 'hoge,fuga,piyo');
//array('hoge','fuga','piyo')

URL を / で分割したりと意外と出番の多い機能ですね。

実は explode() は引数を逆にしても正常に動作するという特徴があります。これは次項で紹介する implode() でも一緒なのですが、これには歴史的な理由があります。

配列を特定の文字列で区切った文字列にする ['hoge', 'fuga', 'piyo'].join(','), implode(',', array('hoge', 'fuga', 'piyo'))

sample.js
['hoge', 'fuga', 'piyo'].join(',');
//'hoge,fuga,piyo'
sample.php
implode(',', array('hoge', 'fuga', 'piyo'));
//'hoge,fuga,piyo'

こちらも良く使う機能ですが、両者ともに区切り文字に '' を指定すると単に文字列を結合する関数として使用できます。

便利なので多用しがちですが、実行速度が単純な結合よりかなり遅くなってしまうので、静的な結合であれば極力演算子による結合を使いましょう。

前項でも紹介した通り、implode() は引数を逆にしても正常に動作しますが、PHPer には有名な言い回しである「歴史的な理由」が PHP のマニュアルに登場するのがこの implode() です。

PHP マニュアル: implode

詳しくは以下のスライドが非常に秀逸かつ感動的です。

お前は PHP の歴史的な理由の数を覚えているのか

感想

意外と書き味が共通してて面白かったです。
フロントエンドであってもバックエンドであっても基本的な文字列操作は重要かつ、ベストプラクティスが似通っているのでしょう。

もちろん、url の扱いやバイナリファイルの文字列化、暗号関連等片方にしかない機能も存在するのですが、急な分野外の作業でも基本的なことをする分にはあまり困らないのではないでしょうか。

記事を書いている身としては、両者ともに公式ドキュメントが充実して読みやすいのがなによりの助けでした。著者、翻訳者に感謝。

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

ダブルクオートを使う必要がある場合

ダブルクオートを使う必要がある場合

# htmlタグの属性指定
<a href="hogehogegohe">aaa</a>

# シングルクオートを表示したいとき
$text = "わたしは'" . $name . "'です";

# テキストに変数を内包させるばあい
$text = "わたしは$nameです";
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む