连接数据库
PHP操作数据库的方式有多种如 mysql
、mysqli
、PDO
,目前主要使用的是PDO处理。
PDO 提供了一个数据访问抽象层,这意味着,不管使用哪种数据库,都可以用相同的函数(方法)来查询和获取数据。
下面是使用 PDO
连接数据库的操作,当连接失败时将抛出异常。
<?php
header('Content-type:text/html;charset=utf8');
$config = [
'host' => 'localhost',
'user' => 'root',
'password' => '',
'db' => 'houdunren',
'charset'=>'utf8'
];
try {
$dsn = sprintf('mysql:host=%s;dbname=%s;charset=utf8', $config['host'], $config['db'],$config['charset']);
$pdo = new PDO($dsn, $config['user'], $config['password']);
} catch (PDOException $e) {
die($e->getMessage());
}
错误处理
错误类型 | 说明 |
---|---|
PDO::ERRMODE_SILENT | 不显示错误 |
PDO::ERRMODE_WARNING | 显示警告错误 |
PDO::ERRMODE_EXCEPTION | 抛出异常 |
可以在连接时设置错误类型
$pdo = new PDO($dns, $config['user'], $config['password'], [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
也可以使用 setAttribute
方法设置错误处理方式
...
$pdo = new PDO($dns, $config['user'], $config['password']);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
...
执行语句
使用 exec
方法可以发送执行语言
$pdo->exec("INSERT INTO news (title) VALUES('houdunren.com')");
echo "自增主键:".$pdo->lastInsertId();
执行删除操作
$affectedRows = $pdo->exec("DELETE FROM news WHERE id>3");
echo "受影响的条数:".$affectedRows;
发送查询
设置返回列名
属性 | 说明 |
---|---|
PDO::CASE_LOWER | 强制列名小写 |
PDO::CASE_NATURAL | 保留数据库驱动返回的列名 |
PDO::CASE_UPPER | 强制列名大写 |
$pdo->setAttribute(PDO::ATTR_CASE,PDO::CASE_LOWER);
返回结果
返回类型 | 说明 |
---|---|
$result->fetchAll(PDO::FETCH_ASSOC) | 获得关联数据 |
$result->fetchAll(PDO::FETCH_NUM) | 获得索引数据 |
$result->fetchAll(PDO::FETCH_BOTH) | 同时获取关联与索引数据 |
$result->fetchAll(PDO::FETCH_OBJ) | 获取对象类型数据 |
fetchAll
一次获取所有结果
...
$query = $pdo->query("select * from news");
$rows = $query->fetchAll();
print_r($rows);
...
fetch
每次获取结果中的一条数据
...
$pdo = new PDO($dns, $config['user'], $config['password']);
$query = $pdo->query("select * from news");
while ($field = $query->fetch(PDO::FETCH_ASSOC)) {
echo sprintf("编号:%s 标题:%s<br/>", $field['id'], $field['title']);
}
...
预准备
预准备是将SQL的解析阶段与参数绑定分开执行,从而可以有效的防止SQL注入。
SQL注入
下面来看一个SQL注入的例子
$query = $pdo->query("SELECT * FROM news WHERE id={$_GET['id']}");
如果GET参数如下将产生SQL注入
http://houdunren.test/1.php?id=1 or id>1
使用预准备
因为预准备是将解析与参数分开处理,可以有效的防止SQL注入。
$sql = "SELECT * FROM news WHERE id=:id";
$sth = $pdo->prepare($sql);
$sth->execute([':id' => $_GET['id']]);
$rows = $sth->fetchAll(PDO::FETCH_ASSOC);
print_r($rows);
预准备添加记录
$sql = "INSERT INTO news (title) VALUES(?)";
$sth = $pdo->prepare($sql);
$sth->execute(['houdunren.com']);
echo $pdo->lastInsertId();
使用点位符操作
$sth = $pdo->prepare("SELECT * FROM news WHERE id>?");
$sth->execute([3]);
print_r($sth->fetchAll());
SQL生成器
处理类
下面构建一个SQL语句生成器,用于快速操作数据库。
<?php
namespace Database;
use PDO;
use Exception;
class DB
{
protected $link = null;
protected $options = ['table' => '', 'field' => '', 'limit' => '', 'order' => '', 'where' => ''];
public function __construct($config)
{
$this->connect($config);
}
public function connect($config)
{
if (is_null($this->link)) {
$dsn = sprintf('mysql:host=%s;dbname=%s;charset=utf8', $config['host'], $config['db']);
$this->link = new PDO($dsn, $config['user'], $config['password'], [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
}
return $this->link;
}
public function query($sql, array $vars = [])
{
$sth = $this->link->prepare($sql);
$sth->execute($vars);
return $sth->fetchAll();
}
public function execute($sql, array $vars = [])
{
$sth = $this->link->prepare($sql);
return $sth->execute($vars);
}
public function field(...$fields)
{
$this->options['field'] = '`' . implode('`,`', $fields) . '`';
return $this;
}
public function table(string $table)
{
$this->options['table'] = $table;
return $this;
}
public function get()
{
$sql = "SELECT {$this->options['field']} FROM {$this->options['table']} {$this->options['where']} {$this->options['order']} {$this->options['limit']}";
return $this->link->query($sql);
}
public function orderBy(string $order)
{
$this->options['order'] = " ORDER BY " . $order;
return $this;
}
public function limit(...$limit)
{
$this->options['limit'] = " LIMIT " . implode(',', $limit);
return $this;
}
public function where(string $where)
{
$this->options['where'] = " WHERE " . $where;
return $this;
}
public function insert(array $vars)
{
$sql = "INSERT INTO {$this->options['table']} (" . implode(',', array_keys($vars)) . ") VALUES(" . implode(',', array_fill(0, count($vars), '?')) . ")";
return $this->execute($sql, array_values($vars));
}
public function delete()
{
$sql = "DELETE FROM {$this->options['table']} {$this->options['where']}";
return $this->execute($sql);
}
public function update(array $vars)
{
if (empty($this->options['where']))
throw new Exception('不能缺少条件');
$sql = "UPDATE {$this->options['table']} SET " . implode('=?,', array_keys($vars)) . "=? {$this->options['where']}";
return $this->execute($sql, array_values($vars));
}
}
预准备查询
...
$db->query("SELECT * FROM news WHERE id>=:id", ['id' => 1])
...
预准备执行
$db->execute("INSERT INTO news (title) VALUES(?)", ['hdcms.com'])
对象实例
use DatabaseDB;
include 'DB.php';
$config = [
'host' => 'localhost',
'user' => 'root',
'password' => '',
'db' => 'houdunren'
];
try {
...
$db = new DB($config);
...
}catch(Exception $e){
die($e->getMessage());
}
查询操作
...
$rows = $db->table('news')->field('id', 'title')->limit(1, 3)->orderBy('id desc')->where("id>3")->get();
...
新增操作
...
$db->prepareExecute("INSERT INTO news (title) VALUES(?)", ['hdcms.com']);
...
更新操作
...
$db->table('news')->where('id=1')->update(['title' => "sina", 'author' => '后盾人', 'description' => '个性介绍']);
...
删除操作
...
$db->table('news')->where('id>2')->delete();
...