Contents
Thread Safe版をダウンロードすべし
PHPをダウンロードする際は、Thread Safeを選択する。一番上にあるNon Thread Safeには大事なモジュール(php7apache2_4.dllなど)が含まれていないので避ける(参照)。
VS Codeでデバッグする
Node.jsやPythonだとなにもファイルをつくらなくてもデバッグできるのだが、PHPだとデバッグしたいファイルと同階層の.vscodeフォルダの下にlaunch.jsonをつくる必要がある。内容は
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
{ // IntelliSense を使用して利用可能な属性を学べます。 // 既存の属性の説明をホバーして表示します。 // 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "name": "Listen for XDebug", "type": "php", "request": "launch", "port": 9000 }, { "name": "Launch currently open script", "type": "php", "request": "launch", "program": "${file}", "cwd": "${fileDirname}", "port": 9000 } ] } |
コマンドラインで動くPHPスクリプトは、「Launch currently open script」を選択してデバッグする。「Listen for XDebug」のほうはたぶんサーバー上で実行されるPHPスクリプトをデバッグするのに使うんだと思うんだがいまのところよくわからん。
Node.jsやPythonでは右下に構成の追加というのがでてきてそれをクリックすると自動でlaunch.jsonをつくってくれるのだが、PHPは手動でつくらなければならないということでメモした。フォルダごとにいちいちlaunch.jsonをつくらないといけないのが面倒だなー。settings.jsonはデフォルトのものがあって、カレントフォルダフォルダの.vscode以下につくるとデフォルトに上書きされるという仕組みなのだが、launch.jsonもこれとおなじ感じならいいのに。
クッキーとセッション
クッキー
1 |
setcookie('name', 'shimada'); |
とすると、いまつくっているレスポンスのヘッダーのset-cookieフィールドに「name=shimada」が追加される。
1 2 |
setcookie('name', 'shimada'); echo 'cookie:' . $_COOKIE['name']; |
としても初回はクッキーを表示することはできない。2度目以降は表示できる。それはsetcookie()は$_COOKIEをいじっているわけではなく、レスポンスヘッダーのset-cookieフィールドをいじっているからである。
セッション
1 |
session_start(); |
とするとレスポンスヘッダーのset-cookieフィールドに「PHPSESSID=a10de7af5a45cc532e06289e495cbaac;」のようにランダムに生成されたセッションIDが書き込まれる。
session_start()したあと
1 |
$_SESSION['name'] = 'shimada'; |
のように$_SESSIONに代入するとサーバー側に保存される。
間違いやすいのは、セッションとクッキーを混同して
1 |
$_COOKIE['name'] = 'shimada'; |
のようにしてしまうこと。$_COOKIEに代入してもクッキーは操作できない。$_COOKIEに代入することは基本的にないはず。
ただし、$_COOKIEで条件分岐をしているときなど、$_COOKIEにデフォルト値を代入したことはある。
セッションはセッションIDとだけ紐づけられている(っぽい)
サーバー側に保存されるセッションの情報は、おそらくセッションID + IPアドレスと紐づけらるんだろうと思っていたが、セッションIDとだけ紐づけられるっぽいな。
セッションハイジャックというのがあって、セッションIDが盗まれるとほかのコンピューターからもアクセスできるらしいので、セッションIDとだけ紐づけられていると思われる。
また、ネット接続を切ってIPアドレスが切り替わってもセッションが維持されていると思われるWebサービスを多数経験していることからも、セッションIDのみで管理しているのだと思う。
傍証として、FirefoxでアクセスしてつくられたセッションIDをChromeにコピーしてアクセスすると、セッションの情報をとることができた。もちろんブラウザーを変えただけではIPアドレスが変わらないので、たしかな証拠ではないのだが。
SQLite3を使う
php.iniに以下の2行を追加。
1 2 |
extension="E:\App\php\ext\php_sqlite3.dll" extension="E:\App\php\ext\php_pdo_sqlite.dll" |
PDOで接続するなら2行目だけ追加すればいいとは思うが、ほかの方法で接続することもあるかもしれないのでついでに1行目も追加。
あとでわかったのだが、以下のようにしてもいい。
1 2 3 |
extension_dir = "E:\App\php\ext" extension=php_sqlite3 extension=php_pdo_sqlite |
DB(pythonでつくったbooks.sqlite3)へ接続し(例外処理は省く)、試しに中身をぜんぶ表示してみる。
1 2 3 4 5 6 7 8 |
$db = new PDO('sqlite:./books.sqlite3'); $books = $db->query('select * from books'); foreach ($books as $book) { echo $book['title'] . $book['auther'] . '\n'; } $db = null; |
.phpファイルとbooks.sqlite3ファイルをFTPソフトでそのまんまレンタルサーバー(ロリポップ)にアップロードして動かしたらうまくいった。お手軽でよい。個人用であればMySQLとか触る必要なしな感じ。
PDOからMySQLにアクセスする
これが基本形。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
define('DB_DATABASE', 'データベース名'); define('DB_USER', 'ユーザー名'); define('DB_PASSWORD', 'パスワード'); define('DB_DNS', 'mysql:dbhost=localhost;dbname=' . DB_DATABASE); try { $db = new PDO(DB_DNS, DB_USER, DB_PASSWORD); // エラーが出たときに例外を投げるようにする。これがないと例外を投げない。 $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // ここに処理を書く $db = null; // 接続を切る } catch (PDOException $e) { echo $e->getMessage(); exit; } |
必要な情報は接続したいデータベース名と、それにアクセスできるユーザー名とパスワードとホスト名。
SQL文をデータベースに投げるにはexec, query, prepareの3つのメソッドがある。
1 |
$db->exec("insert into users (name, score) values ('shimada', 55)"); |
execは結果を返さない安全対策の必要がないSQLに使われる。
1 2 3 4 5 6 |
$stmt = $db->query('select * from users;'); $users = $stmt->fetchAll(PDO::FETCH_ASSOC); foreach($users as $user) { echo $user['name'] . ' ' . $user['score'] . "<br>"; } |
queryは結果を返して安全対策の必要がなく1回だけ実行されるSQLに使われる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
$stmt = $db->prepare('select * from users where score > ?;'); $stmt->execute([20]); $users = $stmt->fetchAll(PDO::FETCH_ASSOC); foreach($users as $user) { echo $user['name'] . ' ' . $user['score'] . "<br>"; } $stmt->execute([3]); $users = $stmt->fetchAll(PDO::FETCH_ASSOC); foreach($users as $user) { echo $user['name'] . ' ' . $user['score'] . "<br>"; } |
prepareは結果を返して安全対策が必要で複数回実行されるSQLに使われる。
表にまとめておく。
メソッド | 結果 | 回数 | 安全対策 |
---|---|---|---|
exec | 返さない | 1回 | 必要ないとき使われる |
query | 返す | 1回 | 必要ないとき使われる |
prepare | 返す | 複数回 | 必要あるとき使われる |
安全対策というのを具体的にどうやるのかはいまはまだわからない。
レンタルサーバーのデータベースにはアクセスできない
レンタルサーバーのデータベースにアクセスできるか実験してみた。
1 2 3 4 |
define('DB_DATABASE', 'データベース名'); define('DB_USER', 'ユーザー名'); define('DB_PASSWORD', 'パスワード'); define('DB_DNS', 'mysql:dbhost=localhost;dbname=' . DB_DATABASE); |
これのdbhostをlocalhost→レンタルサーバーのデータベースサーバーに変更して、PHPAdminでデータベース名・ユーザー名・パスワードぜんぶ調べて設定したが、「SQLSTATE[HY000] [2002] 対象のコンピューターによって拒否されたため、接続できませんでした。 」というエラーになる。
考えてみればあたりまえのことだった。ユーザー名とホスト名がセットになって管理されているので、ホスト名が違うということで弾かれるのだろう。
ローカルのMySQLであればrootで入ってユーザー名とホスト名を任意に設定できるが、レンタルサーバーのMySQLではできない(できたとしたら逆にセキュリティ上まずい)。
require, require_once, include, include_onceの使い分け
こちらのページがわかりやすい。
クラスやライブラリの場合は「require_once」を使います。
基本的には、htmlファイルやテキストファイルを読み込む場合にはincludeを使用すると思っておけばよいでしょう。
以上のことからわかるように、require、include_onceは使わなくても問題ありません。
よく使う関数
CSVファイルを1行ずつ読み込みつつ、わかりやすい変数で受ける。
1 |
list($name, $age, $mail) = explode(",", $line); |
ちなみにexplodeの逆の関数はimplode。配列の要素を連結して文字列をつくる。