2

つまり、基本的に2つのファイルがあります。最終的にはさらに多くの機能がありますが、DBPDOデータベース操作を使用するというクラスを作成し、このクラスを拡張して、データベースを操作するためのすべての関数を作成します。したがってDB、クラスはクラスに拡張されdbADD、さまざまなデータベーステーブルのすべての追加関数が含まれます。

これは呼ばれconfig.phpます:

<?php

DEFINE ('DBHOST', 'localhost');
DEFINE ('DBUSER', 'REMOVED');
DEFINE ('DBPSW', 'REMOVED');
DEFINE ('DBNAME', 'REMOVED');

class DB {
    public $db;
    private static $instance;   

    public function __constructor(){
        $config ['db'] = array(
        'host'      =>  DBHOST,
        'username'  =>  DBUSER,
        'password'  =>  DBPSW,
        'dbname'    =>  DBNAME,
        );

        $this->db = new PDO('mysql:host ='  . $config['db']['host'] . ';dbname='  .   $config['db']['dbname'],$config['db']['username'],$config['db']['password']) ;
    }

    public static function getInstance()
    {
        if (!isset(self::$instance))
        {
            $object = __CLASS__;
            self::$instance = new $object;
        }
        return self::$instance;
    }

    public function GetArticles ($search){
        $sql = "SELECT `FirstColumn`, `SrcColumn`, `article` FROM `test_table`  WHERE `FirstColumn` = 23";  

        //$dbs = new DB();
        $dbs = DB::getInstance();
        $query = $dbs->db->prepare($sql);
        //$query->bindValue(':search', $search, PDO::PARAM_INT);
        $query->execute();

        while ($row = $query->fetch(PDO::FETCH_OBJ)) {
            // = $row['article'],'</br>';
            $return = $row['article'];
        }   
        return $return;
    }
}
?>

このファイルは私のテストファイルですが、テストの場としてはそれほど重要ではありません。呼ばれるtest.php

<?php
require_once('app_core/config.php');
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Untitled Document</title>

    <link rel="stylesheet" href="/style/style.css" type="text/css" media="screen" />
</head>

<body>
    <?php
    $db = new DB();
    //echo $db->db;
    //echo $db->GetTestDB();
    //$test = $db->TestThis();
    //print_r($test);
    echo $db->GetArticles('23');
    ?>
</body>
</html>

可能であれば、他にも2つの懸念があります。最初の質問はセキュリティの問題です。これは良い習慣ですか。もう1つの質問は、このパスワードデータを含むファイルを非表示にして、使用できるが誰も読み取れないようにする方法です。

4

3 に答える 3

3

さて、ここでは多くのことが起こっているので、このクラスが(完全に関連していないメソッドのコレクションではなく)オブジェクト指向の方法で適切に動作するように、一度に1つずつ問題に対処しようとします。 。

まず、コンストラクター:

//  Make these private, will find out why in a moment...
private $db;
// __construct, not __constructor!!
private function __construct() {
    // This whole array doesn't serve any purpose because the constants
    // are defined and available in all scopes
    // while this array is local to the __construct().  
    // Just get rid of it and use the 
    // constants directly in the PDO connection
    //$config ['db'] = array(
    //    'host'          =>      DBHOST,
    //    'username'      =>      DBUSER,
    //    'password'      =>      DBPSW,
    //    'dbname'        =>      DBNAME,
    //);

    // Use some error checking when establishing your connection
    try {
      // Some extra bad whitespace removed around =
      $this->db = new PDO('mysql:host=' . DBHOST . ';dbname=' . DBNAME, DBUSER, DBPSW); 
    } catch (PDOException $e) {
      echo 'Connection failed: ' . $e->getMessage();
    }
}

次に、シングルトンアクセサーgetInstance()。

// No code changes necessary....
public static function getInstance()
{
    if (!isset(self::$instance))
    {
        $object = __CLASS__;
        self::$instance = new $object;
    }
    return self::$instance;
}

クラスにアクセスするメソッドをシングルトンとして定義したので、$dbプロパティと__construct()が作成されprivateます。$DB_class-instance = new DB()それをインスタンス化するために電話$DB_class_instance->dbをかけたり、接続に直接アクセスするために電話をかけたりすることは決してありません。代わりにDB::getInstance()、シングルトンインスタンスにアクセスするために呼び出し、メソッドはGetArticles()クエリを実行するのが好きです。

次に、クエリメソッドについて説明します。

public function GetArticles ($search){
    // Ok a SQL string, no problem...
    $sql = "SELECT `FirstColumn`, `SrcColumn`, `article` FROM `test_table`  WHERE `FirstColumn` = :search";

    // There's no need for this.  You already defined $db as 
    // a class property, so you should be using $this->db
    // $dbs = DB::getInstance();

    $query = $this->db->prepare($sql);
    // bind the $search input parameter...
    $query->bindParam(':search', $search);

    // Test for success
    if ($query->execute()) {

      $row = $query->fetch(PDO::FETCH_OBJ) {
      // I suppose you know what you want here. If you're only expecting 
      // one article, there's no real need for the while loop.
      // You can just fetch() once.
      $return = $row->article;

      // OR.....

      // However, if you are expecting *multiple* rows, you should be accumulating them
      // into an array like this:
      $return = array();
      while ($row = $query->fetch(PDO::FETCH_OBJ)) {
         // Append to an array
         $return[] = $row->article;
         // OR to get multiple columns returned as an object...
         $return[] = $row;
      }
      return $return;
   }
   else {
     // Query failed, return false or something
     return FALSE;
   }
}

最後に、コントローラーコード:

// The constructor is private, so you can't do this
// $db = new DB();
// Instead you need to use getInstance()
$db = DB::getInstance();
// Returns an array, so print_r()
print_r($db->GetArticles('23'));

クラスの$dbプロパティを作成したため、クラスのprivate外部からアクセスすることはできません。GetArticles()したがって、実行する予定の他のクエリと同様のクエリメソッドを定義する必要があります。クラスメソッドではないアドホッククエリを作成する必要があると思われる場合は、次のように変更できます。

public $db

そうすれば、クラスメソッドを作成する代わりに、次のようなクラス外のことを行うことができます。ただし、それでも電話する必要がありますgetInstance()

$dbs = DB::getInstance();
// Run a query via the PDO connection $dbs->db
$result = $dbs->db->query('SELECT * FROM sometable');

小さなスタイルの問題:

識別子は大文字と小文字を区別しないため、これは実際には問題を引き起こしませんが、スタイル的には奇妙です。define()は関数呼び出しであり、通常は小文字で使用されます。

define('DBHOST', 'localhost');
define('DBUSER', 'REMOVED');
define('DBPSW', 'REMOVED');
define('DBNAME', 'REMOVED');

ファイルのセキュリティについて

Webサーバーが正しく構成されている限り、他のユーザーはファイルを読み取ることができません。Webサーバーが.phpファイルの内容をブラウザーにダンプするのではなくPHPインタープリターに送信する場合、ファイルは安全です。共有ホストを使用していて、ホストがファイルを他のテナントから適切に分離していない場合、それが問題であり、より良いホストを取得することが唯一の適切な解決策になります。

ただし、機密ファイルはWebサーバーのドキュメントルートディレクトリの上に保存することをお勧めします。そうすれば、誤って構成されたWebサーバーでさえ、その内容を誤ってクライアントにダンプすることはできません。これらは、を介してのみPHPにアクセスできますinclude

于 2012-12-02T01:30:24.270 に答える
2

PDOはすでにオブジェクトであるため、シングルトンクラスを作成する必要はまったくないかもしれません。

代わりに、PDOオブジェクトを渡す汎用モデルクラスを作成します。

<?php

class Model {
    private $pdo;

    __construct(PDO $pdo) {
        $this->pdo = $pdo
    }

    // generic model methods go here
}

次に、これをサブクラス化して、作成する各モデルの機能を具体化できます。

使用法は次のようになります。

$PDO = new PDO("mysql:host={DBHOST};dbname={DBNAME}", DBUSER, DBPSW);
$myModel = new MyModel($pdo);
$bob = $myModel->getByName('bob');
$articles = new Articles($pdo);
$recentArticles = $articles->getRecent(new Date());

セキュリティに関して、この記事はいくつかの素晴らしい一般的なヒントを提供します、http://www.tuxradar.com/practicalphp/17/0/0。実際、ガイド全体が非常に役立ちます。

于 2012-12-02T02:05:20.923 に答える
1

アドバイス:

  1. 可能であれば、インラインSQLを使用しないでください。データベースのスキームを変更した場合、たとえば列の名前をfooからbarに変更した場合、fooが使用されているすべてのインラインSQLを検索し、それをbarに変更する必要があります。

  2. あなたのアイデアは、さまざまなアクションタイプに対して一般的な動作をするのに適していますが、この優れたアイデアは以前に実装されていたため、実装する意味はありません。たとえば、ORMであり、非常に役立つFlourishを試すことができます。

  3. パスワードをデータベースに保存できる場合は、別のファイルに保存しないでください。ただし、パスワードを暗号化することと、暗号化を改善するためにソルトを使用することも忘れないでください。

于 2012-12-02T01:29:38.617 に答える