328 lines
12 KiB
PHP
328 lines
12 KiB
PHP
<?php
|
||
/* =================================================================================
|
||
* License: GPL-2.0 license
|
||
* Author: 众产® https://ciy.cn/code
|
||
* Version: 0.6.11
|
||
* =================================================================================*/
|
||
|
||
/**
|
||
* 应用数据层类库(单服版)
|
||
* 注:单数据库服务器请用单服版,效率较高。多数据库服务器使用多服版。
|
||
* 1、type: mysql 使用MySQLi引擎 (不再支持)
|
||
* type: pdo 使用PDO引擎
|
||
* type: http 使用http透传(不再支持)
|
||
*
|
||
* 2、mode: db.php [单服版]
|
||
* dbns.php [多服版] 读写分离,一主多从模式。
|
||
* dbms.php [多服版] 多写多读模式。从注册中心获取一台空闲读服务器。
|
||
*
|
||
* getone 获取一条数据。 无数据返回null 出错返回false 判断is_array,确认数据有效
|
||
* get1 获取第一行第一列数据 无数据返回null 出错返回false
|
||
* get 获取数据集合。 无数据返回array() 出错返回false
|
||
* getraw 原始方法获取数据集合。 无数据返回array() 出错返回false
|
||
* insert 新增数据。 成功返回影响行数 出错返回false
|
||
* update 更新数据。 成功返回影响行数 出错返回false
|
||
* delete 删除及备份数据。 成功返回影响行数 出错返回false
|
||
* execute 执行SQL语句。 成功返回影响行数 出错返回false
|
||
* begin 开始事务 成功返回true 出错返回false
|
||
* commit 事务提交 成功返回true 出错返回false
|
||
* rollback 事务回滚 成功返回true 出错返回false
|
||
* tran 事务回调 成功返回true 出错返回false
|
||
* getfield 获取表字段注解 返回字段名称字符串,引用返回注解
|
||
* getdbcodes 获取表内某字段代码数组 无数据返回array()
|
||
* insert_id 获取刚新增数据的id
|
||
* errdata 错误集中接收后返回
|
||
*
|
||
* 变量名取名尽量用s尾缀区分,建议getone函数使用$xxrow,get函数使用$xxrows。
|
||
*/
|
||
|
||
namespace ciy;
|
||
|
||
class db { //单数据库版
|
||
public $linkdb; //写服务器驱动层类实例。
|
||
public $dbpst;
|
||
public $error;
|
||
public $pf;
|
||
public $lock;
|
||
|
||
function __construct($dbpst = '') {
|
||
$this->linkdb = false;
|
||
$this->dbpst = $dbpst;
|
||
$this->error = '';
|
||
$this->lock = false;
|
||
}
|
||
/**
|
||
* 连接到服务器。
|
||
*/
|
||
function connect() {
|
||
if ($this->linkdb !== false)
|
||
return $this->linkdb;
|
||
$cfg = webini('db' . $this->dbpst);
|
||
if (is_string($cfg))
|
||
die($cfg);
|
||
$this->linkdb = new pdo($cfg, $this->pf);
|
||
$this->linkdb->connect();
|
||
return $this->linkdb;
|
||
}
|
||
/**
|
||
* 获取一条数据。
|
||
* 返回array(),无数据返回null,出错返回false
|
||
* csql SQL拼接类
|
||
* 例:
|
||
* $csql = new \ciy\sql();
|
||
* $csql->...
|
||
* $row = $mydata->getone($csql);
|
||
* if(is_array($row))
|
||
* $row['username']...
|
||
*/
|
||
function getone($csql) {
|
||
$limit = $csql->limit;
|
||
if (empty($limit))
|
||
$limit = ' limit 1';
|
||
if ($this->lock)
|
||
$limit .= ' for update';
|
||
$ret = $this->connect()->get(2, $csql->buildsql() . $limit, $csql->tsmt);
|
||
if ($ret === false || $ret === null)
|
||
return $this->errdata($ret);
|
||
return $ret;
|
||
}
|
||
|
||
/**
|
||
* 获取一条数据的单个字段。
|
||
* 返回变量,无数据返回null,出错返回false
|
||
* csql SQL拼接类
|
||
* 例:
|
||
* $csql = new \ciy\sql();
|
||
* $usercount = toint($mydata->get1($csql));
|
||
* $csql->column('name');
|
||
* $username = $mydata->get1($csql);
|
||
*/
|
||
function get1($csql) {
|
||
if ($csql->column == '*')
|
||
$csql->column = 'count(*)';
|
||
$limit = $csql->limit;
|
||
if (empty($limit))
|
||
$limit = ' limit 1';
|
||
if ($this->lock)
|
||
$limit .= ' for update';
|
||
$ret = $this->connect()->get(3, $csql->buildsql() . $limit, $csql->tsmt);
|
||
if ($ret === false || $ret === null)
|
||
return $this->errdata($ret);
|
||
return $ret;
|
||
}
|
||
/**
|
||
* 获取数据集合。
|
||
* 返回array(),出错返回false
|
||
* 判断is_array,确认数据有效
|
||
* csql SQL拼接类
|
||
* pageno 第pageno页,不分页传null,默认null
|
||
* pagecount 每页pagecount条,默认20
|
||
* rowcount 返回总数据条数(数据量大,查询耗时较高),不填不查询。
|
||
* 例:
|
||
* $rows = $mydata->get($csql);//查询全部数据
|
||
* $rows = $mydata->get($csql,1,$pagecount,$rowcount);
|
||
* if(is_array($rows)){
|
||
* foreach($rows as $row)
|
||
* $row['username']...
|
||
* }
|
||
*/
|
||
function get($csql, &$rowcount = 0) { //$pageno=null 查询全部
|
||
$sql = $csql->buildsql();
|
||
$limit = $csql->limit;
|
||
if ($this->lock)
|
||
$limit .= ' for update';
|
||
$ret = $this->connect()->get(1, $sql . $limit, $csql->tsmt);
|
||
if ($ret === false)
|
||
return $this->errdata($ret);
|
||
if ($rowcount == -1) {
|
||
$column = $csql->column;
|
||
$csql->column = 'count(*)';
|
||
$rowcount = toint($this->connect()->get(3, $csql->buildsql(), $csql->tsmt));
|
||
$csql->column = $column;
|
||
}
|
||
return $ret;
|
||
}
|
||
/**
|
||
* 原始参数获取数据集合。
|
||
* 返回array(),出错返回false
|
||
* sql SQL prepare字符串
|
||
* tsmt array ?对应数据集
|
||
* 例:
|
||
* $row = $mydata->getraw('select * from xxx where id=?',[3]);
|
||
*/
|
||
function getraw($sql, $tsmt = array()) {
|
||
$ret = $this->connect()->get(1, $sql, $tsmt);
|
||
if ($ret === false)
|
||
return $this->errdata($ret);
|
||
return $ret;
|
||
}
|
||
function getfield(&$field, $table) {
|
||
$fieldrows = $this->connect()->get(1, 'show full fields from ' . $table, array());
|
||
if ($fieldrows === false)
|
||
return $this->errdata($fieldrows);
|
||
$sorts = array();
|
||
foreach ($fieldrows as $fr) {
|
||
if (!empty($fr['Comment']))
|
||
$sorts[] = $fr['Field'];
|
||
$field[$fr['Field']] = array('c' => $fr['Comment']);
|
||
}
|
||
return implode(',', $sorts);
|
||
}
|
||
function getdbcodes($table, $field) {
|
||
$fieldrow = $this->connect()->get(1, 'show full fields from ' . $table . ' where Field=?', array($field));
|
||
if (count($fieldrow) == 0)
|
||
return array();
|
||
$comment = $fieldrow[0]['Comment'];
|
||
$ret = array();
|
||
$ind = strpos($comment, ',TINT');
|
||
if ($ind !== false) {
|
||
$exts = explode('|', substr($comment, $ind + 6));
|
||
$exts = explode('.', $exts[0]);
|
||
for ($i = 0; $i < count($exts); $i++) {
|
||
$excos = explode(':', $exts[$i]);
|
||
if (count($excos) > 1) {
|
||
$ret[] = array('id' => $excos[0], 'name' => $excos[1]);
|
||
} else if (!empty($excos[0])) {
|
||
$ret[] = array('id' => $i, 'name' => $excos[0]);
|
||
}
|
||
}
|
||
return $ret;
|
||
}
|
||
$ind = strpos($comment, ',TBIN');
|
||
if ($ind !== false) {
|
||
$exts = explode('|', substr($comment, $ind + 6));
|
||
$exts = explode('.', $exts[0]);
|
||
for ($i = 0; $i < count($exts); $i++) {
|
||
$excos = explode('.', $exts[$i]);
|
||
$ret[] = array('id' => $i + 1, 'name' => $exts[$i]);
|
||
}
|
||
return $ret;
|
||
}
|
||
$ind = strpos($comment, ',BOOL');
|
||
if ($ind !== false) {
|
||
$exts = explode('.', substr($comment, $ind + 6));
|
||
if (count($exts) == 1)
|
||
$exts[1] = '';
|
||
$ret[] = array('id' => 1, 'name' => empty($exts[0]) ? '✔' : $exts[0]);
|
||
$ret[] = array('id' => 2, 'name' => empty($exts[1]) ? '✘' : $exts[1]);
|
||
return $ret;
|
||
}
|
||
return $ret;
|
||
}
|
||
function insert_id() {
|
||
return $this->connect(true)->insert_id();
|
||
}
|
||
function insert($csql, $updata) {
|
||
$ret = $this->connect(true)->insert($csql, $updata);
|
||
if ($ret === false)
|
||
return $this->errdata($ret);
|
||
return $ret;
|
||
}
|
||
function update($csql, $updata) {
|
||
$ret = $this->connect(true)->update($csql, $updata);
|
||
if ($ret === false)
|
||
return $this->errdata($ret);
|
||
return $ret;
|
||
}
|
||
/**
|
||
* 删除表数据,支持备份到_bak。(注意_bak建表时,应去掉id的自增属性)
|
||
* 成功返回影响行数,失败返回false
|
||
* csql SQL拼接类
|
||
* backup false:直接删除;true:先备份到table_bak,再删除。
|
||
* 例:
|
||
* $affected = $mydata->delete($csql,true);//备份后删除
|
||
*/
|
||
function delete($csql, $backup = false) {
|
||
if ($backup) {
|
||
$fields = $this->connect(true)->get(1, 'show full fields from ' . $csql->table, array());
|
||
$fieldlts = array();
|
||
if ($fields === false)
|
||
return $this->errdata($fields);
|
||
foreach ($fields as $row)
|
||
$fieldlts[] = $row['Field'];
|
||
$fieldlt = implode(',', $fieldlts);
|
||
$sql = "insert into {$csql->table}_bak ({$fieldlt}) select {$fieldlt} from {$csql->table}" . $csql->buildwhere();
|
||
$ret = $this->connect(true)->execute($sql, $csql->tsmt);
|
||
if ($ret === false)
|
||
return $this->errdata($ret);
|
||
}
|
||
$ret = $this->connect(true)->execute("delete from {$csql->table}" . $csql->buildwhere(), $csql->tsmt);
|
||
if ($ret === false)
|
||
return $this->errdata($ret);
|
||
return $ret;
|
||
}
|
||
/**
|
||
* 执行SQL语句。
|
||
* 成功返回影响行数,失败返回false
|
||
* sql SQL语句。
|
||
* 例:
|
||
* $affected = $mydata->execute('update users set username=? where id=?',['aaa',12]);
|
||
*/
|
||
function execute($sql, $tsmt = array()) {
|
||
$ret = $this->connect(true)->execute($sql, $tsmt);
|
||
if ($ret === false)
|
||
return $this->errdata($ret);
|
||
return $ret;
|
||
}
|
||
function begin() {
|
||
$ret = $this->connect(true)->begin();
|
||
if ($ret === false)
|
||
return $this->errdata($ret);
|
||
$this->lock = true;
|
||
return $ret;
|
||
}
|
||
function commit() {
|
||
$ret = $this->connect(true)->commit();
|
||
if ($ret === false)
|
||
return $this->errdata($ret);
|
||
$this->lock = false;
|
||
_setmemvar($this, 'func_commit', array('params+1'));
|
||
return $ret;
|
||
}
|
||
function rollback() {
|
||
$ret = $this->connect(true)->rollback();
|
||
if ($ret === false)
|
||
return $this->errdata($ret);
|
||
$this->lock = false;
|
||
_setmemvar($this, 'func_rollback', array('params+1'));
|
||
return $ret;
|
||
}
|
||
function tran($func) {
|
||
if (!($func instanceof \Closure)) {
|
||
$this->error = '没有传递正确的闭包函数';
|
||
return false;
|
||
}
|
||
$this->begin();
|
||
$ret = false;
|
||
try {
|
||
$ret = $func();
|
||
} catch (\Exception $ex) {
|
||
$ret = false;
|
||
$this->error = $ex->getMessage();
|
||
}
|
||
if ($ret === false)
|
||
$this->rollback();
|
||
else
|
||
$this->commit();
|
||
return $ret;
|
||
}
|
||
function errdata($ret) {
|
||
if ($this->linkdb !== false)
|
||
$this->error = $this->linkdb->error;
|
||
return $ret;
|
||
}
|
||
function trace($pf, $rsuser = null) { //traceid全链路跟踪
|
||
if (!preg_match('/^[A-Z]{2}\d{13}_\d{8}$/', $pf)) //防止前端攻击
|
||
$pf = 'ER' . time() . '000_' . rand(10000000, 99999999);
|
||
$time = substr($pf, 2, 10);
|
||
if (abs(time() - $time) > 10) //跟随服务器时间
|
||
$pf .= ',svrt=' . time();
|
||
if (is_array($rsuser))
|
||
$this->pf = $pf . ',ip=' . getip() . ',uid=' . $rsuser['id'];
|
||
else
|
||
$this->pf = $pf . ',ip=' . getip() . ',uid=no';
|
||
}
|
||
function __destruct() {
|
||
}
|
||
}
|