Help us understand the problem. What is going on with this article?

[PHP] mysqli使い方まとめ(MySQL接続~SELECT実行まで)

More than 1 year has passed since last update.

PHP5.5から mysql_connect()mysql_query() など、mysql_***系の関数は非推奨となりました。新方式の1つである mysqli の使い方をまとめておきます。(他にはPDO方式があります)

手続き型とオブジェクト型

mysqli の書き方には大きく2通りあります。
 ◎手続き型:従来とよく似た mysqli_***() という書き方(インスタンス生成不要)
 ◎オブジェクト型:オブジェクト指向的な書き方(インスタンス生成必要)

例)DBへの接続

手続き型
// DB接続例:mysqli_xxx関数を使う
$link = mysqli_connect("Host or IP", "User", "Pass", "DBName");
オブジェクト型
// DB接続例:mysqliクラスをオブジェクト化してから使う
$mysqli = new mysqli('Host or IP', 'User', 'Pass', 'DBName');

本ページでは、主に後者のオブジェクト型の書き方について記載します。

DBへの接続〜切断

PHP
<?php
// mysqliクラスのオブジェクトを作成
$mysqli = new mysqli('Host or IP', 'User', 'Pass', 'DBName');
if ($mysqli->connect_error) {
    echo $mysqli->connect_error;
    exit();
} else {
    $mysqli->set_charset("utf8");
}

// ここにDB処理いろいろ書く(後述)

// DB接続を閉じる
$mysqli->close();
?>

SELECT(簡易方式)

完成しているSQLをqueryメソッドでそのまま実行する方式です。

PHP
// 完成済みのSELECT文を実行する
$sql = "SELECT user_id, name FROM user_table";
if ($result = $mysqli->query($sql)) {
    // 連想配列を取得
    while ($row = $result->fetch_assoc()) {
        echo $row["user_id"] . $row["name"] . "<br>";
    }
    // 結果セットを閉じる
    $result->close();
}

SELECT件数の取得:

PHP
// オブジェクト型
echo "rows=" . $result->num_rows;

// 手続き型
echo "rows=" . mysqli_num_rows($result);

SELECT(バインド方式)

SQLの一部を「?」としておき、あとから変数の値で補う(バインドする)方式です。

PHP
// SELECT文のひな型をもとにステートメントハンドルを取得する
$sql = "SELECT user_id, name FROM user_table WHERE user_id=? AND name=?";
if ($stmt = $mysqli->prepare($sql)) {
    // 条件値をSQLにバインドする(補足参照)
    $user_id = 123;
    $name = "hanako";
    $stmt->bind_param("is", $user_id, $name);

    // 実行
    $stmt->execute();

    // 取得結果を変数にバインドする
    $stmt->bind_result($user_id, $name);
    while ($stmt->fetch()) {
        echo "ID=$user_id, NAME=$name<br>"; 
    }
    $stmt->close();
}

SELECT件数の取得:

PHP
$stmt->store_result(); // これ忘れるとnum_rowsは0
echo "rows=" . $stmt->num_rows;

バインド式の補足:

$stmt->bind_param("is", $user_id, $name);の第1引数 "is" は後続のデータ型を表します。i=integer、s=string、d=double、b=blob など。DATE型は s で良いみたいです。
また下記のように値を引数内に直書きすることはできません。
誤)$stmt->bind_param("is", 123, "hanako");

応用例

使いやすいようにクラス化してみる。(DB接続情報は適宜変更して下さい)

MyDB.class.php
<?php
/*
 * MyDBクラス
 */
class MyDB
{
    public $mysqli; // mysqliオブジェクト
    public $mode;   // 戻り値の形式:"json" or "array"(連想配列)
    public $count;  // SQLによって取得した行数 or 影響した行数

    // コンストラクタ
    function __construct($mode = "json") 
    {
        $this->mode = $mode;

        // DB接続
        $this->mysqli = new mysqli('localhost', 'DB-USER', 'DB-PASS', 'DB-NAME');
        if ($this->mysqli->connect_error) {
            echo $this->mysqli->connect_error;
            exit;
        } else {
            $this->mysqli->set_charset("utf8");
        }
    }

    // デストラクタ
    function __destruct()
    {
        // DB接続を閉じる
        $this->mysqli->close();
    }

    // SQL実行(SELECT/INSERT/UPDATE/DELETE に対応)
    function query($sql)
    {
        // SQL実行
        $result = $this->mysqli->query($sql);
        // エラー
        if ($result === FALSE) {
            // エラー内容
            $error = $this->mysqli->errno.": ".$this->mysqli->error;
            // 戻り値
            $rtn = array(
                'status' => FALSE,
                'count'  => 0,
                'result' => "",
                'error'  => $error
            );
            if($this->mode == "array")
                return $rtn;
            else
                return json_encode($rtn); // JSON形式で返す(デフォルト)
        }

        // SELECT文以外
        if($result === TRUE) {
            // 影響のあった行数を格納
            $this->count = $this->mysqli->affected_rows;
            // 戻り値
            $rtn = array(
                'status' => TRUE,
                'count'  => $this->count,
                'result' => "",
                'error'  => ""
            );
            if($this->mode == "array")
                return $rtn;
            else
                return json_encode($rtn); // JSON形式で返す(デフォルト)
        } 
        // SELECT文
        else {
            // SELECTした行数を格納
            $this->count = $result->num_rows;
            // 連想配列に格納
            $data = array();
            while ($row = $result->fetch_assoc()) {
                $data[] = $row;
            }
            // 結果セットを閉じる
            $result->close();
            // 戻り値
            $rtn = array(
                'status' => TRUE,
                'count'  => $this->count,
                'result' => $data,
                'error'  => ""
            );
            if($this->mode == "array")
                return $rtn;
            else
                return json_encode($rtn); // JSON形式で返す(デフォルト)
        }
    }

    // 文字列をエスケープする
    function escape($str)
    {
        return $this->mysqli->real_escape_string($str);
    }
}
?>

使い方

php
$db = new MyDB();
echo $db->query("SELECT * FROM USERTABLE");

結果(JSON形式の文字列)

json
{
    "status": true,
    "count" : 2,
    "result": [
        {"UserID":"aaa", "Name":"AppleMan"},
        {"UserID":"bbb", "Name":"BananaMan"}
    ],
    "error" : ""
}

補足

JSON形式の文字列に変換する json_encode($ary) は、通常だと日本語が \uXXXX 形式(Unicodeエスケープシーケンス)になってしまいます。PHP5.4以降では、
json_encode($ary, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)
とすることで、日本語のまま扱えます。

(・o・ゞ いじょー。

参考URL

mysqli_result::fetch_assoc: 結果の行を連想配列で取得する
http://www.phppro.jp/phpmanual/php/mysqli-result.fetch-assoc.html

mysqli - プリペアドステートメント
http://blog.livedoor.jp/nakamura_tech/archives/51311243.html

【PHP】mysqliとプリペアドステートメントについて|Furudateのブログ
http://furudate.hatenablog.com/entry/2013/10/04/211422

PHPでデータベースに接続するときのまとめ
http://qiita.com/mpyw/items/b00b72c5c95aac573b71

MySQL 改良版拡張モジュール|PHP: MySQLi - Manual
http://php.net/manual/ja/book.mysqli.php

yasumodev
「長い旅行に必要なのは大きなカバンじゃなく、口ずさめる一つの歌さ」スナフキン
https://twitter.com/yasumodev
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした