- 投稿日:2019-11-01T23:05:41+09:00
Laravel6.0 で バリデーションをサーバ側とクライアント側(bootstrap4 + jquery validate)で行ってみたメモ
概要
前回は一覧と作成ができることを確認した。
今回は、bootstrap4とjquery validationを使ったフロントのバリデーションも行った。Form用ライブラリのインストール
bladeでFormを扱うのが楽になるライブラリを導入した。
composer require laravelcollective/htmlLaravelでのバリデーション
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.phpRoute::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">×</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">×</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>{{-- 更新 --}} </th> <th>{{-- 削除 --}} </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.tsinterface JQuery { validate(options: any): JQuery; } interface JQueryStatic { validator: any; }バリデーションの設定
検証失敗/成功時に、bootstrap4のクラスを設定するようにしている。
resources/ts/admin/coupon/index.tsimport { 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 ファサード チートシート
- 投稿日:2019-11-01T19:04:11+09:00
Apache で PHP と http2 を両方利用するための MPM の選択
おことわり
当方は専門家ではなく、自身の経験や Google に頼った結果を基にこの記事を書いています。誤りが含まれる可能性が大いにありますので、この記事の内容は参考程度に留めるようお願いします。また誤りを発見された場合はお手数をおかけしますが編集リクエストよりご指摘いただけると幸いです。
MPM の種類
Apache には現在
preforkworkereventの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 で妥協するか……。
- 投稿日:2019-11-01T18:49:05+09:00
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カテゴリ:インストール
- 投稿日:2019-11-01T18:03:19+09:00
Laravel5.8の環境をDockerで構築する(忙しいあなたに)
忙しいあなたにチャチャっとDocker for Laravel
参考
概要
上で載せたDokcer for Laravelの記事がクソ有能なのでめっちゃ見させてもらってるけど、
パッて使いたい時に説明読むのしんどいので自分用まとめ記事です。自分用なので大分言葉足りずだと思います。
環境
- Laravel5.8
- PHP7.3
- MySQL57
ディレクトリ構造
appがLaravelディレクトリ
docker-compose.yml
web:のports:が被らないようにするmysql:のports:が被らないようにするdocker-compose.ymlversion: '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
DockerfileFROM 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/htmlnpm使うなら以下を追記
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.confserver { 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 bashLaravel5.8をComposerを使用してインストール
Laravelプロジェクト名を変更する際は最後の
app部分を任意の名前に変更するcomposer create-project --prefer-dist laravel/laravel=5.8.* appLaravel設定
DB_をdocker-compose.ymlで設定したものに変更する
.envAPP_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-01T17:25:29+09:00
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にポリゴンを描画に記載しています。
- 投稿日:2019-11-01T14:24:13+09:00
【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
- 投稿日:2019-11-01T13:18:04+09:00
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 ./configureconfigureコマンドの結果、エラーが発生しました。
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 installPHPインストール
ソースファイルをダウンロードし、展開します。
カレントディレクトリは、/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 installPHP再インストール
次の問題である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 phpmodulephpmoduleディレクトリを作成しました。必要なプログラムをphpmodule下でダウンロードし、インストールします。
JPEG
JPEGのエンコード、デコードを行うためのライブラリです。カレントディレクトリは、/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 installFreeType
フォントエンジンを実装したライブラリです。フォント関連の様々な操作をサポートします。
カレントディレクトリは、/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.9configureコマンドの後、makeコマンドよりコンパイル、make installコマンドよりインストールします。
$ sudo ./configure $ sudo make $ sudo make installphpから参照できるようにシンボリックリンクを作成します。
$ sudo ln -s /usr/local/include/freetype2 /usr/local/include/freetypelibPNG
画像データ形式の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.34Makefileをscriptsディレクトリからリネームしてコピーします。
$ sudo cp scripts/makefile.linux Makefileprefixを指定すると必要なライブラリのPathが見つからなくなるようなのでLDFLAGSによってライブラリのPathを指定します。
$ sudo ./configure --prefix=/usr/local LDFLAGS="-L/usr/local/lib -lz" $ sudo make $ sudo make installzlib
データの圧縮および伸張を行うためのライブラリです。公式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.11configureコマンドの後、makeコマンドよりコンパイル、make installコマンドよりインストールします。
$ sudo ./configure $ sudo make $ sudo make installm4
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 installautoconf
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 installlibiconv
異なる文字コード間の相互変換を行う標準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 installlibGD
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 Makefileconfigureコマンド実行時のオプション--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 installcURL
さまざまなプロトコルを用いてデータを転送するライブラリとコマンドラインツールを提供します。
公式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.gzLDFLAGSによってライブラリの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/localmakeコマンドよりコンパイル、make installコマンドよりインストールします
$ sudo make $ sudo make installPHPのインストールにもどります。
カレントディレクトリは、/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/localmakeコマンドよりコンパイル、make installコマンドよりインストールします。
$ sudo make $ sudo make installPHPのモジュールを読み込めるよう設定がなされているかApacheの設定ファイルから確認します。
$ pwd /usr/local/httpd/conf $ vim httpd.conf #一部抜粋、下記の表記があることを確認する。 LoadModule php5_module modules/libphp5.so
- 投稿日:2019-11-01T13:18:04+09:00
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 ./configureconfigureコマンドの結果、エラーが発生しました。
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 installPHPインストール
ソースファイルをダウンロードし、展開します。
カレントディレクトリは、/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 installPHP再インストール
次の問題である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 phpmodulephpmoduleディレクトリを作成しました。必要なプログラムをphpmodule下でダウンロードし、インストールします。
JPEG
JPEGのエンコード、デコードを行うためのライブラリです。カレントディレクトリは、/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 installFreeType
フォントエンジンを実装したライブラリです。フォント関連の様々な操作をサポートします。
カレントディレクトリは、/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.9configureコマンドの後、makeコマンドよりコンパイル、make installコマンドよりインストールします。
$ sudo ./configure $ sudo make $ sudo make installphpから参照できるようにシンボリックリンクを作成します。
$ sudo ln -s /usr/local/include/freetype2 /usr/local/include/freetypelibPNG
画像データ形式の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.34Makefileをscriptsディレクトリからリネームしてコピーします。
$ sudo cp scripts/makefile.linux Makefileprefixを指定すると必要なライブラリのPathが見つからなくなるようなのでLDFLAGSによってライブラリのPathを指定します。
$ sudo ./configure --prefix=/usr/local LDFLAGS="-L/usr/local/lib -lz" $ sudo make $ sudo make installzlib
データの圧縮および伸張を行うためのライブラリです。公式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.11configureコマンドの後、makeコマンドよりコンパイル、make installコマンドよりインストールします。
$ sudo ./configure $ sudo make $ sudo make installm4
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 installautoconf
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 installlibiconv
異なる文字コード間の相互変換を行う標準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 installlibGD
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 Makefileconfigureコマンド実行時のオプション--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 installcURL
さまざまなプロトコルを用いてデータを転送するライブラリとコマンドラインツールを提供します。
公式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.gzLDFLAGSによってライブラリの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/localmakeコマンドよりコンパイル、make installコマンドよりインストールします
$ sudo make $ sudo make installPHPのインストールにもどります。
カレントディレクトリは、/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/localmakeコマンドよりコンパイル、make installコマンドよりインストールします。
$ sudo make $ sudo make installPHPのモジュールを読み込めるよう設定がなされているかApacheの設定ファイルから確認します。
$ pwd /usr/local/httpd/conf $ vim httpd.conf #一部抜粋、下記の表記があることを確認する。 LoadModule php5_module modules/libphp5.so
- 投稿日:2019-11-01T09:12:43+09:00
保存版 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.jslet str = 'hoge'; str += 'fuga'; //'hogefuga'sample.php$str = 'hoge'; $str .= 'fuga'; //'hogefuga'どちらも結合時に使用した演算子に「=」を付けることで追加を行うことができます。
ところで、文字列を追加するときには上記の方法以外にも、
sample.jslet 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.phpstr_pad('hoge', 10, 'e'); //'hogeeeeeee'どちらも計10文字になるまで
'hoge'の末尾に'e'を追加を追加し、結果'hogeeeeeee'を得るコードです。この後も同じようなコードが沢山登場しますが、PHP 使いからすると、PHP では関数の引数として文字列を仕込むのに対し、JavaScript では文字列にメソッドが生えているのに違和感を感じるところですね。
JavaScript の文字列は大抵「String グローバルオブジェクト」というものを継承しているので、PHP のインスタンスのようにメソッドが生えているのです。
どちらも指定した文字数より元の文字数の方が長い場合、元の文字列がそのまま返されます。文字数までカットされるわけではないので注意しましょう。
ちなみに
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.phpstr_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.phpstr_repeat('hoge', 10); //'hogehogehogehogehogehogehogehogehogehoge'同じ文字列を指定回数結合した文字列を生成する関数です。どちらも指定回数に 0 を指定すると空文字を返します。
例によって
repeat()は IE で動かないので使用する場合は Polyfill をお忘れなく。MDN によると Android でも動かないとのことです。
MDN: String.prototype.repeat()判定・情報取得
文字数取得
'hoge'.length,mb_strlen('hoge')sample.js'hoge'.length; //4sample.phpmb_strlen('hoge'); //4JavaScript 側はクラス風に言えばメソッドではなくプロパティなので
()は不要です。PHP で文字列操作をしていると頻繁に登場する「mb_○○○」系の関数ですが、「mb_」が付いていない関数とはマルチバイト文字を考慮するかしないかの違いがあります。
たとえば
mb_strlen('ほげ')は「2」を返すのに対し、strlen('ほげ')は「6」を返します。これはstrlen('ほげ')が返すのが、正確には文字数ではなくバイト数なのが原因です。英語圏では絵文字でも使わない限り特に意識せずにコーディングしても影響なさそうですが、文字数を主眼に操作を行う場合は意識して「mb_○○○」系の関数を使用するようにしましょう。
特定の文字が現れる位置を取得する
'hoge'.indexOf('og'),strpos('hoge', 'og')sample.js'hoge'.indexOf('og'); //1sample.phpstrpos('hoge', 'og'); //1どちらも先頭を「0」として数え始めるので「'hoge'」の中にある「'og'」の位置は「1」となります。
両者の決定的な差は検索結果が無かった場合の返り値で、
indexOf()の場合は-1、strpos()の場合はfalseです。
これについては次項で詳しく説明します。特定の文字が含まれているか判定する
'hoge'.indexOf('og') !== -1,strpos('hoge', 'og') !== false直感的には、「文字列中に特定の文字列が存在するか」を判定する際には正規表現を使う方法が考え付くと思います。
しかし、JavaScript でも PHP でもこれを判定する最速の方法は前項で説明した関数の返り値を使用する方法です(もちろん、静的な文字列ではなく、正規表現における.等を表現する場合などは正規表現を使用することになります)。そのためそれぞれのメソッド・関数が「一致無し」の場合に返す値を利用するのですが
indexOf()の場合は-1、strpos()の場合は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.phppreg_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 側で登場している
\Aと\zですが、何故^と$を使用していないかというとセキュリティ的に問題があるからです。
正規表現をセキュリティに関わる処理に使用しているかどうかは実装次第ですが、PHP で正規表現を扱う場合は基本的に^と$を使用しないクセを付けておいた方が無難かと思われます。
徳丸浩の日記: 正規表現によるバリデーションでは ^ と $ ではなく \A と \z を使おう置換・削除・整形
両端の空白を削除する
' hoge '.trim(),trim(' hoge ')sample.js' hoge '.trim(); //'hoge'sample.phptrim(' hoge '); //'hoge'メソッドなのか関数なのかという違い以外は同じノリで使える両者ですが、実は PHP 側は追加の引数が指定可能です。
sample.phptrim('ふがふがふがhogeふがふがふが', 'ふが'); //'hoge'デフォルトでは空白文字を除去する
trim()関数ですが、第二引数を指定した場合はその文字を両端から削除します。便利ですね。先頭か末尾の空白を削除する
' hoge'.trimStart() or 'hoge '.trimEnd(),ltrim(' hoge') or rtrim('hoge ')sample.js' hoge'.trimStart(); //'hoge' 'hoge '.trimEnd(); //'hoge'sample.phpltrim(' 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.phpstrtolower('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.phpstr_replace('g', 'p', 'hoge'); //'hope'文字列置換と言えば正規表現ですが、静的な文字列を検索して置換する場合、JavaScript では
.replace()で共通なのに対し PHP ではstr_replace()を使用します。
後述するpreg_replace()を使用するより遥かに処理速度が速いので積極的にこちらを使用するようにしましょう。
なお、str_replace()の第一引数には配列が使用できるので、静的な文字列であれば複数でもstr_replace()が使用できます。sample.phpstr_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.phppreg_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.phpmb_substr('hogehugapiyo', 0, 4); //'hoge'意外と使う範囲指定の抜き出し処理は両者似たノリで扱うことができます。
どちらも開始位置を指定している引数(上記例では0)を負の数にすると末尾から処理をスタートさせる挙動となります。変換
文字列中で変数展開する
`${hoge}`,"$hoge"sample.jsconst hoge = 'ほげ' `${hoge}`; //'ほげ'sample.php$hoge = 'ほげ'; "$hoge"; //'ほげ'JavaScript は ES2015 以降限定ですが、バッククォートで括られた範囲の
${}内は変数が展開されます。対して PHP ではダブルクオーテーションで括られた文字列内では自動で変数展開が行われます。
従って、パフォーマンスの観点から PHP で文字列を扱う場合は変数展開の行われないシングルクオーテーションを使用することをお勧めします。数値を三桁ごとに「,」で区切った文字列にする
new Intl.NumberFormat().format(3500),number_format(3500)sample.jsnew Intl.NumberFormat().format(3500) //'3,500'sample.phpnumber_format(3500); //'3,500'存在を知らなかった頃は専用関数を作成していたものですが、多用するからなのか、両者ともに専用のメソッド・関数が存在します。
デフォルトは両者三桁のカンマ区切りですが、フランスでの表記等、独特の区切り方にも対応しているので実装の際はマニュアルを参照してみてください。
MDN: Intl.NumberFormat.prototype.format
PHP マニュアル: number_formatJSON エンコード
JSON.stringify({hoge: 'ほげ', fuga: 'ふが', piyo: 'ぴよ'}),json_encode(array('hoge ' => 'ほげ', 'fuga' => 'ふが', 'piyo' => 'ぴよ'))sample.jsJSON.stringify({hoge: 'ほげ', fuga: 'ふが', piyo: 'ぴよ'}); //'{"hoge":"ほげ","fuga":"ふが","piyo":"ぴよ"}'sample.phpjson_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.jsJSON.parse('{"hoge":"ほげ","fuga":"ふが","piyo":"ぴよ"}'); //{hoge: 'ほげ', fuga: 'ふが', piyo: 'ぴよ'}sample.phpjson_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.jshoge,fuga,piyo'.split(','); //['hoge','fuga','piyo']sample.phpexplode(',', '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.phpimplode(',', array('hoge', 'fuga', 'piyo')); //'hoge,fuga,piyo'こちらも良く使う機能ですが、両者ともに区切り文字に
''を指定すると単に文字列を結合する関数として使用できます。便利なので多用しがちですが、実行速度が単純な結合よりかなり遅くなってしまうので、静的な結合であれば極力演算子による結合を使いましょう。
前項でも紹介した通り、
implode()は引数を逆にしても正常に動作しますが、PHPer には有名な言い回しである「歴史的な理由」が PHP のマニュアルに登場するのがこのimplode()です。詳しくは以下のスライドが非常に秀逸かつ感動的です。
感想
意外と書き味が共通してて面白かったです。
フロントエンドであってもバックエンドであっても基本的な文字列操作は重要かつ、ベストプラクティスが似通っているのでしょう。もちろん、url の扱いやバイナリファイルの文字列化、暗号関連等片方にしかない機能も存在するのですが、急な分野外の作業でも基本的なことをする分にはあまり困らないのではないでしょうか。
記事を書いている身としては、両者ともに公式ドキュメントが充実して読みやすいのがなによりの助けでした。著者、翻訳者に感謝。
- 投稿日:2019-11-01T02:35:47+09:00
ダブルクオートを使う必要がある場合
ダブルクオートを使う必要がある場合
# htmlタグの属性指定 <a href="hogehogegohe">aaa</a> # シングルクオートを表示したいとき $text = "わたしは'" . $name . "'です"; # テキストに変数を内包させるばあい $text = "わたしは$nameです";


