* Date: 13-10-12 * Time: 下午5:48 */ class Mongo_DB { #链接 public $conn = null; #MongoDB public $db = null; #链接参数 private $url = ''; #判断db是否链接 private $collected = null; #查询、更新 映射 有| private $four_map = array( #值是字符串,值不用处理 '>' => '$gt', '>=' => '$gte', '<' => '$le', '<=' => '$lte', '!=' => '$ne', '@' => '$exists', #键是否存在 '?' => 'perl', #正则 ); private $ele_map = array( #数组,值需要处理 '~' => '$elemMatch' #内嵌文档 ); private $log_map = array( #值必须是数组 '^' => '$in', '!^' => '$nin', '*' => '$all', #指定数组元素 ); #没有| private $lgi_map = array( #必须是二维数组 '$' => '$or', '&' => '$and', ); private $where_map = array( '%' => '$where', #javascript 函数 ); private $sort_map = array( 'DESC' => -1, 'ASC' => 1 ); #当前db下所有集合=>键数组 public $collections = null; #基本配置参数 private $config = array( 'host' => 'localhost', 'port' => '27017', 'dbname' => '', 'user' => '', 'pass' => '', 'logpath' => '', #日志目录 'replicaset' => array( #集群 'host' => array() // 'host' => array('host:port'), #主机群 // 'options' => array('readPreference', 'readPreferenceTags', 'replicaSet','slaveok') ), ); /** * 构造函数,基本参数设置 * @param $config * */ public function __construct($config) { if (is_array($config) && $config) { foreach ($this->config as $k => $v) { if (isset($config[$k]) && $config[$k]) $this->config[$k] = !is_array($config[$k]) ? trim($config[$k]) : $config[$k]; } $this->connect(); } } /** * 初始化mongo * */ private function connect() { if (!extension_loaded('mongo')) exit('ERROR:MONGO EXTENSION NOT LOAD'); if ($this->conn === NULL) { try { if ($this->config['replicaset']['host']) { #todo 主从配置,或者副本集,读扩展, } else { $this->url .= "mongodb://{$this->config['user']}:{$this->config['pass']}@{$this->config['host']}: {$this->config['port']}/{$this->config['dbname']}"; $this->conn = new MongoClient($this->url); } $this->db = $this->conn->selectDB($this->config['dbname']); if ($this->db) { $this->collected = true; $this->GetAllCollection(); #获取所有集合列表 } } catch (MongoConnectionException $e) { $this->ErrLog($e->getMessage()); exit('MONGO CONNECT ERROR'); } } } /** * 析构函数 */ public function __destruct() { $this->collected = $this->collections = $this->db = $this->conn = null; } /** * 获取db下所有集合名称 * * @internal param $dbname * @return bool */ private function GetAllCollection() { if (!$this->collected) return false; $colls = $this->db->listCollections(); if ($colls) { foreach ($colls as $v) { $pos = strpos($v, $this->config['dbname']); if ($pos !== false) $this->collections[] = substr($v, ($pos + strlen($this->config['dbname']) + 1)); } return true; } else { return false; } } /** * 初始化集合对象 * @param $collname 集合名 * @return mixed */ public function GetMonCollection($collname) { if (!$this->collected) return false; return $this->db->selectCollection($collname); } /** * 转换字符编码 * @param $array * @return bool */ private function ConvertEncode($array) { if (is_array($array)) { foreach ($array as &$v) { if (is_array($v)) { $v = $this->ConvertEncode($v); if (!$v) return false; } else { $code = mb_detect_encoding($v, array('UTF-8', 'ASCII', 'GB2312', 'GBK', 'CP936'), true); if ($code !== 'UTF-8') $v = mb_convert_encoding($v, 'UTF-8', $code); } } return $array; } return false; } /** * 获取where参数 * @param $where * @param bool $type * @return string * */ private function GetWhere($where, $type = false) { $wheres = array(); $maps = array('four_map', 'log_map', 'ele_map'); $maps_np = array_merge($this->lgi_map, $this->where_map); if (is_array($where) && $where) { #过滤查询条件 foreach ($where as $field => $val) { $pos = strpos($field, '|'); if ($pos !== false) { #四则、正则、函数、数组、in、多重条件内嵌文档 $tep = substr($field, 0, $pos); $key = substr($field, ($pos + 1)); if ($key !== false) { foreach ($maps as $v) { $arr = $this->$v; if (in_array($tep, array_keys($arr))) { if ($v == 'ele_map' && is_array($val)) $val = $this->GetWhere($val, true); if ($tep == '?') { #正则 $val = new MongoRegex($val); $wheres[$key] = $val; } else { $wheres[$key][$arr[$tep]] = $val; } } } } } elseif (in_array($field, array_keys($maps_np))) { if (in_array($field, array_keys($this->lgi_map)) && is_array($val)) { #逻辑 foreach ($val as $v) { $val = $this->GetWhere($v, true); $wheres[$maps_np[$field]][] = $val; } } else { $wheres[$maps_np[$field]] = $val; } } else { #普通查询、单一条件内嵌文档 if (strpos($field, "[") !== false) $field = str_replace("[", ".", $field); if (is_array($val) && $type) { $arr = $this->GetWhere($val); foreach ($arr as $k => $v) { $wheres[$k][] = $v; } } elseif (is_null($val)) { $wheres[$field] = array('$in' => array(null), '$exists' => 1); } else { $wheres[$field] = $val; #支持 array('age'=>array('>'=>'18','<='=>'20')) } } } } return $wheres; } /** * 插入一行 * @param $collect * @param $value * @return bool */ public function InsOne($collect, $value) { if (!$this->collected || !is_array($value)) return false; $id = array_search('id', array_keys($value)); #处理有id字段的情况 if ($id !== false && array_search('_id', array_keys($value)) === false) { $value['_id'] = $value['id']; unset($value['id']); } $value = $this->ConvertEncode($value); if (!$value) return false; try { $result = $this->GetMonCollection($collect)->insert($value); $result = $result['err'] ? false : true; } catch (MongoException $e) { $this->ErrLog($e->getMessage()); return false; } return $result; } /** * 插入多行 * @param $collect 集合 * @param $fields * @param $values 键值对:array(0=>array(''=>'')) * @param bool $continueOnError 是否忽略插入错误,默认忽略 * @return bool */ public function InsMulit($collect, $fields, $values, $continueOnError = false) { if (!is_array($fields) || !is_array($values) || !$this->collected) return false; $id = array_search('id', $fields); #处理有id字段的情况 if ($id !== false && array_search('_id', $fields) === false) $fields[$id] = '_id'; $data = array(); $values = $this->ConvertEncode($values); if ($values) { foreach ($values as $v) { if (is_array($v)) { $v = array_combine($fields, $v); if ($v) $data[] = $v; } } } if (!$data) return false; $option['continueOnError'] = $continueOnError ? true : false; try { $result = $this->GetMonCollection($collect)->batchinsert($data, $option); $result = $result['err'] ? false : true; } catch (MongoException $e) { $this->ErrLog($e->getMessage()); return false; } return $result; } /** * 查询一个 * @param $collect * @param array $where * @param $field string * @return bool */ function FindOne($collect, $where = array(), $field) { if (!$this->collected) return false; $wheres = $this->GetWhere($where); if ($where && !$wheres) return false; if (is_string($field) && trim($field)) $field = trim($field); else return false; $result = $this->GetMonCollection($collect)->findOne($wheres, array($field)); if ($result) { $arr = get_object_vars($result['_id']); $result['_id'] = $arr['$id']; return $result[$field]; } return false; } /** * 查询一条 * @param $collect * @param array|string $where * @param array $fields * @param string $type * @return array|bool */ function FindRow($collect, $where = array(), $fields = array(), $type = 'assoc') { if (!$this->collected) return false; $wheres = $this->GetWhere($where); if ($where && !$wheres) return false; if ($fields && is_array($fields)) { #过滤fields $val = ''; for ($i = 0; $i < count($fields); $i++) { $val[] = 1; } $fields = array_combine($fields, $val); } else { $fields = array(); } $result = $this->GetMonCollection($collect)->findOne($wheres, $fields); if ($result) { if (in_array('_id', $fields)) { $arr = get_object_vars($result['_id']); $result['_id'] = $arr['$id']; } else { unset($result['_id']); } if (strtolower($type) == 'array') $result = array_values($result); return $result; } return false; } /** * 复合查询 todo 查询高级选项扩展 snapshot maxscan min max hint explain * <----------------------- * $gt:>|$gte:>=|$le:<|$lte:<=|$ne:!= * array('x'=>array('$gt'=>'20')) * * $or:$|$end:& * array('x'=>array('$in'=>array('1','2'))) * * $where:% * array('x'=>array('$where'=>function)) * * 正则表达式: * ? * * 数组: * $all:* * * 内嵌文档: * 单个条件:username.user username[user * 多个条件:$elemMatch * * 逻辑操作符: * not:! * or:$ * end:& * sort * array('x'=>0) * * limit|skip * $where = array('&|'=>array('she_hash' => '48b6c531ef2469469ede4ac21eebcf51', 'type' => 'doing')); * $field = array('time', '_id' => 0); * $res = $mongo->FindMix('sapilog', $where, $field,'1,2',array('time'=>'desc')); * -------------------------> * @param $collect |string * @param string $where |array array('>|x'=>'10','<=|x'=>'20','^|x'=>array(),'%|x'=>'fun') * @param array|string $fields |array|string 返回字段 默认为全部 字符串返回一个字段,键为数字则为返回该字段,键为字段,值为-1为不返回该字段 * @param string $limit |string skip,limit 0,10 如果没有 默认 skip为0 limit为当前变量 * @param string $sort |array array('x'=>'desc|asc') desc=>-1 asc=> * @param string $type | string 返回类型 默认为关联数组 assoc|array * @return bool */ public function FindMix($collect, $where = '', $fields = array(), $limit = '', $sort = '', $type = 'assoc') { if (!$this->collected) return false; $wheres = $this->GetWhere($where); if ($where && !$wheres) return false; if ($fields && is_array($fields)) { #过滤fields $val = ''; for ($i = 0; $i < count($fields); $i++) { $val[] = 1; } $fields = array_combine($fields, $val); } else { $fields = array(); } $limits = ''; $skip = ''; if (is_string($limit)) { #过滤limit $limit = explode(",", trim($limit)); if ($limit && is_numeric(implode('', $limit))) { if (count($limit) == 1) { $limits = $limit[0]; } else { $skip = $limit[0]; $limits = $limit[1]; } } } elseif (is_numeric($limit)) { $limits = trim($limit); } $sorts = ''; if (is_array($sort) && $sort) { #过滤sort foreach ($sort as $k => $v) { $k = trim($k); $v = strtoupper(trim($v)); if (in_array($v, array_keys($this->sort_map))) { $sorts[$k] = $this->sort_map[$v]; } } } $result = $this->GetMonCollection($collect)->find($wheres, $fields); if ($skip) $result = $result->skip($skip); if ($limits) $result = $result->limit($limits); if ($sorts) $result = $result->sort($sorts); if ($result) { $return = array(); foreach ($result as $v) { $return[] = $v; } foreach ($return as &$v) { if (in_array('_id', $fields)) { $arr = get_object_vars($v['_id']); $v['_id'] = $arr['$id']; } else { unset($v['_id']); } if (strtolower($type) == 'array') $v = array_values($v); } return $return; } return false; } /** * 修改记录 * $inc、$set、$unset 修改普通文档,如果有就修改,没有就条件加值创建,前者只支持数字类型,使用后者,$unset删除元素 * $push、$addToSet 添加数组元素,前者不去重,使用后者 * $pop、$pull 删除数组元素,前者删除前后,后者删除指定元素,使用后者 * * @param $collect * @param $where * @param $newdata |array * @param string $type 操作类型 upd修改 unset删除指定元素 arr修改数组元素 pull删除数组元素 * @param bool $upsert 是否创建 * @param int $return |1:返回bool,2:返回影响行数 * @return bool */ public function UpdMix($collect, $where, $newdata, $type = 'upd', $upsert = false, $return = 1) { if (!$this->collected || !is_array($newdata)) return false; $wheres = $this->GetWhere($where); if (!$wheres) { $this->ErrLog('where is error'); return false; } $newdata = $this->ConvertEncode($newdata); $type = strtolower(trim($type)); $types = array('upd' => '$set', 'unset' => '$unset', 'arr' => '$addToSet', 'pull' => '$pull'); if (isset($types[$type])) { $option = array(); if ($type == 'upd') $option = array('multiple' => true); if (in_array($type, array('upd', 'arr')) && $upsert) $option['upsert'] = true; $newdata = array($types[$type] => $newdata); } else { return false; } try { $result = $this->GetMonCollection($collect)->update($wheres, $newdata, $option); $result = $return == 1 ? ($result['err'] ? false : true) : $result['n']; } catch (MongoConnectionException $e) { $this->ErrLog($e->getMessage()); return false; } return $result; } #todo EXPLAIN 函数 /** * 对集合执行命令 * @param $data * @return bool */ public function RunCommand($data) { if (is_array($data) && $data && $this->collected) { $result = $this->db->command($data); if (isset($result['values'])) return $result['values']; else $this->ErrLog("command error,info:" . $result['errmsg'] . ",bad_cmd:" . json_encode($result['bad cmd'])); } return false; } /** * todo 聚合 * */ public function Group() { } public function Count($collect, $where = array()) { if (!$this->collected) return false; $wheres = $this->GetWhere($where); if ($where && !$wheres) return false; return $this->GetMonCollection($collect)->count($wheres); } /** * 返回指定键的唯一值列表 * @param $collect * @param $key * @param array $where 额外查询条件 * @return bool */ public function Distinct($collect, $key, $where = array()) { if (!$this->collected) return false; $wheres = $this->GetWhere($where); if ($where && !$wheres) return false; try { $result = $this->GetMonCollection($collect)->distinct($key, $wheres); } catch (MongoException $e) { $this->ErrLog($e->getMessage()); return false; } return $result; } /** * 删除集合中的记录 * @param $collect * @param $where * @param int $return 1:返回bool,2:返回影响行数 * @return bool */ public function RemoveColl($collect, $where, $return = 1) { if (!$this->collected) return false; $wheres = $this->GetWhere($where); if (!$wheres) { $this->ErrLog('where is error'); return false; } try { $result = $this->GetMonCollection($collect)->remove($wheres); $result = $return == 1 ? ($result['err'] ? false : true) : $result['n']; } catch (MongoConnectionException $e) { $this->ErrLog($e->getMessage()); return false; } return $result; } /** * mongo 错误日志函数 * * @param $msg * @param int $lever * */ private function ErrLog($msg, $lever = 2) { global $__CFG; $trace = debug_backtrace(); $error_log = ''; $date = date("Ymd", time()); $line = isset($trace[$lever]['line']) ? trim($trace[$lever]['line']) : ''; $file = isset($trace[$lever]['file']) ? trim($trace[$lever]['file']) : ''; $object = isset($trace[$lever]['object']) ? get_class($trace[$lever]['object']) : ''; $args = isset($trace[$lever]['args']) ? json_encode($trace[$lever]['args']) : ''; $error_log .= "line {$line} " . ($object ? 'of ' . $object : '') . "(in {$file})\n"; $error_log .= $args ? "args:{$args}\n" : ''; $error_log .= "msg:{$msg}"; if (isset($__CFG['com']['id']) && $__CFG['com']['id']) { $com_id = $__CFG['com']['id']; } else { $com_id = 'common'; } $log_dir = $this->config['logpath'] ? $this->config['logpath'] : __ROOT__ . "data/nginx_error_log/{$com_id}/{$date}/mongo.nginx_error_log"; error_log("Date:" . date("Y-m-d H:i:s", $date) . "\nstamp:{$date}\ntrace:{$error_log}\n\n", 3, $log_dir); if (isset($__CFG['currUser']) && $__CFG['currUser'] == 'root' && isset($__CFG['daemon']['user'])) { $paths = explode("nginx_error_log/", $log_dir); $pathc = explode("/", $paths[1]); $pathd = $paths[0] . "nginx_error_log"; foreach ($pathc as $v) { $pathd .= "/" . $v; chgrp($pathd, $__CFG['daemon']['user']); chown($pathd, $__CFG['daemon']['user']); } } } }
按需网站开发可以根据自己的需求进行定制,网站设计、成都做网站构思过程中功能建设理应排到主要部位公司网站设计、成都做网站的运用实际效果公司网站制作网站建立与制做的实际意义