ラベル PHP の投稿を表示しています。 すべての投稿を表示
ラベル PHP の投稿を表示しています。 すべての投稿を表示

2017年3月26日日曜日

schoo カスタマイズから学ぶPHP実践

Schooさんの授業を拝見してました。
「カスタマイズから学ぶPHP実践」


メモ

Plugins
  • BuddyPress
  • All in One SEO Pack
  • WooCommerce

laravel Auth
web.php Auth::routes();
--
Ruote::resource(...)
editなどのCRUDのメソッドを生成する

dd()
laravelのヘルパー関数

except()
laravel のセッションのうち、指定したパラメータ以外を取り出す
公式ドキュ

2017年1月15日日曜日

PHP / DateTime

PHPでの日付・時間の取り扱い方を振り返ります。


メモ

$time = new DateTime('now');
現在時刻でDateTimeクラスインスタンスを生成する

$time->format('Y-m-d H:i:s')
指定したフォーマットで日付を返します。
Y=4桁の西暦
y=2桁の西暦
m=2桁の月
M=英単語の略称 e.g. Jan,Feb
d=2桁の日
H=24時間表記の時間
h=12時間表記の時間
i=2桁の分
s=2桁の秒

2017年1月14日土曜日

PHP / なかなか身につかないPHP

Code IQでHTMLのスクレイピングの問題が出ていたので、PHPで書いてみた。
課題はクリアできなく、振り返りです。

<?php
$input =  trim(fgets(STDIN) )  ;
$th = array();
$td = array();
while ( $input ) {
    // echo $input . "\n";
    preg_match('/^<th>(.*)<\/th>$/', $input, $match_th);
    preg_match('/^<td>(.*)<\/td>$/', $input, $match_td);
    // var_dump($match);
    if ($match_th ) $th[] =  preg_replace('/<\w*>/', '' , $match_th[1] );
    if ($match_td ) $td[] =  preg_replace('/<\/?\w*>/', '' , $match_td[1] );
    $input =  trim(fgets(STDIN) ) ;
}

printCsv($th);
printCsv($td);


function printCsv($array) {
    foreach ($array as $key => $var ) {
        echo "\"" . $var . "\"";
        if ( $key < count($array) -1 ) {
            echo ",";
        } else {
            echo "\n";
        }
    }
}



function e($target){
    return htmlspecialchars($target, ENT_QUOTES);
}
?>


メモ

trim(fgets(STDIN) )
標準入力の読み込みと両端スペースの消去

preg_match(regex_str or regex_array, str or array, $store);
パターンマッチした行とグループ化した部分を$storeに格納する

preg_replace(regex_str, inserted_str , target_str );
target_str内でregex_strに対応する部分をinserted_strに置き換える。
preg_matchと同様にregex_strとinserted_strは配列でも構わない

count($array)

PHPの配列の要素数のカウントを思い出せずググった次第です




foreach ($array as $key => $var ) {

同じく

htmlspecialchars($target, ENT_QUOTES);

同じく

fputcsv(output , array [, delimitter[, enclosure[, escape_char] ] ] )

配列をcsvで出力する
enclosureがつくルールがわからず、今回は使えず

2017年1月4日水曜日

AWS / bitnamiを試す

何をやってもハマります
AWSのEC2インスタンスにlaravel用bitnamiパッケージを展開します。


メモ

bitnami
LAMP用のlaravelパッケージを使ってみました。

localeの設定に失敗する
/home/ec2-user/lampstack-5.6.29-0/mysql "****": perl: warning: Setting locale 
failed.
perl: warning: Please check that your locale settings:
 LANGUAGE = (unset),
 LC_ALL = (unset),
 LC_NUMERIC = "C",
 LC_CTYPE = "UTF-8",
 LANG = "en_US.UTF-8"
    are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").
デフォルトのままだからなのか?
jpの設定にしたらこのlocaleエラーは無くなりました。

export LC_ALL=ja_JP.UTF-8
シェル変数・環境変数を共にjaに変更

/etc/sysconfig/i18n
国際化用ファイルもenのままだったので"ja_JP.utf8"で上書きました。
こちらのQiitaの記事を参照にして、インスタンスを再起動しました。

Perl Module Data::Dumperを入れても、入っていないって言われる
Error: Error running /opt/lampstack-5.6.29-0/mysql/scripts/myscript.sh 
/opt/lampstack-5.6.29-0/mysql "****": FATAL ERROR: please install the following 
Perl modules before executing scripts/mysql_install_db:
Data::Dumper
makeでインストールした(パスを通してなかった?)せいでData::Dumperを実行できていなかったみたいで、
yumでインストールしたところ問題なく実行できた。
参考:orenoblog エンジニアになりたいExcel方眼紙erの物語 /usr/bin/mysql_install_db実行時にFATAL ERROR: please install the following Perl modules before executing /usr/bin/mysql_install_db:

perl -e 'use モジュール名;'
モジュールがインストールされているかのチェックに使える。
Data::Dumperですが、Dumperだけの指定でよかった
また、当たり前のような話ですが、パス通ってなかったら直下で実行する。 参照:Perlモジュールのインストール方法

上のゴタゴタが片付いてもまだエラーが出る
/opt/lampstack-5.6.29-0/php/bin/fixreg.php 
/opt/lampstack-5.6.29-0/php/lib/php/.registry @@BITROCK_PHP_ROOT@@ 
/opt/lampstack-5.6.29-0/php
Press [Enter] to continue:

Error: Unknown error while running /opt/lampstack-5.6.29-0/php/bin/php -q 
/opt/lampstack-5.6.29-0/php/bin/fixreg.php 
/opt/lampstack-5.6.29-0/php/lib/php/.registry/.channel.pear.amazonwebservices.com
 @@BITROCK_PHP_ROOT@@ /opt/lampstack-5.6.29-0/php
Press [Enter] to continue:

Error: Unknown error while running /opt/lampstack-5.6.29-0/php/bin/php -q 
/opt/lampstack-5.6.29-0/php/bin/fixreg.php 
/opt/lampstack-5.6.29-0/php/lib/php/.registry @@BITROCK_APACHE_ROOTDIR@@ 
/opt/lampstack-5.6.29-0/apache2
Press [Enter] to continue:

Error: Unknown error while running /opt/lampstack-5.6.29-0/php/bin/php -q 
/opt/lampstack-5.6.29-0/php/bin/fixreg.php /opt/lampstack-5.6.29-0/php/etc 
@@BITROCK_PHP_ROOT@@ /opt/lampstack-5.6.29-0/php
Press [Enter] to continue:
Warning: Problem running post-install step. Installation may not complete 
correctly
 Unknown error while running chown -R root:daemon 
/opt/lampstack-5.6.29-0/frameworks/laravel/storage
Press [Enter] to continue:

Error: Unknown error while running /opt/lampstack-5.6.29-0/ctlscript.sh start 
apache & > /dev/null

結論
手動で設定しよ!

2017年1月2日月曜日

PHP / 画像のアップロード

今回は画像アップロードについてのメモを残していきます。


メモ

PHP / GDライブラリ
画像ファイルの作成・操作をするPHPライブラリ

ini_set('display_errors',1);
エラー情報を画面に出力する設定

PHP header関数
生のHTTPヘッダーを送信する
覚えておいて頂きたいのは、header() 関数は、 通常の HTML タグまたは PHP からの出力にかかわらず、すべての実際の 出力の前にコールする必要があることです。
引用元:公式ドキュメント

uploadフォーム例
<form enctype="multipart/form-data" action="" method="POST">
    <input type="hidden" name="MAX_FILE_SIZE" value="30000" />
    アップロードファイル: <input name="userfile" type="file" />
    <input type="submit" value="UPLOAD" />
</form>
MAX_FILE_SIZEはtype=fileのインプットフォームより先に指定しないといけない

ファイルアップロード時の各種エラーメッセージ
KEY:VALUE:意味
UPLOAD_ERR_OK:0:アップロード成功
UPLOAD_ERR_INI_SIZE:1:php.iniの upload_max_filesize ディレクティブを超えている
UPLOAD_ERR_FORM_SIZE:2:HTMLフォームに指定したMAX_FILE_SIZE を超えている
などなど

PHP exif_imagetype関数
画像ファイルの拡張子を判定して対応したint値を返す
適切な拡張子を判別できない場合は、falseを返す

Imagetype 定数
画像ファイルの拡張子を表す定数群

sprintf
フォーマットした文字列を返す
一方、よく似ている"printf"は出力する

PHP sha1関数
そのまんま、引数の文字列のsha1ハッシュ値を返します。
第二2引数でtrueを渡すと、20 バイト長のバイナリ形式になってしまう。
今回は、デフォルト(false)で40文字の16進数の値を使用しました。

PHP imagecreatefromgif関数
新しいGIF画像ファイルを作る
URLかファイルパスを引数に渡す
成功した場合は、作成した画像ファイルのID、失敗した場合はFLASEを返す

PHP で h() を書くなら一緒に echo しよう。
ググっているうちに目に留まった記事ですが、確かにそうですね。

PHP uniqid関数
引数なしで、13文字の文字列を返す。
第1引数に、プレフィックストなる文字列を渡すことができる

PHP list()
言語構造。
配列を代入することで、引数に指定した複数の変数に同時に代入することができる

Google社がホストしているjQueryライブラリを使用する
Google Hosted Librariesから
1.x snippet:のscript要素を拝借します。
今回はbody要素の閉じタグ直前に配置しました。

jQuery $('セレクタ').fadeOut(ミリ秒)
選択した要素をフェードアウトさせます。

テキストをフェードアウトさせても高さを残してくにはどうしたらイイんでしょう
ブロック要素のheightをdefaultのautoから固定に変える
文字がフェードアウトすると、ガクッと下の要素が上に移動したのがいけていなかった。
高さを固定することで防げた。

2017年1月1日日曜日

PHP / カレンダー

あけましておめでとうございます。
PHPをじゃんじゃかやっていきましょう。
またまたドットインストールを参考にして、カレンダーを作った時のメモです。


メモ

&laquo;と&raquo;
<<と>>

Atomのコマンドパレット => cmd + shift + p
コマンドパレットという言葉もショートカットも忘れて途方にくれた。

Atom theme "Atom Monokai Dark"
黒背景・行番号エリアも黒くなる・行のハイライトなし
見やすくてオススメ。

PHP DatePeriodクラス
コンストラクタは3つあるが、今回使ったのはこちら。
public __construct ( DateTimeInterface $start , DateInterval $interval , DateTimeInterface $end [, int $options ] )
注意:$endは含まれません。

PHP DateTimeクラス
'2012-07-01'や'first day of this month'といった書き方が可能
「nowで今日の日付とって、dayの部分だけ1にしてDateクラス作って。。。」
みたいなPerlやJavaでありがちな処理にしなくて良い

PHP Intervalクラス
引数に"P"から始まる文字列を入れる
new DateInterval('P1D');
new DateInterval('P1Y1M1DT12H10M');など
MonthもMinuteも同じ"M"ですが、時間部分の前には"T"を入れます。

htmlspecialchars($s, ENT_QUOTES, 'UTF-8');
htmlエンコード関数。

PHP オブジェクトのコピー
$new = clone $orig
$new = $origだと参照渡しになるとのこと

PHP / laravel入門3

引き続きドットインストールのお世話になります。
今回もlaravelフレームワークのメモを残していきます。

version info
  • PHP 5.6.29
  • Laravel Framework version 5.3.28

メモ

@yeild('xxx')
セクション名(?)を決める。
ここに埋め込む内容を@sectionブロックに書く。

@extends('layouts.default')
テンプレートの指定

@section('xxx')
hoge @endsection
セクションに埋め込む内容を記述

@section('xxx' ,'hoge')
埋め込む内容を第2引数にして1行で書くこともできる。

php artisan make:controller Controller
artisanコマンドでコントローラーの作成
app/Http/Controllersディレクトリ配下にController.phpが作成されます。

dd($posts->toArray());
Dump & Die
オブジェクトを出力して、廃棄する?
改めて調べます。

途中のコントローラ
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class PostController extends Controller
{
    //
  public function index() {
//    $posts = \App\Post::all();
    $posts = App\Post::all();
    dd($posts->toArray());
    return view('posts.index');
  }
}

Post::orderBy('created_at', 'desc')->get();
オブジェクトの取得、指定したカラムの降順

$posts = Post::latest('created_at')->get();
同じく、オブジェクトの取得、指定したカラムの降順

return view('posts.index', ['applicants' => $applicants]);
ビューに値・オブジェクトを渡す。
この例だと、applicantsというキーで、$applicantsを渡している。

return view('posts.index')->with('posts' ,$posts);
上の例と同じ。書き方のバリエーションありすぎ困る。。。

    @foreach ( $posts as $post )
      <li><a href="">{{ $post->title }}</a></li>
    @endforeach
bladeでのforeachの埋め込み。
foreachのオルタネイティブな書き方とにている。
{{ }} によるhtml encode(エスケープ)してくれる
試しに<script>を表示させて見たら、
ちゃんと「&lt:script&gt」と表示された

{{-- --}}
bladeのコメント
パースしてあげれば消える

foreach・オブジェクトが空の時の分岐付き
    <ul>
    @forelse ( $posts as $post )
      <li><a href="">{{ $post->title }}</a></li>
    @empty
      <li>empty</li>
    @endforelse
    </ul>
これイイすね。
Thymeleafだと一回リストが空か判定をいれるから、
ネストが深くなって読みづらくなります。forelseだとスッキリしますね。

URLの埋め込み方いろいろ
  • /comment/{{ $comment->id }}
  • {{ url('/comment', $comment->id }}
  • {{ action('CommentController@show', $comment->id) }}
'CommentController@show'は
CommentControllerのshowメソッドを実行

$comments = Comment::findOrFail($id) ;
該当するidのレコードが見つからない場合は、例外を返す

"{!! !!}" と "{{ }}"
"{!! !!}" :HTMLエスケープしない
"{{ }}" :HTMLエスケープする(PHPのhtmlentities関数を通す)

nl2br(string [,bool = true] )
PHPの関数
string内の改行コードを<br>(false時)または<br />(true時)に置き換える 改行

laravelのe()関数(ヘルパー関数)
PHPのhtmlentites関数を実行する

{!! nl2br(e($comment->body)) !!}
安全に文字列を埋め込むには、これだと覚えるしかないですかね。。。
  1. e()でエスケープ
  2. 改行を<br>タグに置き換える
  3. エスケープなしで出力(e()でエスケープ済み)

ルーティングの注意
上から見ていって先にマッチしたマッピングが動作する
ファイル指定のルーティングをパラメータ指定のルーティングより先に書く

CSS: input [type=text] { }
textのinputのブロック
最近全然CSS書いてなかったのでメモ_φ(・_・

MethodNotAllowedHttpException
ルーティングしていないURLにアクセスすると、この例外がでる

public function store(Request $request )
Illuminate\Http\Requestクラスを引数に取ることで、
HTTPリクエストのインスタンスを取得できる。

laravel Eloquentのsaveメソッド
データベースに結びついているオブジェクトを更新する

TokenMismatchException
laravel5の標準でPostのHTTPリクエストを受けると、
TokenMismatchExceptionを投げる。

SQLの失敗例外
QueryException in Connection.php line 770:
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'body' cannot be null (SQL: insert into `posts` (`title`, `body`, `updated_at`, `created_at`) values (fasdf, , 2016-12-31 15:32:15, 2016-12-31 15:32:15))
フォームのnameが間違っていて、not null例外が発生したもの

{{ csrf_field() }}
このトークンをpostを投げるform内に配置することで、
TokenMismatchExceptionを回避できる。
<form method="post" action="{{ url('/') }}">
  {{ csrf_field() }}

フラッシュデータを出力する
return redirect('/')->with('msg', 'You did it!');

session('msg')
セッションの要素を取り出す。

onclick="this.classList.add('hidden')"
DOMの操作。onclickを書いた要素にhiddenクラスを追加

laravel validation
コントローラでvalidateメソッドを呼ぶ
$this->validate($request, [
  'title' => 'required|min:5',
  'body'  => 'required'
]);
バリデートに失敗すると、エラーメッセージとともに元のページに帰る

今時な(?)バリデーションエラーメッセージの表示箇所
上にまとめてとかではなく、該当箇所の横か下が良い。
ただ、入力項目が多いと微妙ですね。
エラーの時にクラスつけて表示をイイ感じにすることなどの方が大事な気がした。

今時な(?)バリデーションエラーメッセージの表示箇所
上にまとめてとかではなく、該当箇所の横か下が良い。
ただ、入力項目が多いと微妙ですね。
エラーの時にクラスつけて表示をイイ感じにすることなどの方が大事な気がした。

The title must be at least 3 characters.
"min:n"のバリデートに失敗した時のデフォルトメッセージ

The body field is required.
"required"のバリデートに失敗した時のデフォルトメッセージ

oldヘルパー関数
直前のリクエストの際の属性の値を取得する
入力フォームで便利

old('column' [, xxx ] )
old(フラッシュデータ)がない時は、
第二引数を返す

$errors->has('colum')
バリデートエラーの際に、columにエラーがあったかを判別

$errors->first('column')
エラーオブジェクトが持つ、要素のうち、最初のcolumnの値を返す

$errors->all()
バリデートエラーを全件取得。
foreachでぐるぐるするという使い方ができる

{{ method_field('patch') }}
ルーティングでpathcメソッドを使えるようにする

プレースホルダー
input:textはplaceholder属性
textareaは要素で挟んだ文字列
よく忘れる!特にtextarea!!

php artisan make:request name
Requestクラスを作成するartisanコマンド
app/Http/Requests/配下に作成されます。

Requestクラスの認証
    public function authorize()
    {
        return false;
    }
認証をしない(全部通す)場合は、 return true;

useの指定
use App\Http\Requests\PostRequest;
とクラス名まで指定(この例では、PostRequestはクラス)

a要素のhref="#" とhref=""は異なる
少しはまっていたので、メモ
「Re:href="#" onclick の悪習」という記事を参考にさせてもらいました。
a要素のhref属性に値が入ってるとonclick属性の内容を実行後にhref属性の値を参照しようとする。
逆にいうと、href=""だとdatasetに値を渡せないみたいでした。
php::
  <form id="form_{{$comment->id}}" >
    <a href="#" data-id="{{ $comment->id }}" onclick="delete(this);" >hoge</a>
  </form>
JS::
  function delete(e) {
    document.getElementById('form_' + e.dataset.id).submit();
}
一応onclickでJS自体は呼び出せてたので紛らわしかったです。
仕様はちゃんと確認できていないですが、
href=""では動かず、href="#"でgetElementできていました。

php artisan make:model Comment --migration
Modelクラスとmigrationを作成する
migrationは、database/migrations/配下
Modelクラスは、app/配下にできます。

belongsTo()

hasMany()

php artisan migrate
マイグレートの実行
間違えても親切なエラーが出る
 [Symfony\Component\Console\Exception\CommandNotFoundException]  
  Command "migration" is not defined.                             
  Did you mean one of these?                                      
      migrate                                                     
      migrate:refresh                                             
      migrate:status                                              
      migrate:reset                                               
      migrate:rollback                                            
      migrate:install                                             
      make:migration

show variables ;
SQLの環境変数の表示
ただ、数が多いので、
show variables like 'port';
show variables where Variable_name = 'port';
のように絞るとイイ。

[Illuminate\Database\QueryException]
Connection refused
vagrantでPHP/MySQL動かしていたのに、Host OSでphp artisan migrateしていた。
Guest OS上で実行して、問題なくDBにアクセスできた。

php artisan migrate:status
migrateの個々の実行状況を出力

php artisan make:migration <マイグレーション名> --table=<変更対象テーブル>
既存テーブル変更のマイグレーション作成
database/migrations/配下にできます。

2016年12月30日金曜日

PHP / laravel入門2

あくまでも自分用のメモ

引き続きドットインストールのお世話になります。
今回もlaravelフレームワークのメモを残していきます。


メモ

php artisan tinker
tinkerの起動

>>> App\Post::all()->toArray();
配列の形で全てのインスタンスを出力する

>>> App\Post::where('id', '>', 1)->get()->toArray();
配列の形で特定のインスタンスを出力する

>>> App\Post::where('id', '>', 0)->orderBy('updated_at', 'desc')->get()->toArray();
orderBy('updated_at', 'desc')で並び替え
昇順はasc、降順はdesc

>>> App\Post::where('id', '>', 0)->orderBy('updated_at', 'desc')->take(1)->get()->toArray();
take(1)でレコード数を制限する。上から1個みたいです。

$post = App\Post::find(2);
>>> $obj = App\Post::find(2);
find(2)で該当のIDのレコード(オブジェクト)を返す。

>>> $post->title = 'title was changed';
プロパティの代入。

>>> $post->save();
変更の保存。

>>> App\Post::find(2)->update(['title'=>'title was changed again']);
update()でプロパティの->save()と同等の効果です。
ずいぶんすっきりしているORMで慣れればわかりやすいかもしれない。




ルーティング

サーブレット・Springフレームワークの言うところのリクエストマッピングですね!

app/Http/routes.php
laravel 5.2以前の場合

routes/web.php
laravel 5.3以降の場合

$ tree -L 2
PHP/laravel関係ないですが、
tree打ったら必要以上に出力された。。
パスの深さの指定は -L n

laravelのバージョン確認
php artisan --version
Laravel Framework version 5.3.28

Route::get('/', function () {
    return view('welcome');
});
/(ドキュメントルート)でアクセスされたら、
viewのwelcomeにアクセスする、という設定。
welcomeは/resources/views/welcome.blade.php

Route::get('/{num}', function ($num) {
        return 'get ' . $num;
});
ドキュメントルートに文字列を付与すると、
get 文字列
という文字列を返す。

Route::get('/', function () {
    return view('posts.index');
});
パスセパレータが.ドット
これで、resources/views/posts/index.blade.phpにアクセスできる

PHP/基本のメモ5

今回はメソッドを中心にメモを残します。


メモ

M_PI
円周率の定数

array_push($array, $var, $var2)
$array = [$var];
$array = [$var2];
と同じですが、array_pushは複数の要素を配列に格納できます。
どちらも配列の末尾に追加です。

sort($array)
配列をソートする

echoとprint
echo:関数。複数の引数を出力できる
print:言語構造。1つの引数しか出力できない

is_a(変数, クラス名を示す文字列)
変数がクラスのオブジェクトがを判定する

property_exists(変数, プロパティ名を示す文字列)
変数がプロパティを持つかを判定する

method_exists(変数, プロパティ名を示す文字列)
変数がメソッドを持つかを判定する

method_exists(変数, プロパティ名を示す文字列)
変数がメソッドを持つかを判定する

プロパティの定数はconst
定数名に$をつけないこと。

クラス定数へのアクセス
クラス名::定数名
$はつけない
クラスメンバへのアクセス(staticなプロパティ、メソッド)も同じ

PHP/基本のメモ4

マイナーなPHPのメモ


メモ

mt_rand(start_num, end_num)
rand()より精度が高い乱数をより早く返せるとのこと。
メルセンヌ・ツイスタを実装って公式にはあるけど、実装が正しくないバグがあったそうです。。。
PHP の mt_rand() は一貫して壊れている(consistently broken)らしい

...まぁ用途によっては気にしなくても大丈夫なのかな。
引数を含む2つの値の間の整数のいづれかを返します。
start_num > end_numの場合はfalseを返します。

$_SERVER
実行環境に関する情報を保存する予約変数
連想配列です。

$_SERVER["SCRIPT_NAME"]
現在のファイルのドキュメントルートからの相対パスを保持しています。
自リンクを作る際に使います。

$_SERVER["PHP_SELF"]
URLの、実行スクリプト以下の部分も含まれてしまう。
URLに実行したいJavaScriptを書いておくで、リンクにスクリプトを埋め込むことができてしまう
そのため、$_SERVER["SCRIPT_NAME"]を使いましょう。

__FILE__
マジック変数の一つ
実行した箇所のファイル名(includeされた箇所ならinludeファイル)のフルパス
※サーバ上でのフルパスですよ!

git commit -a
PHP関係ないですが、自分の認識が間違っていて、気づくのに時間がかかったので、メモ
新規ファイルは上記の-aしてもaddしてくれません。
しょうがないので、きっちり、git addしてからgit commitです。

PHP5.4からは配列の初期化は[]でもオッケー
array()で初期化するものだと思っていましたが、[] , [2,3,4]の形でも配列の初期化ができるとのこと
もう、Perlばりに書き方いろいろあるなぁ。

shuffle(配列)
配列をシャッフルする(システム?)関数
PHPのオブジェクトなしでよびだせる関数ってなんていうんでしょうね。とりあえずシステム関数と読んでみます。

array_slice(配列、オフセット、要素数)
配列のオフセット分ずらした添字の要素から要素数分の配列を返します。
オフセットが配列のサイズより大きい時は、空の配列を返します。

htmlspecialchars($s, ENT_QUOTES, 'UTF-8');
&, >, <, ", ' をHTMLエンコードする
今のWebアプリでは必須。お忘れ無く。
ENT_QUOTESはシングルクォート、ダブルクォートを共にエンコードするという設定
最後の'UTF-8'は見たまんま文字コードの指定です。

<?= 'Hello, World!' ?>
<?php echo 'Hello, World"' ?>と同じ

ini_set('display_errors', 1);
設定を変更します。
display_errorsは、画面にエラー出力を表示させるかどうかです。
デフォルトは1です。

2016年12月29日木曜日

PHP / 配列へのアクセス / [] でも{}でもいいんかい

$array[0] でも $array{0]でもどっちもOKなPHP
どちらにしてもゼロから添字は始まります。

PHP / : コロンでも{} 括弧でもいいんかい

まだまだ驚き溢れるPHPの世界。
PHPの制御構文は、{}だけでなく:コロンでブロックを表現できるとのこと。 Pythonみたいね。

メリット

少しだけhtmlに埋め込んだ時に見た目が改善されます。うん、少しだけ。

if (xxx) { => if (xxx): 
 } else {  => else:
 }         => endif;  
if、 while、for、 foreach、switch が対応しているとのこと。
参照:公式ドキュメント

PHP / elseif /else if

PHPだとelseifともelse ifとも書けるんかいな。。。
結果はどちらでも書いても同じですが、内部的な処理が違うとのこと

複数の elseif を同じ if 文の中で使用することができます。
TRUE と評価された最初の elseif 式を実行します。PHP では、(単語二つで)'else if'と書くこともできます。
動作は(一単語の) 'elseif'と同じです。文法的な意味はやや異なっています
(あなたが C 言語に詳しいとすると、C 言語のそれと同じ動作です)。 しかし、最終的な両者の動作は全く同じです。
抜粋:公式ドキュメント

else ifだと、最初のif条件式がfalseの場合にさらにifブロックがある(入れ子構造)、ということみたいですね。

一方、一単語のelseifだと、最初のif条件式がfalseの場合に、同じ階層に条件判定する式がある、ということみたいです。
まぁどっちでも書けて、結果は変わらないということだけ覚えときゃいいか。

PHP / laravel入門

Nothing worth to see here

あくまでも自分用のメモ

引き続きドットインストールのお世話になります。
今回はlaravelフレームワークのメモを残していきます。


メモ

Composer
laravelをインストールする上で、composerを使います。 依存性チェックツール。
JavaでいうMaven, Gradleにあたりますかね。
PHPはコンパイラ言語ではなくインタープリタ言語のため、build不要のはずです。
そのため、純粋に依存性のチェックと解決(必要なライブラリのインスト)だけだと思っています。
なぜ依存性チェックツールがlaravelのインストールの前に必要かというと、
laravelはフレームワークで多数のライブラリを必要とするため、
手動でライブラリの依存問題を解決するのは、やってられないからです。

composerのインストール
ろくに英語を読まずにやっていましたが、公式ドキュメントを参考に、下記のコマンドを実施しました。
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php -r "if (hash_file('SHA384', 'composer-setup.php') === \
'61069fe8c6436a4468d0371454cf38a812e451a14ab1691543f25a9627b97ff96d8753d92a00654c21e2212a5ae1ff36') \
{ echo 'Installer verified'; } else { echo 'Installer corrupt'; \
unlink('composer-setup.php'); } echo PHP_EOL;"
php composer-setup.php --install-dir=/usr/bin --filename=composer
php -r "unlink('composer-setup.php');"
結果として、/usr/bin/composerが配置されます。 通常、/usr/binにはパスは通っているかと思いますので、基本的にcomposerと打てばどこからでも実行できるようになります。

php artisan --version
laravelのバージョン確認
結果
Laravel Framework version 5.3.28

laravelプロジェクトの作成
composer create-project --prefer-dist laravel/laravel
これでプロジェクトを作成できます。

.env
設定ファイル
まずは、下記3つの項目を更新する。
  1. DB
  2. USER NAME
  3. PW

config/app.php
envヘルパー
'log' => env('APP_LOG', 'single')
と言うやつ。
env()で.envから'APP_LOG'keyがkeyとして設定されている値を返します。
設定されていない場合は、二つ目の引数('single')が設定されるそうです。

config/app.php : 設定項目
'timezone' => 'Asia/Tokyo'
'locale' => 'ja'

yumコマンドのエラー
[vagrant@localhost myblog]$ yum install tree
Failed to set locale, defaulting to C
??????????:fastestmirror
自分の自己解決能力のなさを呪いながらも、Qiitaの記事でFIXしました。
localeがセットできないというエラー。
/etc/sysconfig/i18nにLC_CTYPE="ja_JP.UTF-8"を足す。

Httpセッションの管理系ソースを置くフォルダ
</Project Base Dir>/app/Http/
[vagrant@localhost myblog]$ tree app/Http/
app/Http/
├── Controllers
│   ├── Auth
│   │   ├── ForgotPasswordController.php
│   │   ├── LoginController.php
│   │   ├── RegisterController.php
│   │   └── ResetPasswordController.php
│   └── Controller.php
├── Kernel.php
└── Middleware
    ├── EncryptCookies.php
    ├── RedirectIfAuthenticated.php
    └── VerifyCsrfToken.php

routingを管理するファイル
laravel 5.3ではroute/web.phpでroutingを管理
[vagrant@localhost myblog]$ tree routes/
routes/
├── api.php
├── console.php
└── web.php

View関連を格納するディレクトリ
</Project Base Dir>/resources/Views
[vagrant@localhost myblog]$ tree resources/
resources/
├── assets
├── lang
└── views
    ├── errors
    │   └── 503.blade.php
    ├── vendor
    └── welcome.blade.php

php artisan make:migration <Migration Name>
まだ理解できていないのですが、マイグレーションファイルがこれでできる。
artisanファイルは、laravelのBase Dir直下にありますので、
Base Dirで上記のコマンドを実行しましょう。
 php artisan make:migration create_posts_table --create=posts
Created Migration: 2016_12_28_145157_create_posts_table
これでpostsというテーブルを作るバッチファイル(2016_12_28_145157_create_posts_table)が、
</Project Base Dir>/database/migrationsディレクトリ配下にできます。

マイグレーションファイル
作成直後のファイルのベタ貼り
increments('id');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('posts');
    }
}
up()にテーブル作成の処理、down()にテーブル削除の処理を書いていくとのこと。
テーブル削除も外部キーあると面倒くさかったりしますもんね。

Blueprintクラスのメソッド
  • increments : int unsigned not null auto_increment primary key
  • string : varchar(255) not null
  • text : text not null

マイグレーションファイルの実行
 php artisan migrate
 Migrated: 2016_12_28_145157_create_posts_table

既存テーブルに変更を加えるマイグレーションファイルの作成
php artisan make:migration modification --table=posts
新規作成ではなく、既存テーブルの変更の場合は--tableオプションを使用します。
基本的に--createで作ったファイルと同じですが、
up()/down()それぞれにある、Schema::tableメソッドは未実装です。

php artisan make:status
どのマイグレーションファイルが適用されているかを出力する

マイグレーションファイル実行のロールバック
php artisan migrate:rollback
Rolled back: 2016_12_28_153233_add_summary2
最後に実行したマイグレーションファイルのdown()が実行される模様。便利!

マイグレーションファイル実行のロールバック
php artisan migrate:rollback
Rolled back: 2016_12_28_153233_add_summary2
最後に実行したマイグレーションファイルのdown()が実行される模様。便利!

マイグレーションファイル実行のロールバックで「Class xxx not found」が出た時
composer dump-autoload
Generating autoload files
composerにパスが通っている前提です。

モデル作成用マイグレーションファイルの作成
php artisan make:model Comment
Model created successfully.
appディレクトリ配下にComment.phpができます。

対話的にモデルを通してDBにモデルの構造のレコードを挿入する
tinkerというプログラムを呼ぶ
 php artisan tinker
Psy Shell v0.8.0 (PHP 5.6.29 — cli) by Justin Hileman
>>> $comment = new App\Comment();
=> App\Post {#674}
>>> $comment->title = 'title 1';
=> "title 1"
>>> $comment->body = 'body 1';
=> "body 1"
>>> $comment->save();
=> true
>>> 

tinkerの終了
exit

Mass Assignmentってなんやねん。
答えはスタックオーバーフローにある
冒頭の数行しか読んでないですが、、、、
配列を使った、複数プロパティ(ORMしているからレコードのフィールドと同義)への代入のことですね。
Mass = 大量の, Assignment = 割り当て
ですもんね。
便利ではあるけど、セキュリティホールになるので、laravelはデフォがオフです。
個別に許可を設定する必要があります。

tinkerでstaticメソッドのcreate()を使いDBにモデルの構造のレコードを挿入する
create()メソッドを使って、連想配列を使ってレコードを挿入する。
しかし、前項目で書いた通り、先にMass Assignmentの設定をモデルクラスでする必要があります。
設定しないと下記のエラーが出ます。
>>> App\Comment::create(['title'=>'title 2', 'body'=>'body 2']);
Illuminate\Database\Eloquent\MassAssignmentException with message 'title'

モデルクラスでプロパティにfillableを設定します。
Mass Assignmentを許可するカラム名を配列で設定します。
protected $fillable = [ 'title', 'body'];

Mass Assignmentの設定をしたら、tinkerを再度立ち上げて、createメソッドを実行します。
連想配列の形で、複数カラムに値を設定できます。便利。
>>> App\Comment::create(['title'=>'title 3', 'body'=>'body 3']);

2016年12月27日火曜日

MySQLとPHP/基本のメモ3

前回まではとりあえず書いてみたっていうだけでした。
今回は、ここのメソッドや変数について確認します。


メモ

カウンタ変数に色をついた名前を
文法関係や言語に関係なく、なかなか治らない自分の悪癖
同時にカウンタ変数にアクセスされる場合や、
後で放置されたカウント変数にアクセスしちゃう場合があり得るんですね。
エラーになってくれた方が、論理エラーがなくなって助かりますが。。。

ローカル変数をグローバルに
用途がよくわからないのですが、、、できるようです。
global $変数名;
宣言時にglobal とつけてやる。

クロージャ(無名関数)
最近全然JS書いてないけど、スコープを作るために
無名関数書くっていうのもありますよね。

クラス内の定数
const 定数名 = 値;
グローバルな定数とは書き方が違う。
しかも$マークは付けない。
自クラス内で使う場合は、self::定数名
Javaでのstaticと同じような扱いか。

PHP 5.3 以降のconst
クラスの定数かどうかに関わりなく、定数宣言にconstが使えるそうです。
同じかと思ったら、下記の違いがありました。
constで定義したクラス外の定数 = 名前空間に属する
defineで定義した定数 = グローバルな定数

変数名と定数名と関数名
1文字目 = _または半角英字
2文字目以降 = _と 半角英数字
大文字・小文字を区別する。
※関数名のみ大文字・小文字を区別しない
※そうは言っても「書いた通りの大文字小文字で呼出せよ」と公式ドキュメントには書いてある。

PHPのfor文は変化式を複数かける
まぁforのスコープの中で増やしている処理がすっきり書けるっていうだけですが、
for ( $i = 0 ; $i < 0 ; $i++ , $countDown-- )
という書き方が可能。カンマ区切りで複数の処理を書くことができます。

PHP は関数のオーバーロードをサポートしていません。
公式ドキュメント
Qiitaの記事で紹介されていますが、
実装でカバーできるようです。

NULLとNULL文字(\0・NUL)は同義ではない
NULL文字(\0)の存在を初めて知りました。
文字列の終端を表すための文字なんですね。
一方NULLは何も参照していないことを表す記号ですね。

100-200回を超える再帰呼び出しはするな
これも公式ドキュメントネタです。
Paizaさんみたいなコードクイズでもない限り、自分は再帰処理を滅多に書きませんが、
メモリがスタックする可能性があることは記憶の片隅に留めたい。

PHPの変数は値を格納する「箱」not label
変数Aに変数Bを代入する場合、変数Bの値をコピーするということになる
$a = 10;
$b = $a;
$b = 20;
最後に$bに20を代入しているけど、$aの値は10のまま

逆に2つの変数を連動したい場合
参照を渡してみる
複数回メソッドを呼び出す際や、スコープをまたいで値を変更してあげたいときに
参照渡しを使う
&アンパサンダをつける。 変数の初期化
$a = 10;
$b =& $a;
$b = 20;
最後に$bに20を代入すると、$aも20となる

変数の初期化
 function doubleUp(&$num) {
   $num *= 2;
 }

 $age = 20;
 doubleUp($age);

doubleUpを呼ぶと、引数に渡した変数が倍に設定される。

アクセス修飾子(再掲)
デフォルトなんだったか忘れる。。。。publicですね。
public, protected, private
privateは自クラスのみアクセス可、子クラスからもアクセス不可。
protectedは自クラスと子クラスからアクセス可。
publicはどこからでもアクセス可
varを使ってプロパティを宣言した場合や、メソッドにアクセス権を明記しない場合は、public扱いです。

UTF8 BOM
BOMとか初めて知った。。。
Byte Order Mark
符号化に関するファイルヘッダーで、これが付いていることにより、 想定外の動作になることがあるらしい。

PDO_DSN
DSNはData Source Nameの略みたいです。
詳しくは公式ドキュメント参照ですが、
mysql:host=xxx;port=xx;dbname=xxx
というようにsql名:key=value;..で組み立てた文字列を使う。

PDO::setAttribute
属性の設定
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
で、エラー時に例外を投げる設定になる。その他は公式参照。

PDO::setAttribute( ATTR_EMULATE_PREPARES, false )
属性の設定
SQLインジェクション対策として、常にfalseにしましょう
で、エラー時に例外を投げる設定になる。その他は公式参照。
また、true担っているとDBでint型のものをStringに変換してしまうとか。。。
Qiita PDOでATTR_EMULATE_PREPARESを適切に設定してないとSQLインジェクションの原因になるかも(MySQL編)
参照:なんでPHPはMySQLからのリザルトがint型のはずなのにstring型になってしまうん?

MySQLとPHP/基本のメモ2

続きです。


メモ

ユーザ一覧表示
> SELECT user, host FROM mysql.user;
前回も載せたんですけどね。覚えてなかったので。
mysqlというシステム用のスキーマがあり、そこにuserテーブルがあると。

ユーザの削除
> drop user dbuser@localhost;

PHP Data Objects(PDO)
PHPでDBへつなぐ時のインターフェース。コネクターのことかな。

変数名の_アンダースコア
人気があるコーディング規約
プロパティの変数名の頭に_をつけることで、thisをつけなくても(つけ忘れても)
プロパティとわかりやすくする。また、そうすることで変数名の重複を減らすことができる。

ヒアドキュメント内の変数
展開される
シェルスクリプトとはちがうみたい

define('key' , 'value);
定数の設定。Javaと違いすぎて忘れる。

PDOのテンプレ
まず、DB名やユーザ名・PWを定数定義するとして、
try {
  // connect
  $db = new PDO(PDO_DSN, DB_USERNAME, DB_PASSWORD);
  $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

  // proc
  $db->exec("insert into users (name,score) values ('hoge', 5);");
  echo "user added!";


} catch (PDOException $e) {
  echo $e->getMessage();
  exit;
}

error
SQLSTATE[42000]: Syntax error or access violation: 
1064 You have an error in your SQL syntax; 
check the manual that corresponds to your MySQL server version 
for the right syntax to use near 
'insert555 into users (name,score) values ('tag', 5)' at line 1

preppare()
複数回使うクエリに適している。SQLインジェクションの対策が必要。
  $stmt = $db->prepare("insert into users ( name , score ) values ( ? , ? );");
  $stmt->execute(['hoge', 100]);
  echo "insert no : " . $db->lastInsertId();

exec()
結果を返さないで実行する。selectなど。
安全なクエリに使う。

query()
結果を返す。
安全、かつ、一度しか実行されないようなクエリに使う。
下記の例は2次元配列として格納されるようです。(3つの要素を持つ連想配列の配列)
  $stmt = $db->query("select * from users");
  $users = $stmt->fetchAll(PDO::FETCH_ASSOC);
query()の結果は、PDOStatement オブジェクトが返ります。 詳しいことはQiitaのこの記事を読んでください。

$db->lastInsertId();
最後に挿入されたレコードのIDを返します。

名前付きパラメータ
「:パラメータ名」とすることで連想配列みたいに扱える。
  $stmt = $db->prepare("insert into users ( name , score ) values ( :name , :score );");
  $stmt->execute([':name'=>'hoge', 'score'=>100]);
:を付けても付けなくてもアクセスできました

bindValue()
プレースホルダーに値を保持させたままにすることができる。
下記の例だと$nameは変えてないので、hogeでちがうscoreのレコードを2行挿入できる。
  $stmt = $db->prepare("insert into users ( name , score ) values ( ? , ? );");

  $name = 'hoge';
  $stmt->bindValue(1, $name, PDO::PARAM_STR);
  $score = 43;
  $stmt->bindValue(2, $score, PDO::PARAM_INT);
  $stmt->execute(); // 1st
  $score = 55;
  $stmt->bindValue(2, $score, PDO::PARAM_INT);
  $stmt->execute(); // 2nd


プレースホルダーに名前を付けるとこうなる。
  $stmt = $db->prepare("insert into users ( name , score ) values ( :name , :score );");

  $name = 'hoge';
  $stmt->bindValue('name', $name, PDO::PARAM_STR);
  $score = 43;
  $stmt->bindValue('score', $score, PDO::PARAM_INT);
  $stmt->execute(); // 1st
  $score = 55;
  $stmt->bindValue('score', $score, PDO::PARAM_INT);
  $stmt->execute(); // 2nd

その他のデータ型
PDO::PARAM_NULL
PDO::PARAM_BOOL

bindParam();
プレースホルダーが参照する変数を固定する
  $stmt = $db->prepare("insert into users ( name , score ) values ( :name , :score );");

  $name = 'hoge';
  $stmt->bindValue('name', $name, PDO::PARAM_STR);

  $stmt->bindParam('score', $score, PDO::PARAM_INT);
  $score = 100;
  $stmt->execute();
  $score = 400;
  $stmt->execute();

FETCH_CLASS
PDOオブジェクトをクラスに代入する
Userクラスを作った上で、FETCH_CLASSするとオブジェクトを配列で返す。
class User {
# public $id;
# public $name;
# public $score;
  public function show() {
    echo "$this->name ($this->score) <br>\n";
  }
}

  $stmt = $db->query("select * from users");
  $users = $stmt->fetchAll(PDO::FETCH_CLASS, 'User');
プロパティは書かなくても、PDOのフィールドが勝手に保持されるみたいです。
楽だけどバグに気づかなそうなので、明示すべきですかね。

$stmt->rowCount()
PDOオブジェクトが持つ行数(要素数)を返す。

$db-beginTransaction();
トランザクション開始

$db->commit();
トランザクション終了

$db->rollback();
ロールバック
PDOExceptionをキャッチさせて使う。

2016年12月25日日曜日

PHP/printf/sprintf

PHPの基礎固めとして、PaizaのDランク問題を解きまくっています。
昔書いたコードを見て、少しだけ成長したなと感じたことを書きます。

お題としては、「1-3桁の数字が標準入力されるので、3桁ゼロ詰めで出力してください」

普通はこう書く

<?php printf (  "%03d",trim( fgets(STDIN) )  )?>

2016年3月ごろ書いたのがこちら

<?php
    $input_lines = fgets(STDIN);
    if($input_lines == 100){
        echo $input_lines;
    }elseif($input_lines > 9){
        echo "0".$input_lines;
    }else{
        echo "00".$input_lines;
    }
?>
車輪の再発明とはこのことですかね。無知は怖い。

printfとsprintf

sprintfは第1引数に変数を取れる。

PHP/配列の基礎

引き続き、初歩的な部分のおさらいです。



初期化
$array = array("hoge", "fuga")

print_r($array)
配列の中身をわかりやすく出力する
Array
(
  [0] => hoge
  [1] => fuga
)

$array[0]
配列の要素を返す

echo $array
間違った使いたで、Arrayと出力される。「Array to string conversion」warningが出る

array_push($array , "xxx") or $array[] = "xxx"
配列の末尾に要素を追加する。要素数は柔軟に変更される。
array_pop(), array_shift(), array_unshift()といった関数もある

要素数の上限
PHP4系=>65536個まで,PHP5系=>4294967296個まで
つまり、 PHP4系=>16bit個まで,PHP5系=>32bit個まで

要素の型
何でもいい。
サクッとサンプルプログラムを書く分には楽なんですが、大規模開発時の変数管理や処理速度はどうなのだろうか。。。

count($array)
要素の個数を返す

配列の要素の削除
unset($array[2])
後ろに要素があった場合でも、要素番号は繰り上がらない。
この場合、count()関数の返り値と配列の最大要素番号は関連性がなくなる。

explode("区切り文字", "文字列")
文字列を区切り文字で分割した配列を返す
メールアドレスチェックなんかで、@で分割して要素数が2か判定という使い方もできるか。
しかし、調べてみると、[mb_]substr_count("被検索文字列" , "検索文字列")という関数の方がわかりやすそうでした。

空行を含む入力の読み込み
<?php
while( $input = fgets(STDIN) ) {
    // 配列に$inputの値を追加
    $array[] = trim($input);
}
print_r($array);
?>

添字を連番で振り直す
array_values / array_merge

配列の並び替え
sort / rsort
配列のvalueのソートです。
連想配列に対して、このメソッドを使うとただの配列になってしまうので注意

日本語のソート
「ひらがな、カタカナ、漢字、全角数字」の順らしい
言われてみれば当たり前ですが、漢字のソートは読み仮名ではなく、文字コード順

asort / arsort / ksort / krsort
連想配列の配列
asort / arsort => valueの並び替え
ksrot / krsrot => keyの並び替え

foreach ( $array as $value)
あえていうほどでもないforeach

foreach ( $array as $key => $value)
keyも取得したい場合

PHP/JavaとPHPのhazardousな違い/変数のスコープ

関数内の変数がローカル変数になるだけで、for/while/ifの中でもグローバルスコープなんですね。
また、includeやrequireの中でも先に宣言した変数にアクセスできるとのこと。

一時変数やカウンタ変数の命名や初期化はきっちりやろうと改めて認識しました。

2016年12月24日土曜日

PHP/再帰処理関数

for文ばかり書くのも芸がないので、滅多に書かない再帰処理を関数で書いてみました。
お題は、「ある数の対数log2を求める」です。
配列の要素数の上限見ていたら、「これ何bitやっけ?」と思ったのがお題のきっかけです。


元
<?php
function devide($target)
{
    return $target / 2;
}
$target = 4294967296;
$count = 0;
while ($target > 1) {
    $target = devide($target);
    $count++;
} 
echo $count;
?>

再帰処理関数
<?php
function hoge(&$target, &$count) {
  if ( $target > 1 ) {
    $count++;
    $target/=2;
    hoge($target, $count);
  } 
  return $count;
}
$target = 4294967296;
$count  = 0;
echo hoge($target, $count);
?>

下記のブログエントリーを参考にさせていただきました。
by shigemk2 「PHPで再帰関数を作る」