7 Star 23 Fork 9

myDcool/CornerPHP

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
DB.php 28.27 KB
一键复制 编辑 原始数据 按行查看 历史
zhangzhibin 提交于 2022-06-23 16:32 +08:00 . 简化FileLog用法
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977
<?php
defined('ENV') || exit('illegal Access! @110');
/**
* Class DB
* MySQL数据库链接类
* 分两部分: 1. 数据库链接 2. sql组装
*/
class DB
{
/**
* 数据库链接参数:
*/
public $dbType = 'read';// read 或 write
public $_host=''; //数据库所在主机名
public $_database = '';//当前数据库名
public $_tablename = '';//当前表的表名
public $_dt = ''; //database.tablename
public $connectKey = ''; //把已建立的链接存放在$GLOBALS['DB_LINKS']中, 键名为此变量
public $connectError = ''; //连接失败原因
public $isRelease = 0; //查询完成后是否释放
public $insertId = 0;
public $affectRows = 0;
public $custom = FALSE; //是否是直接查询SQL语句, 例如: query('selct * from ....')
public $rs; //数据库查询数据集
public $data = array(); //查询的主数据
public $relData = array(); //存放最近一次关联的数据, 暂未使用, 准备为关联多层数据用
public $isLog = false;
public static $sqls = array();
public static $currentSql = '';
/**
* SQL语句组装参数
*/
public $fields = '*';
public $arrWhere = [];
public $order = '';
public $arrOrder = [];
public $limit = '';
public $groupBy = '';
public $having = '';
public $arrUpdate = [];
public $extra = '';
public $joinField = [];
public $joinTable = [];
public $joinOn = [];
public $joinAnd = []; //表联结时的筛选条件
public $raw = ['UUID()', 'RAND()', 'NOW()', 'NULL', 'null']; //需要保持原样, 不加引号组装进SQL的字符串
//mysql保留函数 https://dev.mysql.com/doc/refman/8.0/en/func-op-summary-ref.html
public $keywords = [
'AVG', 'CONCAT', 'CONCAT_WS', 'COUNT', 'CURDATE', 'CURRENT_DATE',
'CURRENT_TIME', 'CURRENT_TIMESTAMP','CURTIME', 'DATE', 'DATE_ADD', 'DATE_FORMAT', 'DATE_SUB',
'DAY', 'DAYNAME', 'DAYOFMONTH', 'DAYOFWEEK', 'DAYOFYEAR', 'DIV',
'FLOOR','FROM_DAYS', 'FROM_UNIXTIME',
'GROUP_CONCAT', 'HOUR', 'IFNULL', 'LAST_DAY', 'LAST_INSERT_ID',
'MAX','MIN', 'MOD', 'MONTH', 'MONTHNAME','NOW','POWER', 'RAND', 'ROUND',
'STRCMP', 'SUBDATE', 'SUBSTR', 'SUBSTRING', 'SUBTIME', 'SUM', 'SYSDATE', 'TIME', 'TIME_FORMAT', 'TIME_TO_SEC', 'TIMESTAMP',
'TIMESTAMPADD', 'TIMESTAMPDIFF', 'TO_BASE64', 'TO_DAYS', 'TO_SECONDS', 'TRIM',
'UNIX_TIMESTAMP', 'UPPER', 'UTC_DATE', 'UTC_TIME', 'UTC_TIMESTAMP', 'UUID', 'UUID_SHORT',
'WEEK', 'WEEKDAY', 'WEEKOFYEAR', 'YEAR', 'YEARWEEK',
];
//构造函数
public function __construct($host='', $database='', $tablename='', $isRelease=0)
{
$this->_host = $host;//主机名
$this->_database = $database;//数据库名
$this->_tablename = $tablename;//表名
$this->_dt = $database.'.'.$tablename;//数据库名.表名 sql语句中from用了这个值
$this->isRelease = $isRelease;
}
/**
* desc 获取链接实例
* @param string $vName 虚拟表名, 对应DBConfig中$TableInfo的键名
* @param int $isRelease 执行完sql语句后是否关闭连接,大并发下需要关闭连接
* @return DB|null
* @throws Exception
*/
public static function link($vName, $isRelease=0)
{
$tableinfo = self::getDBInfo($vName);
$host = $tableinfo['vhost'];//host vname
$database = $tableinfo['database'];//database name
$tablename = $tableinfo['table'];//table name
return new self($host, $database, $tablename, $isRelease);
}
//创建一个新的mysql链接
public function newConnect($host, $username, $password, $dbname, $port, $charset='utf8mb4')
{
$mysqli = mysqli_init(); //初始化mysqli
$mysqli->options(MYSQLI_OPT_CONNECT_TIMEOUT, 3); //超时3s
$mysqli->options(MYSQLI_INIT_COMMAND, "set names {$charset}");
//连接错误时报错信息会是乱码
if ($mysqli->real_connect($host, $username, $password, $dbname, $port)) {
$this->connectError = '';
$this->log(Lang::db_connect_create.$host, 'system_connect_db');
return $mysqli;
} else {
$this->connectError = $mysqli->connect_error;
//$connectError[$host] = mysqli_connect_error();
return false;
}
}
//如果主机没变,并且已经存在MYSQL连接,就不再创建新的连接
//如果主机改变,就再生成一个实例创建一个连接
//$type == 'write'或'read'
public function getConnect($type)
{
$this->dbType = $type;
$this->connectKey = $this->_host.'::'.$this->dbType; //例如 default::read
//已经存在链接, 直接返回链接名
if (!empty($GLOBALS['DB_LINKS'][$this->connectKey])) {
return $this; // 方便调用事务等其他方法
}
//随机选取一个可用的数据库连接(区分读写)
DBConfig::init();
$hosts = DBConfig::$hosts[$this->_host][$type];
$isConnected = FALSE;
$connectCounter = 5; //最多5次重连
$connectError = array();
while (!$isConnected && $connectCounter > 0) {
$randKey = array_rand($hosts); //随机选取一台mysql主机
$config = $hosts[$randKey];
//链接数据库
$host = $config['host'];
$username = $config['username'];
$password = $config['password'];
$port = $config['port'];
$charset = $config['charset'];
$connect = $this->newConnect($host, $username, $password, $this->_database, $port, $charset);
//连接错误时报错信息会是乱码
if ($connect !== false) {
$GLOBALS['DB_LINKS'][$this->connectKey] = $connect;
$isConnected = TRUE;
} else {
$connectError[$host] = $this->connectError;
$isConnected = FALSE;
$connectCounter--;
}
}
if ($isConnected) {
return $this;
} else {
$this->error(Lang::db_connect_error . json_encode($connectError));
return $this;
}
}
/**
* 查询封装
* @param string $sql
* @return $this
* @throws Exception
*/
public function query($sql='')
{
if (!empty($sql)) {
$this->custom = TRUE;
self::$sqls[] = self::$currentSql = $sql;
} else {
self::$sqls[] = self::$currentSql;
}
$this->log(self::$currentSql, 'system_sql');
$sql = ltrim(self::$currentSql);
if (strlen($sql) == 0) {
$this->error(Lang::db_query_empty);
}
if (stripos($sql, 'SELECT') === 0 || stripos($sql, 'SHOW') === 0) {
$this->getConnect('read');//读库
} else {
$this->getConnect('write');//写库
}
$connectKey = $this->connectKey;
$this->clearQueryParam(); //清除查询条件
//执行查询语句
$this->rs = $GLOBALS['DB_LINKS'][$connectKey]->query(self::$currentSql);
($this->rs === FALSE) && $this->error($GLOBALS['DB_LINKS'][$connectKey]->error);
if (stripos($sql, 'REPLACE') === 0) {
$this->affectRows = $GLOBALS['DB_LINKS'][$connectKey]->affected_rows;
} elseif (stripos($sql, 'INSERT') === 0) {
//返回自增列的值, 主键非自增则返回0
$this->insertId = $GLOBALS['DB_LINKS'][$connectKey]->insert_id;
} elseif (stripos($sql, 'DELETE') === 0) {
$this->affectRows = $GLOBALS['DB_LINKS'][$connectKey]->affected_rows;
} elseif (stripos($sql, 'UPDATE') === 0) {
$this->affectRows = $GLOBALS['DB_LINKS'][$connectKey]->affected_rows;
} else {
$this->insertId = 0;
$this->affectRows = 0;
}
//查询完成后释放链接, 并删除链接对象
if ($this->isRelease) {
$GLOBALS['DB_LINKS'][$connectKey]->close();
unset($GLOBALS['DB_LINKS'][$connectKey]);
}
return $this;
}
//将结果集转换成数组, 一个一个返回, 如果本函数的返回值会被foreach, 就用此函数
//如果field不为空,则返回的数组以$field为键重新索引
public function rsToArrayYield($field = '')
{
if ($field) {
while ($row = $this->rs->fetch_assoc()) {
$tmp = [];
$tmp[$row[$field]] = $row;
yield $tmp;
}
} else {
while ($row = $this->rs->fetch_assoc()) {
yield $row; //不一次性获取全部数组到内存, 用一个取一个, 返回值的数据类型为"生成器"
}
}
}
//一次性获取所有数据到内存
//如果field不为空,则返回的数组以$field为键重新索引
public function getAll($field='')
{
if (empty($field)) {
$this->data = $this->rs->fetch_all(MYSQLI_ASSOC); //该函数只能用于php的mysqlnd驱动
} else {
while ($row = $this->rs->fetch_assoc()) {
$this->data[$row[$field]] = $row;
}
}
return $this->data;
}
//获取一条记录
public function getOne()
{
$this->data = $this->rs->fetch_assoc();
return !empty($this->data) ? $this->data : array();
}
/**
* 获取一条记录的某一个字段的值
* @param string $field 字段名
* @param string $default 默认值
* @return string
* @throws Exception
*/
public function getOneValue($field, $default='')
{
$rs = $this->rs->fetch_assoc();
if (!empty($rs) && !isset($rs[$field])) {
$this->error(Lang::db_query_field_not_exist .$field);
}
return isset($rs[$field]) ? $rs[$field] : $default;
}
//获取数据集中所有某个字段的值
public function getValues($field, $index='')
{
$this->getAll();
if (!empty($index)) {
return array_column($this->data, $field, $index); //以$index字段的值做索引, 以$field字段的值做值
} else {
return array_column($this->data, $field);
}
}
//获取总数
public function getCount()
{
$rs = $this->rs->fetch_assoc();
return isset($rs['N']) ? $rs['N'] : 0;
}
//断开数据库连接
public function close()
{
$GLOBALS['DB_LINKS'][$this->connectKey]->close();
}
//释放数据
public function freeResult()
{
if ($this->rs instanceof mysqli_result) {
$this->rs->free_result();
}
}
//事务
//自动提交开关
public function autoCommit($bool)
{
$GLOBALS['DB_LINKS'][$this->connectKey]->autocommit($bool);
return $this;
}
//事务开始
// http://php.net/manual/zh/mysqli.begin-transaction.php
public function beginTransaction($flag=MYSQLI_TRANS_START_READ_WRITE, $name)
{
$GLOBALS['DB_LINKS'][$this->connectKey]->begin_transaction($flag, $name);
return $this;
}
//事务完成提交
public function commit()
{
$GLOBALS['DB_LINKS'][$this->connectKey]->commit();
return $this;
}
//回滚
public function rollback()
{
$GLOBALS['DB_LINKS'][$this->connectKey]->rollback();
return $this;
}
//获取当前连接
public static function getCurrentLinks()
{
return $GLOBALS['DB_LINKS'];
}
//获取所有数据库
public function getDatabaseList($host)
{
DBConfig::init();
$hostInfo = DBConfig::getHostInfo($host);
$connect = $this->newConnect($hostInfo['host'], $hostInfo['username'], $hostInfo['password'], '', $hostInfo['port'], $hostInfo['charset']);
if ($connect !== false) {
$this->rs = $connect->query('show databases');
$dbList = array_column($this->rs->fetch_all(), $value=0);
sort($dbList, SORT_FLAG_CASE);
return $dbList;
} else {
return [];
}
}
//获取所有表
public function getTableList($host, $dbname)
{
DBConfig::init();
$hostInfo = DBConfig::getHostInfo($host);
$connect = $this->newConnect($hostInfo['host'], $hostInfo['username'], $hostInfo['password'], $dbname, $hostInfo['port'], $hostInfo['charset']);
if ($connect !== false) {
$this->rs = $connect->query('show tables');
$tableList = array_column($this->rs->fetch_all(), $value=0);
sort($tableList, SORT_FLAG_CASE);
return $tableList;
} else {
return [];
}
}
public function getFieldList($host, $dbname, $table)
{
DBConfig::init();
$hostInfo = DBConfig::getHostInfo($host);
$connect = $this->newConnect($hostInfo['host'], $hostInfo['username'], $hostInfo['password'], $dbname, $hostInfo['port'], $hostInfo['charset']);
if ($connect !== false) {
$this->rs = $connect->query("select COLUMN_NAME, COLUMN_TYPE, COLUMN_DEFAULT, EXTRA, CHARACTER_SET_NAME, COLLATION_NAME, COLUMN_COMMENT from information_schema.columns where table_schema ='{$dbname}' and table_name = '{$table}' ORDER BY ORDINAL_POSITION");
$fieldList = $this->rs->fetch_all(MYSQLI_ASSOC);
//sort($fieldList, SORT_FLAG_CASE);
return $fieldList;
} else {
return [];
}
}
/**
* 查询语句
* @param bool $isQuery 组装完sql语句是否立即查询
* @return $this
*/
public function select($isQuery=TRUE)
{
$where = $this->getWhere();
$order = $this->getOrder();
self::$currentSql = "SELECT {$this->fields} FROM {$this->_dt} {$where} {$this->groupBy} {$this->having} {$order} {$this->limit} {$this->extra}";
$isQuery && $this->query();
return $this;
}
/**
* 增, 另注: 主从切换时注意读写权限
* @param $arrData
* @param bool $isQuery 组装完sql语句是否立即查询
* @return $this
*/
public function insert($arrData, $isQuery=TRUE)
{
$arrData = $this->safe($arrData);
$fields = array_keys($arrData);
$strFields = implode(',', $fields);
$strValues = implode(',', $arrData);
self::$currentSql = "INSERT INTO {$this->_dt} ($strFields) VALUES ($strValues)";
$isQuery && $this->query();
return $this;
}
/**
* 增, 注意高并发下不要用 replace into 效率低而且容易死锁
* @param $arrData
* @param bool $isQuery 组装完sql语句是否立即查询
* @return $this
*/
public function replace($arrData, $isQuery=TRUE)
{
$arrData = $this->safe($arrData);
$fields = array_keys($arrData);
$strFields = implode(',', $fields);
$strValues = implode(',', $arrData);
self::$currentSql = "REPLACE INTO {$this->_dt} ($strFields) VALUES ($strValues)";
$isQuery && $this->query();
return $this;
}
/**
* 每次插入多条记录
* 每条记录的字段相同,但是值不一样
* @param $strFields
* @param $arrData
* @param bool $isQuery 组装完sql语句是否立即查询
* @return $this
*/
public function insertm($strFields, $arrData, $isQuery=TRUE)
{
$data = [];
foreach ($arrData as $arr) {
$arr = $this->safe($arr); //单个SQL语句的数据
$str = implode(',', $arr);
$data[] = "($str)";
}
$strData = implode(',', $data);
self::$currentSql = "INSERT INTO {$this->_dt} ($strFields) VALUES {$strData}";
$isQuery && $this->query();
return $this;
}
/**
* 删除
* @param bool $isQuery 组装完sql语句是否立即查询
* @return $this
* @throws Exception
*/
public function delete($isQuery=TRUE)
{
$where = $this->getWhere();
if (empty($where)) {
$this->error(Lang::db_no_where . $this->_dt);
}
self::$currentSql = "DELETE FROM {$this->_dt} {$where} {$this->limit}";
$isQuery && $this->query();
return $this;
}
//改, 自定义update set语句, 注意没有安全校验
public function addUpdate($str)
{
$this->arrUpdate[] = $str;
return $this;
}
//改, 键值对: a = 1, a = 'b', 有安全校验
public function updateVal($arrData)
{
foreach ($arrData as $field => $v) {
$v = $this->safe($v, $field);
$this->arrUpdate[] = "{$field} = {$v}";
}
return $this;
}
//改, 自定义运算符
// updateOp(a, b, + 1) ==> a = b + 1;
public function updateOp($field1, $field2, $op, $numeric)
{
if (!is_numeric($numeric)) {
$this->error(Lang::db_value_not_number." {$field1} = {$field2} {$op} {$numeric}");
} else {
$this->arrUpdate[] = "{$field1} = {$field2} {$op} {$numeric}";
}
return $this;
}
/**
* 改, 组装update语句
* @param bool $isQuery 组装完sql语句是否立即查询
* @return $this
* @throws Exception
*/
public function update($isQuery=TRUE)
{
$where = $this->getWhere();
if (empty($where)) {
$this->error(Lang::db_no_where.self::$currentSql);
}
$strSql = implode(',', $this->arrUpdate);
self::$currentSql = "UPDATE {$this->_dt} set {$strSql} {$where} {$this->limit}";
$isQuery && $this->query();
return $this;
}
/**
* 获取总数
* @param bool $isQuery 组装完sql语句是否立即查询
* @return $this|string
*/
public function count($isQuery=TRUE)
{
$where = $this->getWhere();
self::$currentSql = "SELECT COUNT(1) AS N FROM {$this->_dt} {$where}";
if ($isQuery) {
$this->query();
return $this->getCount();
} else {
return $this;
}
}
//添加自定义where条件, 注意直接调用时没有安全校验
public function addWhere($str)
{
$this->arrWhere[] = $str;
return $this;
}
//where 等于
public function where($arrData)
{
if (empty($arrData)) {
return $this;
}
$arrData = $this->safe($arrData);
foreach ($arrData as $k => $v) {
if (!is_null($v)) {
$this->addWhere("({$k} = {$v})");
} else {
$this->addWhere("({$k} IS NULL)");
}
}
return $this;
}
//where in
public function whereIn($key, $arrData, $force=false)
{
if (empty($arrData)) {
if ($force === false) {
$str = "({$key} IN (''))";
$this->addWhere($str);
return $this;
} else {
$this->error(Lang::db_where_in_empty);
}
}
$this->safe($arrData);
$arrData = array_unique($arrData);
// sort($arrData);
foreach ($arrData as $k => $v) {
if (!is_numeric($v) && !is_string($v)) {
$this->error(Lang::db_value_not_support.$k);
unset($arrData[$k]);
} else {
$arrData[$k] = !is_string($v) ? $v : "'{$v}'";
}
}
$strData = implode(',', $arrData);
$this->addWhere("({$key} IN ( {$strData} ))");
return $this;
}
//between and
public function whereBetween($key, $min, $max)
{
$min = $this->safe($min);
$max = $this->safe($max);
$str = "({$key} BETWEEN {$min} AND {$max})";
$this->addWhere($str);
return $this;
}
//where(a, >, b) ==> where a>b
public function whereOp($key, $op, $value)
{
$value = $this->safe($value, $key);
$this->addWhere("({$key} {$op} {$value})");
return $this;
}
//获取最终查询用的where条件
public function getWhere()
{
if (!empty($this->arrWhere)) {
return 'WHERE '.implode(' AND ', $this->arrWhere);
} else {
return '';
}
}
//以逗号隔开
public function fields($fields)
{
$this->fields = $fields;
return $this;
}
// order by a desc
public function order($order)
{
if (!empty($order)) {
$this->arrOrder[] = $order;
}
return $this;
}
//获取order语句
public function getOrder()
{
if (empty($this->arrOrder)) {
return '';
} else {
$str = implode(',', $this->arrOrder);
$this->order = "ORDER BY {$str}";
}
return $this->order;
}
//group by year, month
public function groupBy($str)
{
$this->groupBy = "GROUP BY {$str}";
return $this;
}
// haveing count(*) > 1 and t1.status = 1
public function having($str)
{
$this->having = "HAVING {$str} ";
}
//e.g. '0, 10'
//用limit的时候可以加where条件优化:select ... where id > 1234 limit 0, 10
public function limit($limit)
{
if (!empty($limit)) {
$this->limit = 'LIMIT '.$limit;
}
return $this;
}
/**
* 组装最终的join 语句
* @param bool $isQuery 组装完sql语句是否立即查询
* @return $this
*/
public function join($isQuery=TRUE)
{
$where = $this->getWhere();
$order = $this->getOrder();
$joinFields = $this->getJoinFields();
$joinTable = $this->getJoinTable();
self::$currentSql = "SELECT {$joinFields} FROM {$this->_dt} {$joinTable} {$where} {$this->groupBy} {$this->having} {$order} {$this->limit}";
$isQuery && $this->query();
return $this;
}
/**
* 连接查询, 设置查询字段
* 可多次调用
* @param string $table 表名
* @param string $fields 该表的字段
* @return $this
*/
public function joinFields($table, $fields)
{
$fields = preg_replace('#,\s+#', ',', $fields);//去掉空白
$fields = explode(',', $fields);
foreach ($fields as $k => $v) {
$fields[$k] = $table.'.'.$v;
}
$this->joinField[] = implode(',', $fields);
return $this;
}
/**
* 组装要查询的字段
* @return string
*/
public function getJoinFields()
{
return implode(', ', $this->joinField);
}
/**
* 组装 left join .. on ..
* 注意, where中的[not] exists 语句中的不能有 inner join tb on xxx and xxx 中的 and xxx
* @param string $table1 左表的model名, 会根据它来查找真正的表名
* @param string $field1 关联字段
* @param string $table2 右表的model名, 会根据它来查找真正的表名
* @param string $field2 关联字段
* @param string $joinMethod join方式, 默认LEFT, 还可以是 RIGHT, INNER
* @return $this
* @throws Exception
*/
public function joinTable($table1, $field1, $table2, $field2, $joinMethod = 'LEFT')
{
$arr1 = self::getDBInfo($table1);
$table1Name = $arr1['table'];
$arr2 = self::getDBInfo($table2);
$table2Name = $arr2['table'];
$str = $joinMethod. " JOIN {$table2Name} ON {$table1Name}.{$field1} = {$table2Name}.{$field2}";
$this->joinTable[] = $str;
return $this;
}
//将数组转换成字符串
public function getJoinTable()
{
return implode(' ', $this->joinTable);
}
//tf1: table1.field1
public function joinTables($tf1, $tf2, $joinMethod = 'LEFT')
{
list($table1, $field1) = explode('.', $tf1);
list($table2, $field2) = explode('.', $tf2);
$arr1 = self::getDBInfo($table1);
$table1Name = $arr1['table'];
$arr2 = self::getDBInfo($table2);
$table2Name = $arr2['table'];
$joinAnd = $this->getJoinAnd();
$str = $joinMethod. " JOIN {$table2Name} ON {$table1Name}.{$field1} = {$table2Name}.{$field2} {$joinAnd}";
$this->joinAnd = array();
$this->joinTable[] = $str;
return $this;
}
public function joinAnd($tf, $operation, $value)
{
list($table, $field) = explode('.', $tf);
$arr = self::getDBInfo($table);
$tableName = $arr['table'];
if (is_int($value)) {
$this->joinAnd[] = "{$tableName}.{$field} {$operation} {$value}"; //table.field = 123 或者 table.field > 123
} else {
if (strpos($value, '(') !== FALSE) {
$this->joinAnd[] = "{$tableName}.{$field} {$operation} {$value}"; // table.field in (xxx)
} elseif (stripos($value, 'and') !== FALSE) {
$this->joinAnd[] = "({$tableName}.{$field} {$operation} {$value})"; // table.field between xxx and yyy
} else {
$this->joinAnd[] = "{$tableName}.{$field} {$operation} '{$value}'"; //table.field = 'xxx'
}
}
return $this;
}
public function getJoinAnd()
{
if (!empty($this->joinAnd)) {
return ' AND '. implode(' AND ', $this->joinAnd);
} else {
return '';
}
}
//自定义sql后缀,
// setExtra(for update) ==> select.... for update;
// setExtra(lock in share mode) ==> select.... lock in share mode;
public function setExtra($str)
{
$this->extra = $str;
}
//清除查询数据, 避免影响下一次查询
public function clearQueryParam()
{
$this->arrWhere = [];
$this->arrUpdate = [];
$this->order = '';
$this->arrOrder = [];
$this->limit = '';
$this->groupBy = '';
$this->having = '';
$this->joinField = [];
$this->joinTable = [];
$this->joinOn = [];
}
/**
* @param string $modelName 对应$TableInfo的键名
* @return array
* @throws Exception
*/
public static function getDBInfo($modelName)
{
$TableInfo = DBConfig::$TableInfo;
$strDT = '';
if (array_key_exists($modelName, $TableInfo)) {
$strDT = $TableInfo[$modelName];//获得database table 字符串
} else {
foreach ($TableInfo as $pattern => $dt) {
if (strpos($pattern, '(') !== FALSE) {
preg_match('#' . $pattern . '#', $modelName, $matches);
if (!empty($matches)) {
$strDT = $dt;
foreach ($matches as $key => $value) {
$strDT = str_replace('$' . $key, $value, $strDT);
}
break;
}
}
}
}
if (!empty($strDT)) {
$strDT = preg_replace('#,\s+#', ',', $strDT);//去掉空白
$arr = explode(',', $strDT);
return array(
'vhost' => $arr[0],
'database' => $arr[1],
'table' => $arr[2],
);
} else {
throw new Exception(Lang::db_table_not_exist.$modelName);
}
}
public function safe($data, $field='')
{
if (is_string($data)) {
if (!in_array($data, $this->raw)) {
$data = $this->excapeString($data);
return "'{$data}'";
} else {
return $data;
}
} elseif (is_numeric($data)) {
return $data;
} elseif (is_null($data)) {
return null;
} elseif (is_array($data)) {
foreach ($data as $k => &$v) {
$v = $this->safe($v, $k);
}
return $data;
} else {
$this->error(Lang::db_value_not_support.$field.' 2');
}
}
/**
* Returns a string with backslashes before characters that need to be escaped.
* As required by MySQL and suitable for multi-byte character sets
* Characters encoded are NUL (ASCII 0), \n, \r, \, ', ", and ctrl-Z.
* suitable for all statements, but especially suitable for `LIKE`.
*
* @param string $string String to add slashes to
* @return $string with `\` prepended to reserved characters
*
* @author Trevor Herselman
*/
public function excapeString($string)
{
if (function_exists('mb_ereg_replace')) {
return mb_ereg_replace('[\x00\x0A\x0D\x1A\x22\x27\x5C]', '\\\0', $string);
} else {
return preg_replace('/[\x00\x0A\x0D\x1A\x22\x27\x5C]/u', '\\\$0', $string);
}
}
public function error($str)
{
FileLog::error($str. '===' . self::$currentSql, 'db_error');
throw new Exception($str.'===='.FileLog::$uuid);
}
private function log($str, $prefix='db_log')
{
if ($this->isLog) {
FileLog::info($str, $prefix);
}
}
public function startLog()
{
$this->isLog = true;
return $this;
}
public function closeLog()
{
$this->isLog = false;
return $this;
}
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
PHP
1
https://gitee.com/myDcool/SummerPHP.git
git@gitee.com:myDcool/SummerPHP.git
myDcool
SummerPHP
CornerPHP
master

搜索帮助