PHPからSQLに接続する

記録用

##準備
###DBに接続する

読み込めば接続できるファイルを作っておく

```php:dbh.php
<?php //dbh.php

$dsn = 'mysql:host=ホストアドレス;
        dbname=接続するDB名;
        charset=utf8mb4';
//charset=utf8mb4はutfの前4byteを参照して比較するために変更する (詳細は寿司ビール問題)

//$dsn = 'mysql:host=localhost;
//        dbname=DB_name;
//        charset=utf8mb4';
//基本はこんな感じ

$user = '接続するDBのユーザーネーム';
$pass = '接続するDBのパスワード';

$options = [
    \PDO::ATTR_EMULATE_PREPARES => false, // 静的プレースホルダにする //セキュリティの強化
    \PDO::MYSQL_ATTR_MULTI_STATEMENTS => false, // 複文を禁止する
    \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION, // エラー時に例外を投げる
    ];

try {
    //ここでpostしている
    $dbh = new PDO($dsn,$user,$pass,$options);
}catch(\PDOException $e){
    echo 'Error\n';
    echo $e->getMessage();
    exit;
}
```

##接続

↓サンプルコード

```php:sample.php
<?php 
ob_start();//これを入れるとheaderでエラーが出なくなる(要詳細)
require_once(__DIR__.'./dbh.php');

//入力データを取得
$id  = $_POST['id'] ?? '';
$pw  = $_POST['pw'] ?? '';
$pw2  = $_POST['pw2'] ?? '';

//validate
if( ('' === $id)
    ||('' === $pw)
    ||('' === $pw2)
    ){
    echo '入力が足りません';
    exit;
}
if($pw !== $pw2){
    echo 'パスワードが一致しません';
    exit;
}
if(129 < strlen($id)){
    echo 'idが長すぎます (128文字以下)';
    exit;
}

//ユーザーを登録したい
try {$sql = 'INSERT INTO users(user_id,password,created_at)
            VALUES(:user_id, :password, :created_at);';
    $pre = $dbh->prepare($sql);

    //値をバインド
    $pre->bindValue(':user_id',$id,PDO::PARAM_STR);
    $pre->bindValue(':password',password_hash($pw , PASSWORD_DEFAULT),PDO::PARAM_STR);
    $pre->bindValue(':created_at',date('Y-m-d H:i:s'),PDO::PARAM_STR);

    //SQLを実行
    $r = $pre->execute();
} catch(Throwable $e){
    //xxx
    echo $e->getMessage();
    exit;
}

//完了画面の出力

header('Location: ./completed.html');
```

###読み込み
```php
require_once(__DIR__.'./dbh.php');
```
require_onceで上で作ったdbh.phpを読み込み
ちな、`__DIR__.`は現在のファイルの場所を意味する

###validate
[validate](https://e-words.jp/w/%E3%83%90%E3%83%AA%E3%83%87%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3.html)
簡単に説明するならデータチェック

サンプルのパスワードはこれ

```php
if( ('' === $id)
    ||('' === $pw)
    ||('' === $pw2)
    ){
    echo '入力が足りません';
    exit;
}
if($pw !== $pw2){
    echo 'パスワードが一致しません';
    exit;
}
if(129 < strlen($id)){
    echo 'idが長すぎます (128文字以下)';
    exit;
}
```

特に決まった書き方はないため必要最低限はここで弾いておく

###DBにレコードを追加

```php
//ユーザーを登録したい
$sql = 'INSERT INTO users(user_id,password,created_at)
        VALUES(:user_id, :password, :created_at);';
$pre = $dbh->prepare($sql);

//値をバインド
$pre->bindValue(':user_id',$id,PDO::PARAM_STR);
$pre->bindValue(':password',password_hash($pw , PASSWORD_DEFAULT)PDO::PARAM_STR);
$pre->bindValue(':created_at',date('Y-m-d H:i:s'),PDO::PARAM_STR);

//SQLを実行
$r = $pre->execute();
```
###[prepare](https://www.php.net/manual/ja/pdo.prepare.php)

`$sql`にSQL文を書き込む
`prepare`で準備をする

```php
$sql = 'SQL文';
$pre = $dbh->prepare($sql);
```
ここは基本構文
サンプルの場合はSQL文内のVALUESで指定した値を変更し追加できる

詳細は`プリペアドステートメント`で検索

###[bindValue](https://www.php.net/manual/ja/pdostatement.bindvalue.php)

```php
//値をバインド
$pre->bindValue(':user_id',$id,PDO::PARAM_STR);
$pre->bindValue(':password',password_hash($pw , PASSWORD_DEFAULT)PDO::PARAM_STR);
$pre->bindValue(':created_at',date('Y-m-d H:i:s'),PDO::PARAM_STR);
```
SQLにValueを仕込んだので`bindValue`で値を変更できるようになった


###[execute](https://www.php.net/manual/ja/pdostatement.execute.php)

```php
$r = $pre->execute();
```
`execute`で実行というか今まで書いていたレコードの保存をする
`$r`にはレコードの実際のが入る