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日木曜日

Macのhostsファイルどこだっけ?

/private/etc/hostsでした

Excel VBA入門

引き続きドットインストールのお世話になります。
Excel VBAを書く機会が近々ありそうなので、ドットインストールで復習です。
手元に製品版のエクセルがない(Win版があるけどWinPCがめっさ重い)ため、
動作確認はできてません。復讐のため可とします。


メモ

リファレンス
マイクロソフトのものはオススメしない
Office 田中がオススメ
テストセンターのOdyseyが運営しているmoug
あとはググれば大抵の問題は解決できます。書籍もたくさん出ているので適当に。

コメント
’シングルクォートです。

エディター・IDE
VBE
開発タブ(リボン)を表示させないと出てこないアレ

用語
ワークブック
ワークシート
セル
オブジェクト:操作の対象
プロパティ:属性
メソッド:振る舞い

よく使うウィンドウ
プロジェクトウィンドウ
プロパティウィンドウ

プロシージャのテンプレート
Sub WriteHello()
  MsgBox ("hello")
End Sub
Sub:プロシージャの始まりを宣言
MsgBox:ポップアップでメッセージを表示するメソッド
End Sub:プロシージャの終わり
改行:行の終わりを示す(;セミコロンじゃない)
 _(スペースとアンダーバー):行の途中で改行
最初の一文字:キーワードやメソッド、プロパティはだいたい最初の一文字は大文字(確かVBEが補正してくれたはず)

セルの操作・値の代入
Worksheets("Sheet1").Range("A1").Value = "Hey"
Range("A2").Value = "Hey"
Cells(3,1).Value = "Hey"
Cells(3.1).Offset(1,0).Value = "Hey"
上記の例では、A1 - A4にそれぞれHeyと入力される。
シートの指定がなければ、アクティブなシートに対して実行される。
また、最後のValueについては、セルの標準プロパティでもあるので、省略することが可能です。
実行速度も、省略してもしなくても差はないそうです。参照:Office 田中
Rangeはセル番地を文字列として指定するのに対し、CellsはCells(行番号、列番号)と数値で指定します。
僕は”行列”という言葉で順番を覚えています。Offsetは指定した行数と列数分、セルの指定をずらします。
数が増えるほど、右下に移ります。

複数のセルの操作
Range("A1","C3").Value = "Hey"
Range("A1:C3").Value = "Hey"
どちらも、A1からC3までのセル範囲の全てのセルに、Heyと入力します。
下の書き方は変数入れづらかったような気がする。
Range("A:A").Value = "Hey"
Range("1:1").Value = "Hey"
上はA列全てのセルに、下は1行目全てのセルに、Heyと入力します。

Cells.Clear
全セルの内容と書式の消去です。
内容のみ:ClearContents
書式のみ:ClearFormats
コメント:ClearComments
アウトライン:ClearOutline 

With
対象をEnd Withまで操作対象を省略できる
Range("A1").Value = "Hey"
Range("A1").Font.Bold = True
Range("A1").Font.Size = 16
Range("A1").Interior.Color = vbRed
            ↓
With Range("A1")
  .Value = "Hey"
  .Font.Bold = True
  .Font.Size = 16
  .Interior.Color = vbRed
もしフォントの操作の2行だけなら、With Range("A1").Fontって書いてもOKです。
あと、Endブロックを入れ子にしてもオッケーです。

Range("B2").Delete shift:=xlShiftLeft
セルの削除。
shift:はオプション
セルB2を削除して左に詰める

Worksheets.Add after:=Worksheets("Sheet1"), Count:=2
ワークシートの追加
複数のオプションが設定可能で、2個目以降のオプションはカンマで区切る
例の操作は、Sheet1のあとに2枚ワークシートを追加する。

マクロの記憶
この機能のおかげで、全部を覚える必要はないため、助かる。
ただし、無駄な記録を削るのに少し調べる必要があったりする。

Dim 変数 As データ型
変数の宣言。
VBAでは変数宣言は必須ではないが、見つけづらい文法エラーになるので、常に変数宣言したほうがいい。
モジュールの頭に(つまり、Subの宣言より上に)Option Explicitと書くと、変数の型を明示しろっていうオプションが付く。
これが付いていると変数を宣言せずに使うとエラーが発生する。

変数宣言しない怖さはOffice田中をご参照ください。

Debug.Print 変数
イミディエイトウィンドウに変数の値を表示する

数値演算
あまり:mod
べき乗:^

変数の型
Integer
Double
Data:"yyyy/mm/dd"
Variant
Boolean:True/False
Range:初期化時はSetをつける(Set ran = Range("A1")

Excelの日付の扱い
シリアル値(連続した値)として内部的に保持している。
1900/1/1 0:00が内部値「1」で、1日ずつ「1」増えていきます。
これはVBAでも同じらしく 日付に「+1」すれば1日後の値となります。

配列
Excel VBAで配列を使うには、下記2つの方法があります。
Dim fruits(3) As String
fruits(0) = "Apple"
fruits(1) = "Banana"
fruits(2) = "Orange"
Dim fruits As Variant
fruits = Array("Apple", "Banana", "Orange")
他の言語同様、添字はゼロ始まり。

条件分岐If
If Range("a1").Value = "Apple" Then
  MsgBox ("Apple")
End if

Select
他言語のswitch相当
Select Case fruit
Case "apple"
  xxx
Case "banana"
  xxx
Case Else
  xxx
End select

Loop処理
Dim i As Integer
i = 1

Do While i < 10
  Cells(i, 1).Value = i
  i = i + 1
Loop
Dim i As Integer
For i = 1 To 9 Step 1
  Cells(i, 1).Value = i
Next i
最近VBA書いてなかったから、懐かしい。。。

Foreach
Dim fruits As Variant
fruits = Array("apple", "banana", "orange")

For Each fruit In fruits
  MsgBox (fruit)
Next

プロシージャの種類
Subプロシージャ:戻り値を持たない Functionプロシージャ:値を戻す

引数の受け取り
Sub Greet(ByVal name As String)
値渡しだとByVal
参照渡しだとByRef

引数の受け取り
Sub Greet(ByVal name As String)
値渡しだとByVal
参照渡しだとByRef

判定式
等しい:=
等しくない:<>

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日日曜日

MySQL/基本のメモ

PHPの基礎文法をおさらいできたところでMySQLも基本を振り返ってみます。


メモ

ログイン
$ mysql -u USER [-p]
-pを入れるとパスワードを入力することができる。

ログアウト
> exit;
OR
> \q

ヘルプ
\h OR help

標準入力のクリア
\c

DBの作成と作業ユーザへの権限付与
> set password for root@localhost=password('xxx'); -- rootユーザのパスワード設定
> create database store; -- DBの作成
> show databases; -- DBの一覧表示
> grant all on store.* to dbuser@localhost identified by 'xxx'; -- 作業ユーザの作成と権限付与
> SELECT user, host FROM mysql.user; -- ユーザ一覧表示
> use store; -- DBへの接続

テーブルの作成
> create table users (
-> id int,
-> name varchar(255),
-> email varchar(255),
-> password char(32),
-> score double,
-> sex enum('male', 'female'),
-> memo text,
-> created datetime
-> ); -- table作成
> show tables; -- table一覧表示

テーブルのコピー
> create table new_users like users; -- テーブル名だけ違う、同じ構造のテーブルを作成

NULL制約
id int not null

UNIQ制約
email varchar(255) unique

連番
id int auto_increment
連番を振るカラムにはインデックスを張る必要がある。
その際、primary key / keyのどちらでも問題ない。

default
score double default 0.0

主キー
id int primary key

主キーでないところにインデックスを貼る
key score (score)

tableのインデックスの確認
> show indexes from TABLE_NAME;

tableの構造を表示
desc[ribe] TABLE_NAME;

列の追加
> alter table users add created datetime default CURRENT_TIMESTAMP ;

indexの追加
> alter table users add index name(name);
インデックス名(カラム名)

indexの削除
> alter table users rename system_users;

tableのリネーム
> alter table users drop index name;

DBの削除
> drop database store; -- DBの削除

扱えるデータ型
  • 数値:int, double
  • 文字列:char, varchar, text
  • 日付:date, datetime
  • その他:enum

レコードを帳票形式(項目を横ではなく縦に並べる方式)で出力する
select * from users \G
\Gで文が終わるみたいです。;セミコロンを続けて末尾に入れたら、空行だと怒られた。
select * from users \G;
ズラズラ
...
ERROR:
No query specified

limit / offset。上から2行を無視し、3行取得。
「limit 3 offset 2」「limit 2 ,3」のどちらでもいい。
パラメータが逆になるので注意

外部ファイルからSQLを実行
$ mysql -u dbuser -p store < dataInit.sql

バックアップファイルの作成
$ mysqldump -u dbuser -p store > store.bu.dump

バックアップファイルからの復元
$ mysql -u dbuser -p store < store.bu.dump

カジノIR法 / まぁ仕方がないんじゃない

カジノについては私は容認派です。
自身はギャンブルやりませんが、国が稼ぐ手段は多い方がいいでしょう、というだけの理由です。

民間事業者にしてみればビッグチャンスで、どんなに政府が規制したとしても、
問題が全く起きないということはない、とは思います。
少し時間かけてでも問題が小さくなるようにしてもらえれば思うぐらいです。

ところで政府のギャンブル依存症調査の対象者は2,200人ほどらしいのですが、統計的には十分なのか。。。

なお、政府のギャンブル依存症調査の設計は、対象者は全国の成人2,200人ほど、設問は100項目で、ギャンブルの経験や生活への影響など。家庭への影響も検討を含む。
参照:カジノIRジャパン

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の中でも先に宣言した変数にアクセスできるとのこと。

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

PHP/わかっていなかった空文字判定

途中に空行を含む標準入力を最後まで読み込む、というのをwhile/fgets(STDIN)/trimで書こうとしたら少しハマった。

こんな標準入力だと仮定して
0

hoge
結局、下記のように書いてFix
<?php
// 標準入力から1行データを取得
$input = fgets(STDIN);
// $inputの値が空で無ければループする
while( $input != "" ) {
    // 配列に$inputの値を追加
    $array[] = trim($input);
    // 標準入力から1行データを取得
    $input = fgets(STDIN);
}
print_r($array);
?>
追記
while ( $input != "" ) でなくて、while ( $input ) であれば十分でした。。。
trimしないことで、改行コードが残るんで。

注意点
  • 「改行コード」をtrimして変数に代入した場合、その変数は定義済みだが「空」であること(nullじゃない)
  • 判定前にtrimしてしまうと改行コードも空に成ってしまい、データがないことによる「空」と区別がつかない
  • 配列に改行コードは入れたくない

こちらのサイトを参考にさせてもらいました。
Allied ArchitectsEngineer Blog 空文字とかNULLとか0とか


おまけ

自分でも少し検証してみました。
まぁ、そうなりますよね。

結果
"0"
if ( $a ) : false
if ( $a == "" ) : false
if ( $a === "" ) : false
if ( is_null($a) ) : false
*******************************
null
if ( $a ) : false
if ( $a == "" ) : true
if ( $a === "" ) : false
if ( is_null($a) ) : true
*******************************
trim("\n")
if ( $a ) : false
if ( $a == "" ) : true
if ( $a === "" ) : true
if ( is_null($a) ) : false
*******************************
""
if ( $a ) : false
if ( $a == "" ) : true
if ( $a === "" ) : true
if ( is_null($a) ) : false
*******************************
"\n"
if ( $a ) : true
if ( $a == "" ) : false
if ( $a === "" ) : false
if ( is_null($a) ) : false
*******************************
0
if ( $a ) : false
if ( $a == "" ) : true
if ( $a === "" ) : false
if ( is_null($a) ) : false
コード

$a = "0";
echo "\"0\""."\n";
if ( $a ) {
    echo "if ( \$a ) : true\n";
} else {
    echo "if ( \$a ) : false\n";
}

if ( $a == "") {
    echo "if ( \$a == \"\" ) : true\n";
} else {
    echo "if ( \$a == \"\" ) : false\n";
}

if ( $a === "") {
    echo "if ( \$a === \"\" ) : true\n";
} else {
    echo "if ( \$a === \"\" ) : false\n";
}

if ( is_null($a) ) {
    echo "if ( is_null(\$a) ) : true\n";
} else {
    echo "if ( is_null(\$a) ) : false\n";
}

echo "*******************************\n";

$a = null;
echo "null"."\n";
if ( $a ) {
    echo "if ( \$a ) : true\n";
} else {
    echo "if ( \$a ) : false\n";
}

if ( $a == "") {
    echo "if ( \$a == \"\" ) : true\n";
} else {
    echo "if ( \$a == \"\" ) : false\n";
}

if ( $a === "") {
    echo "if ( \$a === \"\" ) : true\n";
} else {
    echo "if ( \$a === \"\" ) : false\n";
}


if ( is_null($a) ) {
    echo "if ( is_null(\$a) ) : true\n";
} else {
    echo "if ( is_null(\$a) ) : false\n";
}


echo "*******************************\n";


// $a = "";
$a = trim("\n");
echo "trim(\"\\n\")"."\n";
if ( $a ) {
    echo "if ( \$a ) : true\n";
} else {
    echo "if ( \$a ) : false\n";
}

if ( $a == "") {
    echo "if ( \$a == \"\" ) : true\n";
} else {
    echo "if ( \$a == \"\" ) : false\n";
}

if ( $a === "") {
    echo "if ( \$a === \"\" ) : true\n";
} else {
    echo "if ( \$a === \"\" ) : false\n";
}

if ( is_null($a) ) {
    echo "if ( is_null(\$a) ) : true\n";
} else {
    echo "if ( is_null(\$a) ) : false\n";
}


echo "*******************************\n";


$a = "";
echo "\"\""."\n";
if ( $a ) {
    echo "if ( \$a ) : true\n";
} else {
    echo "if ( \$a ) : false\n";
}

if ( $a == "") {
    echo "if ( \$a == \"\" ) : true\n";
} else {
    echo "if ( \$a == \"\" ) : false\n";
}

if ( $a === "") {
    echo "if ( \$a === \"\" ) : true\n";
} else {
    echo "if ( \$a === \"\" ) : false\n";
}

if ( is_null($a) ) {
    echo "if ( is_null(\$a) ) : true\n";
} else {
    echo "if ( is_null(\$a) ) : false\n";
}

echo "*******************************\n";


$a = "\n";
echo "\"\\n\""."\n";
if ( $a ) {
    echo "if ( \$a ) : true\n";
} else {
    echo "if ( \$a ) : false\n";
}

if ( $a == "") {
    echo "if ( \$a == \"\" ) : true\n";
} else {
    echo "if ( \$a == \"\" ) : false\n";
}

if ( $a === "") {
    echo "if ( \$a === \"\" ) : true\n";
} else {
    echo "if ( \$a === \"\" ) : false\n";
}

if ( is_null($a) ) {
    echo "if ( is_null(\$a) ) : true\n";
} else {
    echo "if ( is_null(\$a) ) : false\n";
}


echo "*******************************\n";


$a = 0;
echo "0"."\n";
if ( $a ) {
    echo "if ( \$a ) : true\n";
} else {
    echo "if ( \$a ) : false\n";
}

if ( $a == "") {
    echo "if ( \$a == \"\" ) : true\n";
} else {
    echo "if ( \$a == \"\" ) : false\n";
}

if ( $a === "") {
    echo "if ( \$a === \"\" ) : true\n";
} else {
    echo "if ( \$a === \"\" ) : false\n";
}

if ( is_null($a) ) {
    echo "if ( is_null(\$a) ) : true\n";
} else {
    echo "if ( is_null(\$a) ) : false\n";
}


?>

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で再帰関数を作る」

PHP/コードゴルフ/1〜20までの数字を出力

めっちゃ簡単なお題ですが、コードゴルフもどきです。

「1〜20までの数字を出力」をできるだけ短く書く

普通に書くと、これですよね。

<?php
$i = 1;
while ( $i <= 20 ) {
    echo $i."\n";
    $i++;
}
?>

下記の特徴を活かして省略します。

  • PHPは変数を宣言せずに使える(動的型付け言語)
  • while文を{}ブロックなしで書くことができる(みたい)
  • 前置インクリメントが使える

デン

<?php while ($i<20) echo ++$i."\n";?>

PHP/trim/文字列の先頭・末尾の空白や改行の除去

あえて書くほどでものない関数
改行も除いてくれるんですね。

rtrim, ltrimもあります。
chopはrtrimのエイリアスで非推奨とのこと。

PHP/フレームワーク/laravelにすべきかSymfonyにすべきか

記事書いてて結論が出ました。
PHPのフレームワークはどれを勉強するか迷っていましたが、laravelやります!
ただ、なぜlaravelが最近人気出ているのか、他のフレームワークとの差分はもうちょっと調べます。

PHPはフレームワークが多いって話は聞いていましたが、調べてみると本当に多いですね。
下記の記事で、8個リストアップされていました。
Qiita メモ書きPHPフレームワーク一覧

自分でもGoogle Trendsを使って確認してみました。
laravel人気ですね。
過去1年の日本でのトレンドです。

先日、何も考えずにPHPの本を1冊購入したのですが、
こちらの本ではSymfonyを使っていました。

改めて、Google Trendsを過去5年間に引き伸ばしたところ、下記のような趨勢でした。

  • 2011年頃 :SymfonyとCodeIgniterが2強として競う
  • 2013年頃 :FuelPHPの検索数がSymfonyとCodeIgniterを上回る
  • 2014年末頃:laravelの検索数がFuelPHPと並ぶ
  • 2016年  :FuelPHPの検索数がガクッと落ちてlaravel一人勝ち状態が始まり、今に至る

人気が出ているものが素晴らしいとは限らず、
すべての言語・フレームワークは一長一短だと思いますが、
息の長いテクノロジーに乗っかりたいのでlaravelを勉強することにします。

PHP/strpos/文字列内の部分文字列が最初に現れる場所を見つける

部分一致している最初の文字位置を返す。
最初の位置はゼロ。(1なのってSQLぐらいか。。。)

Qiitaで良い記事がありました。
部分一致があるかの判定でstrposを使う場合、==ではなく===を使い、型判定まで使う必要があります。
※参照:Qiita 【PHP】特定の文字列を含むかのチェック

これはもし文の最初で一致していた場合、strposからはゼロが返ってきます。
つまり、「abcにaが含まれていない時」を表現しようと
strpos('abc' , 'a') == false とかいた場合、
0 == false となり、ゼロはfalseと同意なので
false == false (0 == 0なのかな?)のように最終的に比較され
true という結果になる、みたいです。「abcにaが含まれている」のに実行されてしまいます。

無理くりまとめると、

部分一致している時に実行 :strpos('abc' , 'a') !== false
部分一致していない時に実行:strpos('abc' , 'a') === false
と書きましょう

PHP/array_values/配列の全ての値を返す

この関数により、連想配列を普通の配列としたり、添字が飛んでいる配列の添字を振り直すことができるみたいです。

PHP/日付の取得

今年が西暦何年か「西暦year年」(yearは今年の西暦)と出力して下さい。

<?php
$year = date('Y');
echo '西暦'.$year.'年';
?>

date関数でした。。。
引数のフォーマットで日時を返します。
date('Y')

初めてのPHP 2

凡ミスはなくしたい。Javaでも共通のプログラミング初心者あるある。
自分ではこの段階は卒業したと思っています。

  • クォート内とコメント以外は全角文字不可
  • セミコロンとコロンの打ちまつがえ
  • 行末の;セミコロン忘れ

てっとり早いFixはIDEを使うこと。
スペース・タブ記号や行番号を表示させておきたい。

2016年12月23日金曜日

初めてのPHP


周りでPHPを始めた人がいたので、自分も乗っかってみました。
まずはドットインストールから入り、適当な書籍に移っていこうと思います。
ドットインストールのPHP入門講座を見てみたり、paizaでレベルDの超簡単な問題をPHPで書いたり、ドキュメントをググったりして得た気づきをリストアップします。



環境

  • 概要:MacOSにvagrant + virtual BOXでcent osを載っけてPHP5
  • Host OS: MacOS El Capitan 10.11.6
  • Guest OS:centos 6.6
  • PHP: 5.6.29
  • Vagrant: 1.9.1
  • Virtual Box:5.1.12



気づき

PHPの由来
SlideShare PHP基礎勉強会より引用
Hypertext Preprocessor(ハイパーテキストプリプロセッサー)
元々PHPは「Personal Home Page」(パーソナルホームページ)の略でしたが、1998年にリリースされたPHP3から意味が変更されました。

コメント
1行コメントは // , # どっちもいける
複数行は /* */

文末は;セミコロン
そのまんま

閉じタグ
PHPしか書かない時は、<?phpの閉じタグ(?>)は書かなくていい

php? PHP?
ロゴは小文字ですが、公式サイトの文章内ではPHPと大文字でした

ビルドインサーバを実行できる
ドキュメントルートに移動して、「php -S 192.168.33.10:8000」
アクセスログやエラーログが標準出力される。

メソッド名間違えただけでも HTTP Response Statusが500 Internal Server Errorになるみたい
試しにechoメソッドをechooにしてみてから、そのファイルにアクセスしたところ、
500 Internal Server Errorとなった。
テンプレートエンジンとは違い、シビアですね。

ログはわかりやすい。
[Fri Dec 23 10:59:32 2016] 192.168.33.1:59552 [500]:
 / - syntax error, unexpected '"hello from the TOP!"'
 (T_CONSTANT_ENCAPSED_STRING) in /home/vagrant/php_lessons/index.php on line 8
実際のindex.phpの8行目
 echoo "hello from the TOP!";

変数
変数の宣言およびアクセスは「$変数名」
アクセスする際は、「{$変数名}」も可
宣言に「$」をつけることを除けばシェルスクリプトと同じ。
動的型付け言語。変数宣言時に型の指定が不要。
perlみたいに条件判定は柔軟に行えるかな?

var_dump(変数)
変数の型を取得する

 $msg = "hello from the TOP!";
 var_dump($msg);

string(19) "hello from the TOP!"

定数
defineメソッドで定義する。
define(定数名, 値);

また、アプリケーションが持つ定数がある。
__LINE__(行数), __FILE__(ファイル名), __DIR__(ディレクトリ名)

**
PHP5.6からはべき乗の演算子が使える。
Javaだとpow()関数ですね。

単項演算子
インクリメントは前置も後置も対応している。
x++
++x

""'(ダブルクォート) , ''(シングルクォート)の文字列の扱いの違い
シェルスクリプトなんかと同じですが、""は変数を展開します。
一方、''は変数を展開せず、入力した値の通りに扱います。
また、特殊文字(\t, \n)も同じように""だと展開される。

文字列の連結
.(ドット)でつなげる。ここはperlと同じ。
.=(複合代入演算子)も大丈夫。

エルスイフはelseif
ここの表記は言語間で統一してくれ...

==, ===
JSでよく話題に上がるアレ
===だと型まで判定に含めるので、数値の1と文字列の1は別。
==だと数値の1も文字列の1も同じだと見なす。
Javaだと型を変換する必要があり面倒くさいから、ここら辺はPHPだと助かる。

標準入力
fgets(STDIN)で標準入力を取得できます。

False
文字列:空、"0"
数値: 0、0.0
論理値:false
配列: 要素の数がゼロ
null

True
文字列:(空、"0")以外
数値: (0、0.0)以外
論理値:true
配列: 要素の数が1以上

SWITCH句
文字列で分岐できる!
Javaじゃできん。

DO-WHILEだけ;が必要
CもJavaもPHPも、while句では;いらないけど、
do-whileだと;が必要なんですね。。。

連想配列と一般的な配列の区切りが少ない?
一般的な配列も、keyをゼロから連番で振っている連想配列だと考えることもできると気づきました。
要素の値を取り出す際は、配列名[添字またはkey名]

foreach ($arrays as $key => $value) { }
配列のkey-valueを取り出せる。
Java : for (int seiseki: data){ }
Javaだとオブジェクトも取り出せますね。
一方、PHPはオブジェクト取り出せないように見えますが、keyとvalueの取り出しがわかりやすい。
またPHPのforeachは、次のようにも書ける。
foreach ($colors as $values) :
  echo "$values\n";
endforeach;

function
JSか。。。
引数の初期値を設定できるのは斬新
function greet($word = "Hi"){ }
また、PHPは動的型付けなので、関数の戻り値も設定しないんですね。

スコープ
スコープ外の変数にアクセスしてもnullとなるだけ。
Javaみたいに例外でプログラムが止まったりしない。楽ですね。
まぁ見つけづらくなるというデメリットがありますが。

try-catch-finally句
PHP5.5以降でfinally対応。




セッション関連

ドットインストールやQiitaの記事( Cookieとセッションをちゃんと理解する )を参照しました。

クッキー

ブラウザが持つ
そのため改ざんが比較的容易
大きなデータは持てない

PHPセッション

HTTPセッションと紛らわしい。。。
サーバが持つ
そのため改ざんが比較的困難
大きなデータも持てる
$_SERVER['REQUEST_METHOD']
HTTP REQUESTの種類を取り出す

$_POST['パラメータ名']
bodyに含まれるパラメータの値を取り出す

htmlspecialchars(文字列, ENT_QUOTES, 文字コードを示す文字列)
文字列のエスケープ

setcookie("username", "hoge");
クッキーを保存する
同じブラウザの違うタブでもアクセスできる
第3引数に有効期間を設定できる(デフォルトはブラウザを閉じるまで)

$_COOKIE['キー']
クッキーを取り出す

session_start();
HTTPセッションをまたぐパラメータのやり取りを可能にする。
このsession_startのセッション(区別のため「PHPセッション」と呼ぶべきか)の
スコープ(生存期間)がよくわかっていない。

$_SESSION['パラメータ名']
HTTPセッション間でのパラメータ

unset($_SESSIN['パラメータ名'])
HTTPセッション間でのパラメータを破棄するメソッド




関数リスト

echo ""
文字列の出力

ceil($int);
切り捨て

floor($int);
切り上げ

round($int);
四捨五入

rand(1, 6);
引数1から、引数2までの整数をランダムに取得

strlen($str);
文字列の長さを返す
strlen(ネコ)が6で返ってきたので、びっくり。
全角文字は絶対2バイトだと勘違いしていましたが、調べたところ、UTF-8だと1-6バイトのいずれかになるらしいです。

mb_strlen($str);
マルチバイト文字の文字列の長さを返す
mb_strlen(ネコ)は2です。
第2引数に文字コードを明記できます。

printf
お馴染みのフォーマット指定の出力

count(配列名)
要素の数を返す

implode("文字", 配列)
文字で、配列を連結した文字列を返す

explode("文字", 文字列);
implodeの逆
文字で、文字列を分割した配列を返す



クラスとインスタンス


だいたいJavaと同じっぽい。助かった。。。


コンストラクタ
__construct()と書く

メンバ
$this->変数と書く
※変数の前に$はつけない!

extends
継承。
Javaと同じく多重継承できない。
多重継承と同じ効果は、interfaceを通して実現する

final
子クラスで上書き不可を示す修飾子

public, protected, private, default
アクセス修飾子
privateは自クラスのみアクセス可、子クラスからもアクセス不可。
protectedは自クラスと子クラスからアクセス可。
publicはどこからでもアクセス可
公式ドキュメントには、「アクセス権 (visibility) 」と記載されている。
varを使ってプロパティを宣言した場合や、メソッドにアクセス権を明記しない場合は、public扱いです。

static
クラスをインスタンス化しないでアクセスできるようにする修飾子。
クラスメソッドの呼び出しは クラス名::メソッド()
クラスプロパティへのアクセスは、self::$プロパティ名

abstract
抽象クラスであることを示す修飾子




コードの分割

requireとrequire_onceの違いを調べてて、
PHPってインタプリタ言語なんだなって痛感しました。
Javaだとクラスファイルを書き分けるために、ソースコードを分ける場合がほとんどだと思います。
PHPだと、「一連の処理だけ別のファイルに書き出す」ってこともできるみたいです。
requireやincludeでファイルを読み込んだ時点で、その中の処理が実行される場合があるということです。
あと、「ファイルパスは絶対パスで書こう」意見を見つけました。
マコトのおもちゃ箱 ~ぼへぼへ自営業者の技術メモ~ 「PHP、require、includeする時の注意点。」
振り返ってみると、Javaのパッケージ読み込みはフルパスですね。
そういえば、PHPのIDEは何がpopularなのだろうか。。。
require
「君が絶対必要なんだ!」ということで、指定したファイルがなきゃ実行しない。(fatal error)

include
を含む。なかったら警告を出す。プログラムは止まらない。

require_once / include_once
同じファルは2回読み込まない。
アプリ全体でカウントするのか、特定の呼び出し元ファイル内だけでカウントするのかがわからない。
困った時に調べよう。

autoload
未定義のクラスについて、そのクラス名でファイルを探索して読み込む。
便利!

sql_autoload_register(function($class){
  require 
});
これで未定義のクラスについて、自動で読み込んでくれます。

クラスファイルを読み込み忘れた時
こんなエラーメッセージで怒られる。status 500。。。。
[Fri Dec 23 20:10:21 2016] 192.168.33.1:52369 [500]:
 / - Class 'User' not found in /home/vagrant/php_lessons/index.php on line 12

namespace hoge\Lib;
階層の区切りが\です。
<html>要素の中に書いたらダメ。
ファイルの冒頭にphpタグを入れて、その中に書く。

use 名前空間 as 別名;
名前空間に別名をつけることができる。



PHP IDEの考察

考察と言ってもググってTOP5の記事をブラウズしただけですが(^^;
自分が最も助かった記事はグーグル順位5位のこちらの記事でした。
BULBLUB WEBの仕事をしている建築士のブログ 「PHP向けIDEリスト[PHPSTORM, NETBEANS, APTANA STUDIO, ECLIPSE]」
個人的にEclipseを試してみます。
理由は2つあり、

  1. Javaでたまにお世話になっているので、UIに違和感がない
  2. 本当はPhpStromを使いたいが、メイン言語ではないPHPのIDEに$89は出せない
です

SQLインジェクション対策もれの責任を開発会社に問う判決 | 徳丸浩の日記

SQLインジェクション対策もれの責任を開発会社に問う判決 | 徳丸浩の日記


WEB+DBマガジンか、Software Designかどちらかの雑誌に載っていたので、直接ブログエントリーを読んでみました。


2009年4月15日のウェブサイト稼働開始時点ではクレジットカード情報を扱っていなかったことから、僕はこの判決は原告に甘すぎるのではないかと思いました。このウェブサイト向け商品受注システムがどのような商品を扱っているかはわかりませんが、初めはクレジットカードをサーバに格納しない状況だったので、セキュアなシステム要件を暗黙に認めるかというと微妙なのではと考えました。


一方、被告にまったく非がないかと言えば、非はあったようです。管理ユーザーIDPWがデフォルトでよく使われるもので、あまりセキュリティを意識していないような成果物だったようです。


この判決は、昨今のセキュリティへの問題意識の高まりを汲んだものではないかと、私は穿った見方をしています。何はともあれ、今後のシステム開発の現場では、IPAが発表しているセキュリティ対策やチェックは必須だと考えないといけないですね。

2016年12月21日水曜日

C言語を復習してみた

ドットインストールさん、お世話になっています。
周りにC言語を始めた方がいたので、ドットインストールを使って復習してみました。

気になった点だけメモする。

  • string型はないので、文字列はcharの配列
  • 文字列の終端は「\0」
  • 配列は、宣言と同時に初期化する場合は、要素数の指定不要(初期化した要素数となる)
  • ローカル変数にstaticをつけると、関数が終わっても値を保持する
  • Javaはcに似ている(if/for/while/switch)
  • コンパイルめんどくさい。。。
  • モジュールのインポートは#include
  • whileはブロックなのに対して、do-whileは文(do-whileの末尾にセミコロンが必要)
  • ポインタの宣言時には、名前の前に*をつける
  • 変数のアドレスを取り出す際は、変数名の前に&をつける(先頭のアドレス位置を取り出す)
  • ポインタ名の前に*をつけることで、ポインタに格納されているアドレスの位置、を示す領域が持つ値を取り出せる。

2016年12月17日土曜日

Java

コーディング力上げたいな。 もっというと、要件やテストケースの理解力が大事ですね。

Paizaさんのコンテンツで遊んでたけど、六村リオの緊急事態 (Bランク問題)のテストケース4で失敗する。。。悔しか。。。



/////////////////
// code
/////////////////
import java.util.*;

public class Main {
    public static void main(String[] args) {
        // 自分の得意な言語で
        // Let's チャレンジ!!
        Scanner sc = new Scanner(System.in);
        String line = sc.nextLine();
        String[] tempArray = line.split(" ", 0); 
        String[] currentDir = tempArray[0].split("/",0);
        ArrayList path = new ArrayList( Arrays.asList(currentDir) );
        String[] targetPath = tempArray[1].split("/",0);
        // System.out.println( Arrays.toString(currentDir) );
        // System.out.println( Arrays.toString(targetPath) );
        
        String output = "/";
        int position = path.size() - 1 ;
        // System.out.println(position);
        for ( String dir : targetPath ) {
            if ( dir.equals("..") ) {
                position =  ( position == 0 ) ? position : --position;
                
            } else if ( dir.equals(".") ) {
                continue;    
            } else if (  ! path.get( position ).equals(dir)  ) {
                path.add( position + 1  ,dir);
                position++;
            }
        }
        
        for ( int i = 1; i < position + 1  ; i++ ) {
            output += path.get(i) ;
            if ( i < position  ) {
                output += "/";
            }
        }
        System.out.println(output);
    }
}

MicrosoftもFlashと距離をおきますか。。。

マイナビニュース マイクロソフトもEdgeからFlashを排除の方向

HTML5によるコンテンツ配信がデフォルトですね

2016年12月10日土曜日

what3words

日本だと需要ないだろうけど、面白いサービス

全世界の住所を3x3meterで分割し、それぞれのブロックを英単語3語を組み合わせたURLで特定する。 ちなみに東京六本木は下記のURLになりました。
http://w3w.co/brittle.writings.coached

モンゴルの郵便公社がサービスを利用するのだとか
http://gigazine.net/news/20160626-mongolia-three-word-address/