「PHPとデータベース - MySQL」の版間の差分

提供:MochiuWiki - SUSE, Electronic Circuit, PCB
ナビゲーションに移動 検索に移動
 
(同じ利用者による、間の7版が非表示)
1行目: 1行目:
== 概要 ==
== 概要 ==
PHPにおいて、MySQLへの接続とCRUDの手順を記載する。<br>
PHPにおいて、MySQLへの接続とCRUDの手順を記載する。<br>
<br><br>
== 環境設定 (Windowsのみ) ==
PHPでMySQLを使用できるように、php.iniファイルの設定を変更する。<br>
# php.iniファイル
# 編集前
;extension=php_mysql.dll
# 編集後
extension=php_mysql.dll
<br><br>
<br><br>


57行目: 68行目:
     // データベースの接続を閉じる
     // データベースの接続を閉じる
     mysqli_close($link);
     mysqli_close($link);
?>
</syntaxhighlight>
<br>
また、MySQLへ接続するには、PDO拡張モジュールを使用することもできる。<br>
<u>PDO拡張モジュールは、PHP 5.1から使用できる。</u><br>
<br>
PHP Data Objects(PDO) は、データベースに接続するためのインターフェイスとして機能する拡張機能である。<br>
mysqliとは異なり、あらゆるデータベース機能を実行することができ、MySQLに限定されるものではない。<br>
データベース間の柔軟な連携を可能であり、mysqliよりも汎用的である。<br>
<br>
PDOは、サーバ側とクライアント側のプリペアドステートメントをサポートしている。<br>
<br>
PDOの大きな強みは、クエリで起こりうるあらゆる問題に対処するための例外クラスを持っていることである。<br>
これは、try-catchブロックを組み込むことによってこれらの問題を解決する。<br>
<br>
以下の例では、PDO拡張モジュールを使用して、MySQLサーバへ接続している。<br>
<syntaxhighlight lang="php">
<?php
    $host    = "localhost";
    $username = "username";
    $passwd  = "password";
    $dbname  = "mydb";
    $charset  = "utf8mb4";
    try {
      # DSN(database source name)は、データベースの種類と名前、およびその他の追加情報を定義する
      # PDOは様々な種類のデータベースをサポートしているため、別のデータベースを使用している場合は、構文(mysql)の部分を使用しているデータベースに置き換える
      $dsn = "mysql:host=$host; dbname=$dbname; charset=$charset";
 
      # PDOコンストラクタは、データベースへの接続を確立する
      # 3つのパラメータを持っており、データソース名(dsn)、データベースのユーザ名、データベースのパスワードである
      $pdo = new PDO($dsn, $username, $passwd);
      # PDOにパラメータを設定するsetAttributeメソッド
      # PDO::ATTR_ERRMODEおよびPDO::ERRMODE_EXCEPTIONは、クエリが失敗した場合に例外を実行するようにPDOに指示する
      $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
      echo "Connection Okay";
      # データベースに接続するためのPDO変数を返す
      return $pdo
    }
    catch (PDOException $e)
    {  # 接続に失敗した場合はエラーメッセージを表示する
      echo "Connection failed: ". $e->getMessage();
    }
  ?>
  ?>
  </syntaxhighlight>
  </syntaxhighlight>
623行目: 680行目:
  </syntaxhighlight>
  </syntaxhighlight>
<br><br>
<br><br>
== パラメータをエスケープする ==
SQL文で使用する値が固定値の場合は問題無いが、例えば、フォーム等に入力した条件を使用してSQL文を生成する場合、<br>
SQLインジェクション攻撃を防ぐためにパラメータをエスケープする必要がある。<br>
<br>
エスケープするためには、<code>mysqli_real_escape_string</code>関数を使用する。<br>
<br>
string mysqli_real_escape_string(mysqli link_identifier, string escapestr)
現在使用している文字コードで、escapestrの特殊文字をエスケープして、mysqli_query関数で安全に利用できる形式に変換する。
バイナリデータを挿入する場合は、必ず、mysqli_real_escape_string関数を使用しなければならない。
引数:
    link_identifier  MySQLリンクID
    escapestr  エスケープされる文字列
戻り値:
    成功する場合はエスケープ後の文字列、失敗する場合はfalseを返す。
<br>
マジッククオートを有効化している場合も似たような効果が得られるが、<br>
マジッククオートは無効化して、<code>mysqli_real_escape_string</code>関数を使用して必要に応じてエスケープすることが推奨されている。<br>
<br>
例えば、SQL文において、値にシングルクォーテーション(')等が含まれる場合、<br>
<code>mysqli_real_escape_string</code>関数を実行することで、SQL文で直接記述できない値に対して<code>\</code>を付加してエスケープ処理を自動的に行う。<br>
<syntaxhighlight lang="php">
$test = "book's";
mysqli_real_escape_string($test);  //--> $test = "book¥'s"
</syntaxhighlight>
<br>
以下の例では、POSTで送信されたユーザ名とパスワードをエスケープ処理を実行してSQL文を生成している。<br>
<syntaxhighlight lang="php">
function quote_smart($link, $value)
{
    // 数値以外をクオートする
    if(!is_numeric($value))
    {
      $value = "'" . mysqli_real_escape_string($link, $value) . "'";
    }
    return $value;
}
$query = sprintf("SELECT * FROM users WHERE user=%s AND password=%s", quote_smart($_POST['username']), quote_smart($_POST['password']));
mysqli_query($link, $query);
</syntaxhighlight>
<br>
以下の例では、上記のセクションのINSERT文を書き直している。<br>
<syntaxhighlight lang="php">
<?php
    function quote_smart($link, $value)
    {
      // 数値以外をクオートする
      if(!is_numeric($value))
      {
          $value = "'" . mysqli_real_escape_string($link, $value) . "'";
      }
      return $value;
    }
    $link = mysqli_connect('localhost', 'user', 'passwd', 'uriage');
    if(!$link)
    {
      die('接続失敗です。'.mysqli_error());
    }
    print('<p>接続に成功しました。</p>');
    $db_selected = mysqli_select_db($link, 'uriage');
    if(!$db_selected)
    {
      die('データベースの選択に失敗しました。'.mysqli_error());
    }
    print('<p>uriageデータベースを選択しました。</p>');
    // 文字コードをutf8mb4 に変更
    if(!mysqli_set_charset($link, "utf8mb4"))
    {
      printf('文字コードの変更に失敗しました。'.mysqli_error($link));
      exit();
    }
    print('<p>レコードを追加します。</p>');
    $id = 5;
    $name = "Toyama's Wine";
    $sql = sprintf("INSERT INTO shouhin(id, name) VALUES(%s, %s)", quote_smart($link, $id), quote_smart($link, $name));
    print('<p>エスケープ後のデータ:'.quote_smart($name).'</p>');  //--> $name = Toyama¥'s Wine
    $result_flag = mysqli_query($link, $sql);
    if(!$result_flag)
    {
      die('INSERTクエリが失敗しました。'.mysqli_error());
    }
    print('<p>追加後のレコードを取得します。</p>');
    $result = mysqli_query($link, 'SELECT id,name FROM shouhin');
    if(!$result)
    {
      die('SELECTクエリが失敗しました。'.mysqli_error());
    }
    while($row = mysqli_fetch_assoc($result))
    {
      print('<p>');
      print('id='.$row['id']);
      print(',name='.$row['name']);
      print('</p>');
    }
    $close_flag = mysqli_close($link);
    if($close_flag)
    {
      print('<p>切断に成功しました。</p>');
    }
?>
</syntaxhighlight>
<br>
SQL文に含まれていたシングルクオーテーションがエスケープ処理されて、Toyama¥'s Wineに変換されていることが確認できる。<br>
このように、'のような特殊な意味を持つ文字を、単なる文字の'として処理することができる。<br>
<br><br>
== 暗号化 / 復号 ==
データベースの接続情報を暗号化する場合は、openssl_encrypt / decrypt関数を使用して暗号化 / 復号を行う。<br>
<br>
暗号化キー (ENCRYPTION_KEY) と IV(ENCRYPTION_IV) は、ソースコードとは別の場所に保管する。<br>
<br>
また、INIファイルには暗号化された値を保存する必要がある。<br>
<br>
初期設定時において、以下に示すように値を暗号化して設定ファイルに保存する。<br>
<syntaxhighlight lang="php">
$encrypted_password = encryptString('実際のパスワード');
</syntaxhighlight>
<br>
<syntaxhighlight lang="php">
// 暗号化キーとIVを安全な場所に保存する
define('ENCRYPTION_KEY', '<32[byte]の秘密鍵>');
define('ENCRYPTION_IV', '<16バイトのIV>');
// 暗号化関数
function encryptString($plaintext)
{
    $cipher = "aes-256-cbc";
    $options = OPENSSL_RAW_DATA;
    return base64_encode(openssl_encrypt($plaintext,
                                        $cipher,
                                        ENCRYPTION_KEY,
                                        $options,
                                        ENCRYPTION_IV));
}
// 復号関数
function decryptString($encrypted)
{
    $cipher = "aes-256-cbc";
    $options = OPENSSL_RAW_DATA;
    return openssl_decrypt(base64_decode($encrypted),
                          $cipher,
                          ENCRYPTION_KEY,
                          $options,
                          ENCRYPTION_IV);
}
</syntaxhighlight>
<br>
<syntaxhighlight lang="php">
// 使用例
// INIファイルから読み込んだ接続情報を復号して使用
$host    = decryptString($config['host']) ?? 'localhost';
$dbname  = decryptString($config['dbname']) ?? '';
$username = decryptString($config['username']) ?? 'root';
$password = decryptString($config['password']) ?? '';
</syntaxhighlight>
<br><br>
{{#seo:
|title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki
|keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,Podman,電気回路,電子回路,基板,プリント基板
|description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This page is {{PAGENAME}} in our wiki about electronic circuits and SUSE Linux
|image=/resources/assets/MochiuLogo_Single_Blue.png
}}


__FORCETOC__
__FORCETOC__
[[カテゴリ:Web]]
[[カテゴリ:Web]][[カテゴリ:MySQL]]

2024年11月20日 (水) 17:20時点における最新版

概要

PHPにおいて、MySQLへの接続とCRUDの手順を記載する。


環境設定 (Windowsのみ)

PHPでMySQLを使用できるように、php.iniファイルの設定を変更する。

# php.iniファイル

# 編集前
;extension=php_mysql.dll

# 編集後
extension=php_mysql.dll



MySQLの接続・切断

MySQLの接続

MySQLへ接続するには、mysqli_connect関数を使用する。

resource mysqli_connect(string host, string username, string passwd, string dbname [, int port [, string socket ]])

MySQLサーバへ接続または再利用する。

引数:
   host  接続先のMySQLサーバを指定する。
         <ホスト名またはIPアドレス>:<ポート番号>のように、ポート番号を指定することが可能であり、
         ホスト名またはIPアドレスでは、:/path/to/socketのようにソケットへのパスを指定することも可能である。

         <ホスト名またはIPアドレス>または<ホスト名またはIPアドレス>:<ポート番号>を指定する場合、
         MySQLクライアントライブラリはそれをオーバーライドして、ローカルソケット(Windowsでは名前付きパイプ)に接続する。

   username  ユーザ名

   password  パスワード

   dbname  接続するデータベース名を指定する。

   port  接続するMySQLサーバーのポート番号を指定する。

   socket  使用するソケットを指定する。

戻り値:
   MySQLサーバへの接続オブジェクトを返す。


以下の例では、MySQLサーバへ接続している。

 <?php
    // データベースへの接続に必要な変数を指定
    $host = 'localhost';  // 以下の指定方法も可能
                          // localhost:3307(ホスト名とポート番号)
                          // 127.0.0.1:3307(IPアドレスとポート番号)
                          // /tmp/mysql(ソケットのみ)
    $username = 'root';
    $passwd = 'root';
    $dbname = 'mydb';
 
    // データベースへ接続
    $link = mysqli_connect($host, $username, $passwd, $dbname);
 
    // 接続チェック
    if(!$link)
    {
       die('データベースの接続に失敗しました。');
    }
 
    echo "データベースの接続に成功しました! \n";
 
    // データベースの接続を閉じる
    mysqli_close($link);
 ?>


また、MySQLへ接続するには、PDO拡張モジュールを使用することもできる。
PDO拡張モジュールは、PHP 5.1から使用できる。

PHP Data Objects(PDO) は、データベースに接続するためのインターフェイスとして機能する拡張機能である。
mysqliとは異なり、あらゆるデータベース機能を実行することができ、MySQLに限定されるものではない。
データベース間の柔軟な連携を可能であり、mysqliよりも汎用的である。

PDOは、サーバ側とクライアント側のプリペアドステートメントをサポートしている。

PDOの大きな強みは、クエリで起こりうるあらゆる問題に対処するための例外クラスを持っていることである。
これは、try-catchブロックを組み込むことによってこれらの問題を解決する。

以下の例では、PDO拡張モジュールを使用して、MySQLサーバへ接続している。

 <?php
    $host     = "localhost";
    $username = "username";
    $passwd   = "password";
    $dbname   = "mydb";
    $charset  = "utf8mb4";
 
    try {
       # DSN(database source name)は、データベースの種類と名前、およびその他の追加情報を定義する
       # PDOは様々な種類のデータベースをサポートしているため、別のデータベースを使用している場合は、構文(mysql)の部分を使用しているデータベースに置き換える
       $dsn = "mysql:host=$host; dbname=$dbname; charset=$charset";
 
       # PDOコンストラクタは、データベースへの接続を確立する
       # 3つのパラメータを持っており、データソース名(dsn)、データベースのユーザ名、データベースのパスワードである
       $pdo = new PDO($dsn, $username, $passwd);
 
       # PDOにパラメータを設定するsetAttributeメソッド
       # PDO::ATTR_ERRMODEおよびPDO::ERRMODE_EXCEPTIONは、クエリが失敗した場合に例外を実行するようにPDOに指示する
       $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
 
       echo "Connection Okay";
 
       # データベースに接続するためのPDO変数を返す
       return $pdo
    }
    catch (PDOException $e)
    {  # 接続に失敗した場合はエラーメッセージを表示する 
       echo "Connection failed: ". $e->getMessage();
    }
 ?>



MySQLの切断

MySQLへの接続を切断するには、mysqli_close関数を使用する。

bool mysqli_close(mysqli link_identifier])

link_identifierが指すMySQLへの非持続的リンクを閉じる。
link_identifierを省略する場合、最後に開いたリンクが使用される。

持続的ではないリンクは、スクリプトの実行終了時に自動的に閉じるため、通常は、mysql_close関数は不要である。

引数:
   link_identifier  mysqli_connect関数の戻り値のリンクIDを指定する。

戻り値:
   MySQLの切断に成功する場合はtrue、失敗する場合はfalseを返す。


以下の例では、MySQLへの接続を明示的に切断している。

 $host = 'localhost';
 $username = 'root';
 $passwd = 'root';
 $dbname = 'mydb';
 
 // データベースへ接続
 $link = mysqli_connect($host, $username, $passwd, $dbname);
 
 // ...MySQLのCRUD処理
 
 mysqli_close($link);



エラー処理

MySQLに対する処理でエラーが発生する場合、mysqli_error関数を使用して、エラーメッセージを取得することができる。

string mysqli_error(mysqli link_identifier])

直近のMySQL関数からのエラー文字列を返す。
MySQLのバックエンドのエラーは警告が発生しないため、 代わりに、mysqli_error関数を使用してエラー文字列を取得する。

引数:
   link_identifier  MySQLのリンクID

戻り値:
   直近のMySQL関数からのエラー文字列を返す。
   エラーが発生していない場合は、空文字列を返す。


以下の例では、mysqli_connect関数でエラーが発生した場合にエラーメッセージを取得している。

 $host = 'localhost';
 $username = 'root';
 $passwd = 'root';
 $dbname = 'mydb';
 
 // データベースへ接続
 $link = mysqli_connect($host, $username, $passwd, $dbname);
 
 if(!$link)
 {
    print(mysqli_error());
 }
 
 // ...MySQLに対するCRUD処理
 
 mysqli_close($link);


MySQLの接続に失敗する場合、その後のMySQLに対する処理を実行できないため、
exit関数またはdie関数を使用して、プログラムを終了する。
exit関数およびdie関数の詳細は、PHPの基礎 - PHPの終了処理を参照すること。

 $host = 'localhost';
 $username = 'root';
 $passwd = 'root';
 $dbname = 'mydb';
 
 // データベースへ接続
 $link = mysqli_connect($host, $username, $passwd, $dbname);
 
 if(!$link)
 {
    die('接続失敗です。'.mysqli_error());
 }
 
 // ...MySQLに対するCRUD処理
 
 mysqli_close($link);


以下の例では、MySQLの接続と切断を実行している。

 <?php
    $host = 'localhost';
    $username = 'root';
    $passwd = 'root';
    $dbname = 'mydb';
 
    // データベースへ接続
    $link = mysqli_connect($host, $username, $passwd, $dbname);
    if(!$link)
    {
       die('接続失敗です。'.mysqli_error());
    }
 
    print('<p>接続に成功しました。</p>');
 
    // ...MySQLに対するCRUD処理
 
    $close_flag = mysqli_close($link);
 
    if($close_flag)
    {
       print('<p>切断に成功しました。</p>');
    }
 ?>



データベースの選択

MySQLへ接続後、データベースを選択するには、mysqli_select_db関数を使用する。

bool mysqli_select_db(mysqli link_identifier, string dbname)

データベース名を指定して、アクティブなデータベースに設定する。
それ以降に実行するmysqli_query関数は、全てアクティブなデータベース上で実行される。
link_identifierを指定しない場合は、直近に接続したリンクを指定したとみなされる。

mysqli_select_db関数は、接続のデフォルトデータベースを変更する際にのみ使用する。
デフォルトデータベースは、mysqli_connect関数の第4引数でも指定できる。

引数:
   link_identifier  MySQLのリンクID
   database_name  アクティブにするデータベース名

戻り値:
   成功した場合はtrue、失敗する場合はfalseを返す。


SELECT文等のクエリを発行する場合は、アクティブなデータベースに対して実行されるため、
クエリを発行する前に、データベース名を指定してデータベースを選択する必要がある。

また、存在しないデータベースを選択する場合、以下のようなエラーが表示される。

Access denied for user '<ユーザ名>'@'<ホスト名またはIPアドレス>' to databese '<データベース名>'


 <?php
    $link = mysqli_connect('localhost', 'user', 'pass', 'my_db');
    if(!$link)
    {
       die('接続失敗です。'.mysqli_error());
    }
 
    print('<p>接続に成功しました。</p>');
 
    // 現在のデフォルトデータベース名を返す
    if($result = mysqli_query($link, "SELECT DATABASE()"))
    {
       $row = mysqli_fetch_row($result);
       printf("Default database is %s.\n", $row[0]);
       mysqli_free_result($result);
    }
 
    // データベースをworldに変更する
    $db_selected = mysqli_select_db($link, "world");
    if(!$db_selected)
    {
       die('データベース選択失敗です。'.mysql_error());
    }
 
    print('<p>uriageデータベースを選択しました。</p>');
 
    // ...MySQLに対するCRUD処理
 
    $close_flag = mysqli_close($link);
    if($close_flag)
    {
       print('<p>切断に成功しました。</p>');
    }
 ?>



データの取得(SELECT文)

クエリを発行するには、mysqli_query関数を使用する。
SQL文の最後にセミコロン(;)を付加してはならないことに注意すること。

mixed mysqli_query(mysqli link, string query [, int resultmode])

指定したクエリを発行する。

引数:
   query  発行するクエリを記述したSQL。
          クエリ文字列は、セミコロンを付加してはならない。

   link_identifier  MySQLのリンクID

戻り値:
   成功した場合はtrue、失敗する場合はfalseを返す。
   SELECT、SHOW、DESCRIBE、EXPLAINの場合は、mysqli_query関数は結果オブジェクトを返す。


以下の例では、一時テーブルを作成して、レコードを10行取得している。

 <?php
    $link = mysqli_connect("localhost", "my_user", "my_password", "my_db");
 
    // 接続状況の確認
    if(mysqli_connect_errno())
    {
       printf("Connect failed: %s\n", mysqli_connect_error());
       exit();
    }
 
    // 一時テーブルの作成(結果セットを返さない)
    if(mysqli_query($link, "CREATE TEMPORARY TABLE myCity LIKE City") === TRUE)
    {
       printf("Table myCity successfully created.\n");
    }
 
    // SELECT文の実行(結果セットを返す)
    if($result = mysqli_query($link, "SELECT Name FROM City LIMIT 10"))
    {
       printf("Select returned %d rows.\n", mysqli_num_rows($result));
 
       // 結果セットを開放する
       mysqli_free_result($result);
    }
 
    // 大量のデータを取得する場合、MYSQLI_USE_RESULTを使用する
    if($result = mysqli_query($link, "SELECT * FROM City", MYSQLI_USE_RESULT))
    {
       // この結果セットが閉じるまで、サーバとやりとりする関数は一切実行できないことに注意する
       // もし、関数を実行した時、out of syncエラーが発生する
       if(!mysqli_query($link, "SET @a:='this will not work'"))
       {
          printf("Error: %s\n", mysqli_error($link));
       }
 
       // 結果セットを開放する
       mysqli_free_result($result);
    }
 
    mysqli_close($link);
 ?>


SELECT文は、テーブルから条件に合うレコードに含まれる指定フィールドの値を取得するものである。
したがって、結果として、複数のカラムの値が複数のレコード数だけ取得できる。

結果セットから実際のデータを取得するには、mysqli_fetch_assoc関数を使用する。

array mysqli_fetch_assoc(mysqli_result result)

mysqli_fetch_assoc関数は、取得した結果セットの最初のレコードの値を、連想配列で取得する。
連想配列のキーは、結果セットのカラムを表す。
mysqli_fetch_assoc関数の実行後、レコードは1行進む。

もし、2つ以上のカラムが同じフィールド名であった場合、最後に現れたカラムが優先され、以前のデータを上書きする。
同名の複数のカラムにアクセスする場合、mysqli_fetch_row関数を使用して数値添字配列を使用するか、カラム名にエイリアスを指定する。

注意
この関数により返されるフィー ルド名は、大文字・小文字を区別する。
カラムの値がNULLの場合、PHPのNULL値が代入される。

引数:
   result  クエリを発行して取得した出力セットの値

戻り値:
   取得したレコードにおいて、カラム名と値に対応する連想配列を返す。
   結果セットの全てのレコードを取得した場合は、NULLを返す。


SELECT文の出力結果には、複数のレコードが含まれる。
出力結果のレコードに対するカーソルがあり(最初は先頭の行を指す)、mysqli_fetch_assoc関数を実行する時、
カーソルがあるレコードに対する処理が行われて、処理が終わればカーソルは自動的に次のレコードに移る。
そのため、mysqli_fetch_assoc関数を連続して実行することにより、出力結果に含まれる全てのレコードに対する処理が実行できる。

mysqli_fetch_assoc関数では、現在、カーソルがあるレコードの各カラムの値を連想配列の形にして返す。

例えば、SELECT id, name from T_SampleのようなSELECT文を実行する場合、
以下のように記述することで、現在のレコードの各カラムの値を取得できる。

 $result = mysqli_query($link, 'SELECT id, name from T_Sample');
 
 $row = mysqli_fetch_assoc($result);
 print($row['id']);
 print($row['name']);


クエリの出力結果に含まれる全てのレコードを取得するには、以下のように記述する。

 $result = mysqli_query($link, 'SELECT id, name from T_Sample');
 
 while($row = mysqli_fetch_assoc($result))
 {
    print($row['id']);
    print($row['name']);
 }


以下の例では、データベースuriageのテーブルshouhinから該当する全てのレコードを取得している。

 <?php
    $link = mysqli_connect('localhost', 'user', 'passwd', 'my_db');
    if(!$link)
    {
       die('接続失敗です。'.mysqli_error());
    }
 
    print('<p>接続に成功しました。</p>');
 
    $db_selected = mysqli_select_db($link, 'uriage');
    if(!$db_selected)
    {
       die('データベースの選択に失敗しました。'.mysqli_error());
    }
 
    print('<p>uriageデータベースを選択しました。</p>');
 
    // 文字コードをutf8mb4 に変更
    if(!mysqli_set_charset($link, "utf8mb4"))
    {
       printf('文字コードの変更に失敗しました。'.mysqli_error($link));
       exit();
    }
 
    $result = mysqli_query($link, 'SELECT id,name FROM shouhin');
    if(!$result)
    {
       die('クエリが失敗しました。'.mysqli_error());
    }
 
    while($row = mysqli_fetch_assoc($result))
    {
       print('<p>');
       print('id='.$row['id']);
       print(',name='.$row['name']);
       print('</p>');
    }
 
    $close_flag = mysqli_close($link);
    if($close_flag)
    {
       print('<p>切断に成功しました。</p>');
    }
 ?>


※注意
MySQLの設定によっては文字化けを引き起こすため、SELECT文等の出力結果を取得する前に、
mysqli_set_charset('utf8mb4');等を実行して、MySQLのクライアントの文字コードを変更すること。


レコードの追加(INSERT)

INSERT文の場合、mysqli_query関数の出力結果において、成功する場合はtrue、失敗する場合はfalseを返す。

以下の例では、データベースuriageのテーブルshouhinにレコードを挿入している。

 <?php
    $link = mysqli_connect('localhost', 'user', 'passwd', 'uriage');
    if(!$link)
    {
       die('接続失敗です。'.mysql_error());
    }
 
    print('<p>接続に成功しました。</p>');
 
    $db_selected = mysqli_select_db($link, 'uriage');
    if(!$db_selected)
    {
       die('データベース選択失敗です。'.mysql_error());
    }
 
    print('<p>uriageデータベースを選択しました。</p>');
 
    // 文字コードをutf8mb4 に変更
    if(!mysqli_set_charset($link, "utf8mb4"))
    {
       printf('文字コードの変更に失敗しました。'.mysqli_error($link));
       exit();
    }
 
    print('<p>データを追加します。</p>');

    $sql = "INSERT INTO shouhin(id, name) VALUES(4, 'プリンター')";
    $result_flag = mysqli_query($link, $sql);
    if(!$result_flag)
    {
       die('INSERTクエリが失敗しました。'.mysql_error());
    }
 
    print('<p>追加後のデータを取得します。</p>');
 
    $result = mysqli_query($link, 'SELECT id, name FROM shouhin LIMIT 10 ORDER BY id');
    if(!$result)
    {
       die('SELECTクエリが失敗しました。'.mysql_error());
    }
 
    while($row = mysqli_fetch_assoc($result))
    {
       print('<p>');
       print('id='.$row['id']);
       print(',name='.$row['name']);
       print('</p>');
    }
 
    $close_flag = mysqli_close($link);
    if($close_flag)
    {
       print('<p>切断に成功しました。</p>');
    }
 ?>



データの更新(UPDATE)

UPDATE文の場合、mysqli_query関数の出力結果において、成功する場合はtrue、失敗する場合はfalseを返す。

以下の例では、データベースuriageのテーブルshouhinのレコードを更新している。

 <?php
    function quote_smart($value)
    {
       // 数値以外をクオートする
       if(!is_numeric($value))
       {
          $value = "'" . mysqli_real_escape_string($value) . "'";
       }
       return $value;
    }
 
    $link = mysqli_connect('localhost', 'user', 'passwd', 'uriage');
    if(!$link)
    {
       die('接続失敗です。'.mysqli_error());
    }
 
    print('<p>接続に成功しました。</p>');
 
    $db_selected = mysqli_select_db($link, 'uriage');
    if(!$db_selected)
    {
       die('データベース選択失敗です。'.mysqli_error());
    }
 
    print('<p>uriageデータベースを選択しました。</p>');
 
    // 文字コードをutf8mb4 に変更
    if(!mysqli_set_charset($link, "utf8mb4"))
    {
       printf('文字コードの変更に失敗しました。'.mysqli_error($link));
       exit();
    }
 
    print('<p>データを更新します。</p>');
 
    $id = 5;
    $name = 'デジタルカメラ';
 
    $sql = sprintf("UPDATE shouhin SET name = %s WHERE id = %s", quote_smart($name), quote_smart($id));
    $result_flag = mysqli_query($link, $sql);
    if(!$result_flag)
    {
       die('UPDATEクエリが失敗しました。'.mysqli_error());
    }
 
    print('<p>更新後のデータを取得します。</p>');
 
    $result = mysqli_query($link, 'SELECT id,name FROM shouhin');
    if(!$result)
    {
       die('SELECTクエリが失敗しました。'.mysqli_error());
    }
 
    while($row = mysqli_fetch_assoc($result))
    {
       print('<p>');
       print('id='.$row['id']);
       print(',name='.$row['name']);
       print('</p>');
    }
 
    $close_flag = mysqli_close($link);
    if($close_flag)
    {
       print('<p>切断に成功しました。</p>');
    }
 ?>



レコードの削除(DELETE)

DELETE文の場合、mysqli_query関数の出力結果において、成功する場合はtrue、失敗する場合はfalseを返す。

以下の例では、データベースuriageのテーブルshouhinのレコードを削除している。

 <?php
    function quote_smart($value)
    {
       // 数値以外をクオートする
       if(!is_numeric($value))
       {
          $value = "'" . mysql_real_escape_string($value) . "'";
       }
       return $value;
    }
 
    $link = mysqli_connect('localhost', 'user', 'passwd', 'uriage');
    if(!$link)
    {
       die('接続失敗です。'.mysqli_error());
    }
 
    print('<p>接続に成功しました。</p>');
 
    $db_selected = mysqli_select_db($link, 'uriage');
    if(!$db_selected)
    {
       die('データベースの選択に失敗しました。'.mysqli_error());
    }
 
    print('<p>uriageデータベースを選択しました。</p>');
 
    // 文字コードをutf8mb4 に変更
    if(!mysqli_set_charset($link, "utf8mb4"))
    {
       printf('文字コードの変更に失敗しました。'.mysqli_error($link));
       exit();
    }
 
    print('<p>レコードを削除します。</p>');
 
    $id = 4;
 
    $sql = sprintf("DELETE FROM shouhin WHERE id = %s", quote_smart($id));
    $result_flag = mysqli_query($link, $sql);
    if(!$result_flag)
    {
       die('DELETEクエリが失敗しました。'.mysqli_error());
    }
 
    print('<p>削除後のレコードを取得します。</p>');
 
    $result = mysqli_query($link, 'SELECT id,name FROM shouhin');
    if(!$result)
    {
       die('SELECTクエリが失敗しました。'.mysqli_error());
    }
 
    while($row = mysqli_fetch_assoc($result))
    {
       print('<p>');
       print('id='.$row['id']);
       print(',name='.$row['name']);
       print('</p>');
    }
 
    $close_flag = mysqli_close($link);
    if($close_flag)
    {
       print('<p>切断に成功しました。</p>');
    }
 ?>



パラメータをエスケープする

SQL文で使用する値が固定値の場合は問題無いが、例えば、フォーム等に入力した条件を使用してSQL文を生成する場合、
SQLインジェクション攻撃を防ぐためにパラメータをエスケープする必要がある。

エスケープするためには、mysqli_real_escape_string関数を使用する。

string mysqli_real_escape_string(mysqli link_identifier, string escapestr)

現在使用している文字コードで、escapestrの特殊文字をエスケープして、mysqli_query関数で安全に利用できる形式に変換する。
バイナリデータを挿入する場合は、必ず、mysqli_real_escape_string関数を使用しなければならない。

引数:
   link_identifier  MySQLリンクID
   escapestr  エスケープされる文字列

戻り値:
   成功する場合はエスケープ後の文字列、失敗する場合はfalseを返す。


マジッククオートを有効化している場合も似たような効果が得られるが、
マジッククオートは無効化して、mysqli_real_escape_string関数を使用して必要に応じてエスケープすることが推奨されている。

例えば、SQL文において、値にシングルクォーテーション(')等が含まれる場合、
mysqli_real_escape_string関数を実行することで、SQL文で直接記述できない値に対して\を付加してエスケープ処理を自動的に行う。

 $test = "book's";
 
 mysqli_real_escape_string($test);  //--> $test = "book¥'s"


以下の例では、POSTで送信されたユーザ名とパスワードをエスケープ処理を実行してSQL文を生成している。

 function quote_smart($link, $value)
 {
    // 数値以外をクオートする
    if(!is_numeric($value))
    {
       $value = "'" . mysqli_real_escape_string($link, $value) . "'";
    }
    return $value;
 }
 
 $query = sprintf("SELECT * FROM users WHERE user=%s AND password=%s", quote_smart($_POST['username']), quote_smart($_POST['password']));
 mysqli_query($link, $query);


以下の例では、上記のセクションのINSERT文を書き直している。

 <?php
    function quote_smart($link, $value)
    {
       // 数値以外をクオートする
       if(!is_numeric($value))
       {
          $value = "'" . mysqli_real_escape_string($link, $value) . "'";
       }
       return $value;
    }
 
    $link = mysqli_connect('localhost', 'user', 'passwd', 'uriage');
    if(!$link)
    {
       die('接続失敗です。'.mysqli_error());
    }
 
    print('<p>接続に成功しました。</p>');
 
    $db_selected = mysqli_select_db($link, 'uriage');
    if(!$db_selected)
    {
       die('データベースの選択に失敗しました。'.mysqli_error());
    }
 
    print('<p>uriageデータベースを選択しました。</p>');
 
    // 文字コードをutf8mb4 に変更
    if(!mysqli_set_charset($link, "utf8mb4"))
    {
       printf('文字コードの変更に失敗しました。'.mysqli_error($link));
       exit();
    }
 
    print('<p>レコードを追加します。</p>');
 
    $id = 5;
    $name = "Toyama's Wine";
 
    $sql = sprintf("INSERT INTO shouhin(id, name) VALUES(%s, %s)", quote_smart($link, $id), quote_smart($link, $name));
    print('<p>エスケープ後のデータ:'.quote_smart($name).'</p>');  //--> $name = Toyama¥'s Wine
    $result_flag = mysqli_query($link, $sql);
    if(!$result_flag)
    {
       die('INSERTクエリが失敗しました。'.mysqli_error());
    }
 
    print('<p>追加後のレコードを取得します。</p>');
 
    $result = mysqli_query($link, 'SELECT id,name FROM shouhin');
    if(!$result)
    {
       die('SELECTクエリが失敗しました。'.mysqli_error());
    }
 
    while($row = mysqli_fetch_assoc($result))
    {
       print('<p>');
       print('id='.$row['id']);
       print(',name='.$row['name']);
       print('</p>');
    }
 
    $close_flag = mysqli_close($link);
    if($close_flag)
    {
       print('<p>切断に成功しました。</p>');
    }
 ?>


SQL文に含まれていたシングルクオーテーションがエスケープ処理されて、Toyama¥'s Wineに変換されていることが確認できる。
このように、'のような特殊な意味を持つ文字を、単なる文字の'として処理することができる。


暗号化 / 復号

データベースの接続情報を暗号化する場合は、openssl_encrypt / decrypt関数を使用して暗号化 / 復号を行う。

暗号化キー (ENCRYPTION_KEY) と IV(ENCRYPTION_IV) は、ソースコードとは別の場所に保管する。

また、INIファイルには暗号化された値を保存する必要がある。

初期設定時において、以下に示すように値を暗号化して設定ファイルに保存する。

 $encrypted_password = encryptString('実際のパスワード');


 // 暗号化キーとIVを安全な場所に保存する
 define('ENCRYPTION_KEY', '<32[byte]の秘密鍵>');
 define('ENCRYPTION_IV', '<16バイトのIV>');
 
 // 暗号化関数
 function encryptString($plaintext)
 {
    $cipher = "aes-256-cbc";
    $options = OPENSSL_RAW_DATA;
    return base64_encode(openssl_encrypt($plaintext,
                                         $cipher,
                                         ENCRYPTION_KEY,
                                         $options,
                                         ENCRYPTION_IV));
 }
 
 // 復号関数
 function decryptString($encrypted)
 {
    $cipher = "aes-256-cbc";
    $options = OPENSSL_RAW_DATA;
    return openssl_decrypt(base64_decode($encrypted),
                           $cipher,
                           ENCRYPTION_KEY,
                           $options,
                           ENCRYPTION_IV);
 }


 // 使用例
 
 // INIファイルから読み込んだ接続情報を復号して使用
 $host     = decryptString($config['host']) ?? 'localhost';
 $dbname   = decryptString($config['dbname']) ?? '';
 $username = decryptString($config['username']) ?? 'root';
 $password = decryptString($config['password']) ?? '';