2

所以我基本上有两个文件。最后我会得到更多,但我想创建一个名为的类,该类DB将使用 PDO 数据库操作,然后我将扩展该类以使我的所有函数都用于处理数据库。所以DBclass 会扩展为 class 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>

如果可能的话,我还有另外两个担忧:第一个问题是安全问题——这是一个好习惯吗?另一个问题是如何隐藏带有此密码数据的文件,以便我可以使用它们但没有人可以读取它们?

4

3 回答 3

3

好的,这里有很多事情要做,所以我将尝试一次解决一个问题,以使此类以面向对象的方式正常运行(而不是一组不完全相关的方法) .

首先,您的构造函数:

//  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->dbDB::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

As PDO is already an object, maybe you don't need to create a singleton class for it at all.

Instead, make a generic model class which you pass the PDO object to.

<?php

class Model {
    private $pdo;

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

    // generic model methods go here
}

Then you can subclass this and flesh out the functionality for each model that you create.

Usage would be something like:

$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());

In regards to security, this article offers some nice general tips, http://www.tuxradar.com/practicalphp/17/0/0. In fact, the entire guide is quite helpful.

于 2012-12-02T02:05:20.923 回答
1

建议:

  1. 如果可能,不要使用内联 SQL,因为如果您更改数据库的方案,假设您将列从 foo 重命名为 bar,您将必须找到使用 foo 的所有内联 SQL 并将其更改为 bar。

  2. 你的想法很好,对不同的动作类型有一个通用的行为,但是没有实现它的意义,因为这个好想法之前已经实现了。例如,您可以尝试 Flourish,它是一个 ORM,可以为您提供很多帮助。

  3. 如果可以将密码存储在数据库中,请不要将密码存储在单独的文件中,但不要忘记加密密码并使用盐来改进加密。

于 2012-12-02T01:29:38.617 回答