sql >> データベース >  >> RDS >> Access

データベースアクセスにPHPPDOを使用する必要がある理由

    多くのPHPプログラマーは、MySQLまたはMySQLi拡張機能を使用してデータベースにアクセスする方法を学びました。 PHP 5.1の時点で、より良い方法があります。 PHP Data Objects(PDO)は、プリペアドステートメントとオブジェクトの操作のためのメソッドを提供します。これにより、生産性が大幅に向上します。

    CRUDジェネレーターとフレームワーク

    データベースコードは反復的ですが、正しく理解するために非常に重要です。そこで、PHP CRUDジェネレーターとフレームワークが登場します。これらは、この反復的なコードをすべて自動的に生成することで時間を節約し、アプリの他の部分に集中できるようにします。

    CodeCanyonには、優れた品質の製品を時間どおりに提供するのに役立つCRUDジェネレーターとフレームワークがあります。 (CRUDは、作成、読み取り、更新、削除の頭字語であり、データベースの基本的な操作です。)

    • PHP9便利なPHPCRUDジェネレーターとフレームワークがCodeCanyonFrancLucasで利用可能
    • PHPは、PDO Advanced CRUDGeneratorToolSajalSoniを使用してPHPCRUDインターフェイスをすばやく構築します

    PDOの概要

    PDO(PHPデータオブジェクト)は、複数のデータベースにアクセスするための統一された方法を提供するデータベースアクセスレイヤーです。

    データベース固有の構文は考慮されていませんが、多くの場合、接続文字列を切り替えるだけで、データベースとプラットフォームを切り替えるプロセスをかなり簡単にすることができます。

    このチュートリアルは、SQLの完全なハウツーを目的としたものではありません。これは主に、現在mysqlを使用しているユーザー向けに書かれています。 またはmysqli よりポータブルで強力なPDOにジャンプするのに役立つ拡張機能。

    PHPでのデータベース操作に関しては、PDOには生の構文に比べて多くの利点があります。簡単にいくつか挙げてみましょう:

    • 抽象化レイヤー
    • オブジェクト指向構文
    • プリペアドステートメントのサポート
    • より良い例外処理
    • 安全で再利用可能なAPI
    • 人気のあるすべてのデータベースのサポート

    データベースのサポート

    拡張機能は、PDOドライバーが作成されたすべてのデータベースをサポートできます。この記事の執筆時点では、次のデータベースドライバを利用できます。

    • PDO_DBLIB (FreeTDS / Microsoft SQL Server / Sybase)
    • PDO_FIREBIRD (Firebird / Interbase 6)
    • PDO_IBM (IBM DB2)
    • PDO_INFORMIX (IBM Informix Dynamic Server)
    • PDO_MYSQL (MySQL 3.x / 4.x / 5.x)
    • PDO_OCI (Oracle Call Interface)
    • PDO_ODBC (ODBC v3(IBM DB2、unixODBC、およびwin32 ODBC))
    • PDO_PGSQL (PostgreSQL)
    • PDO_SQLITE (SQLite3およびSQLite2)
    • PDO_4D (D)

    これらのドライバーのすべてが、システムで必ずしも使用できるとは限りません。使用しているドライバーをすばやく確認する方法は次のとおりです。

    print_r(PDO::getAvailableDrivers());

    接続

    データベースが異なれば、接続方法もわずかに異なる場合があります。以下に、最も人気のあるデータベースのいくつかに接続する方法を示します。データベースタイプを除いて、最初の3つは同一であり、SQLiteには独自の構文があります。

    try {
      # MS SQL Server and Sybase with PDO_DBLIB
      $DBH = new PDO("mssql:host=$host;dbname=$dbname", $user, $pass);
      $DBH = new PDO("sybase:host=$host;dbname=$dbname", $user, $pass);
     
      # MySQL with PDO_MYSQL
      $DBH = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);
     
      # SQLite Database
      $DBH = new PDO("sqlite:my/database/path/database.db");
    }
    catch(PDOException $e) {
        echo $e->getMessage();
    }

    try/catchブロックに注意してください。常にPDO操作をtry/catchでラップし、例外メカニズムを使用する必要があります。これについては後ほど詳しく説明します。通常、接続は1つだけにします。構文を示すために、いくつかの接続がリストされています。 $DBH 「データベースハンドル」の略で、このチュートリアル全体で使用されます。

    ハンドルをnullに設定すると、接続を閉じることができます。

    # close the connection
    $DBH = null;

    PHP.netから、データベース固有のオプションや他のデータベースの接続文字列に関する詳細情報を入手できます。

    例外とPDO

    PDOは例外を使用してエラーを処理できます。つまり、PDOで行うことはすべて、try/catchブロックでラップする必要があります。新しく作成したデータベースハンドルにエラーモード属性を設定することにより、PDOを3つのエラーモードのいずれかに強制できます。構文は次のとおりです。

    $DBH->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT );
    $DBH->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING );
    $DBH->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );

    設定したエラーモードに関係なく、接続エラーは常に例外を生成し、接続の作成は常にtry/catchブロックに含まれている必要があります。

    PDO::ERRMODE_SILENT

    これはデフォルトのエラーモードです。このモードのままにしておくと、mysqlを使用したことがある場合に、おそらく慣れている方法でエラーをチェックする必要があります。 またはmysqli 拡張機能。他の2つの方法は、DRYプログラミングに適しています。

    PDO::ERRMODE_WARNING

    このモードでは、標準のPHP警告が発行され、プログラムの実行を続行できます。デバッグに役立ちます。

    PDO::ERRMODE_EXCEPTION

    これは、ほとんどの状況で必要なモードです。例外が発生し、エラーを適切に処理し、誰かがシステムを悪用するのに役立つ可能性のあるデータを非表示にすることができます。例外を利用する例を次に示します。

    # connect to the database
    try {
      $DBH = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);
      $DBH->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
     
      # UH-OH! Typed DELECT instead of SELECT!
      $DBH->prepare('DELECT name FROM people');
    }
    catch(PDOException $e) {
        echo "I'm sorry, Dave. I'm afraid I can't do that.";
        file_put_contents('PDOErrors.txt', $e->getMessage(), FILE_APPEND);
    }

    selectステートメントに意図的なエラーがあります。これにより例外が発生します。例外は、エラーの詳細をログファイルに送信し、ユーザーにわかりやすい(またはあまりわかりにくい)メッセージを表示します。

    挿入と更新

    新しいデータの挿入(または既存のデータの更新)は、より一般的なデータベース操作の1つです。 PHP PDOを使用すると、これは通常2段階のプロセスです。このセクションで説明する内容はすべて、UPDATEの両方に等しく適用されます。 およびINSERT 操作。

    最も基本的なタイプのインサートの例を次に示します。

    # STH means "Statement Handle"
    $STH = $DBH->prepare("INSERT INTO folks ( first_name ) values ( 'Cathy' )");
    $STH->execute();

    exec()を使用して同じ操作を実行することもできます。 メソッド、呼び出しが1つ少なくなります。ほとんどの場合、プリペアドステートメントを利用できるように、より長いメソッドを使用します。一度だけ使用する場合でも、プリペアドステートメントを使用すると、SQLインジェクション攻撃から保護するのに役立ちます。

    プリペアドステートメント

    プリペアドステートメントを使用すると、SQLインジェクションから保護するのに役立ちます。

    プリペアドステートメントは、データだけをサーバーに送信することで複数回実行できる、事前にコンパイルされたSQLステートメントです。プレースホルダーで使用されるデータをSQLインジェクション攻撃から自動的に保護するという追加の利点があります。

    SQLにプレースホルダーを含めることにより、プリペアドステートメントを使用します。次に、3つの例を示します。1つはプレースホルダーなし、1つは名前のないプレースホルダーあり、もう1つは名前付きのプレースホルダーです。

    # no placeholders - ripe for SQL Injection!
    $STH = $DBH->prepare("INSERT INTO folks (name, addr, city) values ($name, $addr, $city)");
     
    # unnamed placeholders
    $STH = $DBH->prepare("INSERT INTO folks (name, addr, city) values (?, ?, ?)");
     
    # named placeholders
    $STH = $DBH->prepare("INSERT INTO folks (name, addr, city) values (:name, :addr, :city)");

    最初の方法は避けたいと思います。比較のためにここにあります。名前付きまたは名前なしのプレースホルダーの使用の選択は、それらのステートメントのデータの設定方法に影響します。

    名前のないプレースホルダー

    # assign variables to each place holder, indexed 1-3
    $STH->bindParam(1, $name);
    $STH->bindParam(2, $addr);
    $STH->bindParam(3, $city);
     
    # insert one row
    $name = "Daniel"
    $addr = "1 Wicked Way";
    $city = "Arlington Heights";
    $STH->execute();
     
    # insert another row with different values
    $name = "Steve"
    $addr = "5 Circle Drive";
    $city = "Schaumburg";
    $STH->execute();

    ここには2つのステップがあります。まず、さまざまなプレースホルダーに変数を割り当てます(2〜4行目)。次に、それらのプレースホルダーに値を割り当てて、ステートメントを実行します。別のデータセットを送信するには、それらの変数の値を変更して、ステートメントを再実行するだけです。

    これは、多くのパラメーターを持つステートメントでは少し扱いに​​くいように見えますか?です。ただし、データが配列に格納されている場合は、簡単なショートカットがあります:

    # the data we want to insert
    $data = array('Cathy', '9 Dark and Twisty Road', 'Cardiff');
     
    $STH = $DBH->prepare("INSERT INTO folks (name, addr, city) values (?, ?, ?)");
    $STH->execute($data);

    簡単です!

    配列内のデータは、プレースホルダーに順番に適用されます。 $data[0] 最初のプレースホルダーに入る$data[1] ただし、配列のインデックスが適切でない場合、これは正しく機能しないため、配列のインデックスを再作成する必要があります。

    名前付きプレースホルダー

    おそらく構文を推測できますが、例を次に示します。

    # the first argument is the named placeholder name - notice named
    # placeholders always start with a colon.
    $STH->bindParam(':name', $name);

    ここでもショートカットを使用できますが、連想配列で機能します。次に例を示します:

    # the data we want to insert
    $data = array( 'name' => 'Cathy', 'addr' => '9 Dark and Twisty', 'city' => 'Cardiff' );
     
    # the shortcut!
    $STH = $DBH->prepare("INSERT INTO folks (name, addr, city) value (:name, :addr, :city)");
    $STH->execute($data);

    配列のキーはコロンで始める必要はありませんが、それ以外の場合は名前付きプレースホルダーと一致する必要があります。配列の配列がある場合は、それらを繰り返し処理して、executeを呼び出すだけです。 データの各配列で。

    名前付きプレースホルダーのもう1つの優れた機能は、プロパティが名前付きフィールドと一致すると仮定して、オブジェクトをデータベースに直接挿入できることです。オブジェクトの例と、挿入を実行する方法は次のとおりです。

    # a simple object
    class person {
        public $name;
        public $addr;
        public $city;
     
        function __construct($n,$a,$c) {
            $this->name = $n;
            $this->addr = $a;
            $this->city = $c;
        }
        # etc ...
    }
     
    $cathy = new person('Cathy','9 Dark and Twisty','Cardiff');
     
    # here's the fun part:
    $STH = $DBH->prepare("INSERT INTO folks (name, addr, city) value (:name, :addr, :city)");
    $STH->execute((array)$cathy);

    executeの配列にオブジェクトをキャストする プロパティが配列キーとして扱われることを意味します。

    データの選択

    データは->fetch()を介して取得されます 、ステートメントハンドルのメソッド。 fetchを呼び出す前に、データをどのようにフェッチするかをPDOに指示することをお勧めします。次のオプションがあります:

    • PDO::FETCH_ASSOC 列名でインデックス付けされた配列を返します。
    • PDO::FETCH_BOTH (デフォルト):列名と数値の両方でインデックス付けされた配列を返します。
    • PDO::FETCH_BOUND 列の値を->bindColumn()で設定された変数に割り当てます メソッド。
    • PDO::FETCH_CLASS 列の値を名前付きクラスのプロパティに割り当てます。一致するプロパティが存在しない場合は、プロパティが作成されます。
    • PDO::FETCH_INTO 名前付きクラスの既存のインスタンスを更新します。
    • PDO::FETCH_LAZY PDO::FETCH_BOTHを組み合わせます / PDO::FETCH_OBJ 、使用時にオブジェクト変数名を作成します。
    • PDO::FETCH_NUM 列番号でインデックス付けされた配列を返します。
    • PDO::FETCH_OBJ 列名に対応するプロパティ名を持つ匿名オブジェクトを返します。

    実際には、ほとんどの状況をカバーする3つがあります:FETCH_ASSOCFETCH_CLASS 、およびFETCH_OBJ 。フェッチ方法を設定するには、次の構文を使用します。

    $STH->setFetchMode(PDO::FETCH_ASSOC);

    ->fetch()内で直接フェッチタイプを設定することもできます メソッド呼び出し。

    FETCH_ASSOC

    このフェッチタイプは、列名でインデックス付けされた連想配列を作成します。これは、mysql/mysqli拡張機能を使用したことのある人なら誰でもよく知っているはずです。この方法でデータを選択する例を次に示します。

    # using the shortcut ->query() method here since there are no variable
    # values in the select statement.
    $STH = $DBH->query('SELECT name, addr, city from folks');
     
    # setting the fetch mode
    $STH->setFetchMode(PDO::FETCH_ASSOC);
     
    while($row = $STH->fetch()) {
        echo $row['name'] . "\n";
        echo $row['addr'] . "\n";
        echo $row['city'] . "\n";
    }

    whileループは、完了するまで一度に1行ずつ結果セットを通過し続けます。

    FETCH_OBJ

    このフェッチタイプは、フェッチされたデータの各行に対してstdクラスのオブジェクトを作成します。次に例を示します:

    # creating the statement
    $STH = $DBH->query('SELECT name, addr, city from folks');
     
    # setting the fetch mode
    $STH->setFetchMode(PDO::FETCH_OBJ);
     
    # showing the results
    while($row = $STH->fetch()) {
        echo $row->name . "\n";
        echo $row->addr . "\n";
        echo $row->city . "\n";
    }

    FETCH_CLASS

    オブジェクトのプロパティは、コンストラクターが呼び出される前に設定されます。これは重要です。

    このフェッチメソッドを使用すると、選択したクラスにデータを直接フェッチできます。 FETCH_CLASSを使用する場合 、オブジェクトのプロパティはBEFOREに設定されます コンストラクターが呼び出されます。それをもう一度読んでください—それは重要です。列名に一致するプロパティが存在しない場合、それらのプロパティは(パブリックとして)作成されます。

    つまり、データがデータベースから出力された後に変換が必要な場合は、各オブジェクトが作成されるときにオブジェクトによって自動的に変換を行うことができます。

    例として、レコードごとにアドレスを部分的に隠す必要がある状況を想像してみてください。これは、コンストラクターでそのプロパティを操作することで実行できます。次に例を示します:

    class secret_person {
        public $name;
        public $addr;
        public $city;
        public $other_data;
     
        function __construct($other = '') {
            $this->address = preg_replace('/[a-z]/', 'x', $this->address);
            $this->other_data = $other;
        }
    }

    データがこのクラスにフェッチされると、アドレスにはすべて小文字の a-z 文字が文字に置き換えられましたx 。これで、クラスを使用してそのデータ変換を実行することは完全に透過的です:

    $STH = $DBH->query('SELECT name, addr, city from folks');
    $STH->setFetchMode(PDO::FETCH_CLASS, 'secret_person');
     
    while($obj = $STH->fetch()) {
        echo $obj->addr;
    }

    アドレスが「5Rosebud」の場合、出力として「5Rxxxxxx」が表示されます。もちろん、データが割り当てられる前にコンストラクターを呼び出す必要がある場合もあります。 PDOもこれをカバーしています。

    $STH->setFetchMode(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'secret_person');

    ここで、このフェッチモード(PDO::FETCH_PROPS_LATE)を使用して前の例を繰り返すと、 )、アドレスは コンストラクターが呼び出され、プロパティが割り当てられたため、不明瞭になります。

    最後に、本当に必要な場合は、PDOを使用してオブジェクトにデータをフェッチするときにコンストラクターに引数を渡すことができます:

    $STH->setFetchMode(PDO::FETCH_CLASS, 'secret_person', array('stuff'));

    オブジェクトごとにコンストラクターに異なるデータを渡す必要がある場合は、fetch内でフェッチモードを設定できます。 方法:

    $i = 0;
    while($rowObj =  $STH->fetch(PDO::FETCH_CLASS, 'secret_person', array($i))) {
        // do stuff
        $i++
    }

    その他の役立つ方法

    これはPDOのすべてを網羅することを意図したものではありませんが(これは大きな拡張です!)、PDOで基本的なことを行うために知っておく必要のある方法が他にもいくつかあります。

    $DBH->lastInsertId();

    ->lastInsertId() メソッドは、ステートメントハンドルではなく、常にデータベースハンドルで呼び出され、その接続によって最後に挿入された行の自動インクリメントされたIDを返します。

    $DBH->exec('DELETE FROM folks WHERE 1');
    $DBH->exec("SET time_zone = '-8:00'");

    ->exec() メソッドは、影響を受ける行以外のデータを返すことができない操作に使用されます。上記は、execメソッドを使用する2つの例です。

    $safe = $DBH->quote($unsafe);

    ->quote() メソッドは文字列を引用符で囲むため、クエリで安全に使用できます。これは、プリペアドステートメントを使用していない場合のフォールバックです。

    $rows_affected = $STH->rowCount();

    ->rowCount() メソッドは、操作の影響を受ける行数を示す整数を返します。 PDOの少なくとも1つの既知のバージョンでは、メソッドはselectステートメントで機能していませんでした。ただし、バージョンPHP5.1.6以降では正しく機能します。

    この問題が発生していてPHPをアップグレードできない場合は、次のようにして行数を取得できます。

    $sql = "SELECT COUNT(*) FROM folks";
    if ($STH = $DBH->query($sql)) {
        # check the row count
        if ($STH->fetchColumn() > 0) {
     
        # issue a real select here, because there's data!
        }
        else {
            echo "No rows matched the query.";
        }
    }

    CodeCanyonのPHPCRUDジェネレーター

    CodeCanyonからPHPCRUDジェネレーターを見つけてプロジェクトで使用することにより、時間を節約できます。今すぐ使い始めることができる最も人気のあるダウンロードの5つを次に示します。

    1。 Laravel多目的アプリケーション:Sximo 6

    Sximo 6ビルダーは、最も人気のあるフレームワークに基づいています。また、2021年の新しいアップデートを受け取り、可能な限り使いやすく、機能が豊富になっています。これらの機能の一部は次のとおりです。

    • データベーステーブルの管理
    • フロントエンドとバックエンドのテンプレート
    • モジュールMySQLエディター
    • 複数の画像とファイルのアップロードのサポート

    CRUD PHPテンプレートを使用して時間を節約したい場合は、試してみてください。

    2。 PDO Crud:フォームビルダーとデータベース管理

    もう1つの強力なCRUDPHPジェネレーターがあります。このPHPPDOコードテンプレートは、データベース管理を適切に実行します。しかし、それだけではありません。 PDO CRUDを使用して、データベーステーブルから直接役立つフォームを作成することもできます。これは、他の多くのオプションにはない便利な機能です。

    3。 Cicool:ページ、フォーム、REST API、CRUDジェネレーター

    Cicoolは、検討する価値のあるもう1つの多目的ビルダーです。 CRUDビルダーを提供するだけでなく、次の機能も備えています。

    • ページビルダー
    • フォームビルダー
    • RESTAPIビルダー

    これらの機能に加えて、Cicoolに拡張機能を追加して、テーマを簡単にカスタマイズすることもできます。

    4。 PHPCRUDジェネレーター

    簡単な管理パネルビルダー?小切手。ナビゲートしやすいインターフェース?小切手。詳細なデータベース分析?別のチェック。このPHPCRUDジェネレーターには、優れたダッシュボードを構築してデータを保存するために必要なものがすべて揃っています。さまざまなユーザー認証および権限管理機能を備えたこのPDOPHPテンプレートは、チェックする価値があります。


    1. SQL Serverで既存の列を計算列に変更する(T-SQLの例)

    2. MySQLベースのシステム(MySQL / MariaDBレプリケーション+ガレラ)用にAppArmorを構成する方法

    3. SQLServerGUIDの並べ替えアルゴリズム。なんで?

    4. MySQLで1時間ごとにデータを取得する方法