diff --git a/lib/base/dao/dao.class.php b/lib/base/dao/dao.class.php
new file mode 100644
index 0000000000..b775563773
--- /dev/null
+++ b/lib/base/dao/dao.class.php
@@ -0,0 +1,2002 @@
+table的别名。
+ * The alias of $this->table.
+ *
+ * @var string
+ * @access public
+ */
+ public $alias;
+
+ /**
+ * 查询的字段。
+ * The fields will be returned.
+ *
+ * @var string
+ * @access public
+ */
+ public $fields;
+
+ /**
+ * 查询模式,raw模式用于正常的select update等sql拼接操作,magic模式用于findByXXX等魔术方法。
+ * The query mode, raw or magic.
+ *
+ * This var is used to diff dao::from() with sql::from().
+ *
+ * @var string
+ * @access public
+ */
+ public $mode;
+
+ /**
+ * 执行方式:insert, select, update, delete, replace。
+ * The query method: insert, select, update, delete, replace.
+ *
+ * @var string
+ * @access public
+ */
+ public $method;
+
+ /**
+ * 是否自动增加lang条件。
+ * If auto add lang statement.
+ *
+ * @var bool
+ * @access public
+ */
+ public $autoLang;
+
+ /**
+ * 需要修复表的错误代码
+ * The sql code of need repair table.
+ *
+ * @var string
+ * @access public
+ */
+ public $repairCode = '|1034|1035|1194|1195|1459|';
+
+ /**
+ * 执行的请求,所有的查询都保存在该数组。
+ * The queries executed. Every query will be saved in this array.
+ *
+ * @var array
+ * @access public
+ */
+ static public $querys = array();
+
+ /**
+ * 存放错误的数组。
+ * The errors.
+ *
+ * @var array
+ * @access public
+ */
+ static public $errors = array();
+
+ /**
+ * 缓存。
+ * The cache.
+ *
+ * @var array
+ * @access public
+ */
+ static public $cache = array();
+
+ /**
+ * 构造方法。
+ * The construct method.
+ *
+ * @access public
+ * @return void
+ */
+ public function __construct()
+ {
+ global $app, $config, $lang, $dbh, $slaveDBH;
+ $this->app = $app;
+ $this->config = $config;
+ $this->lang = $lang;
+ $this->dbh = $dbh;
+ $this->slaveDBH = $slaveDBH ? $slaveDBH : false;
+
+ $this->reset();
+ }
+
+ /**
+ * 设置$table属性。
+ * Set the $table property.
+ *
+ * @param string $table
+ * @access public
+ * @return void
+ */
+ public function setTable($table)
+ {
+ $this->table = $table;
+ }
+
+ /**
+ * 设置$alias属性。
+ * Set the $alias property.
+ *
+ * @param string $alias
+ * @access public
+ * @return void
+ */
+ public function setAlias($alias)
+ {
+ $this->alias = $alias;
+ }
+
+ /**
+ * 设置$fields属性。
+ * Set the $fields property.
+ *
+ * @param string $fields
+ * @access public
+ * @return void
+ */
+ public function setFields($fields)
+ {
+ $this->fields = $fields;
+ }
+
+ /**
+ * 设置autoLang项。
+ * Set autoLang item.
+ *
+ * @param bool $autoLang
+ * @access public
+ * @return void
+ */
+ public function setAutoLang($autoLang)
+ {
+ $this->autoLang = $autoLang;
+ return $this;
+ }
+
+ /**
+ * 重置属性。
+ * Reset the vars.
+ *
+ * @access public
+ * @return void
+ */
+ public function reset()
+ {
+ $this->setFields('');
+ $this->setTable('');
+ $this->setAlias('');
+ $this->setMode('');
+ $this->setMethod('');
+ $this->setAutoLang(isset($this->config->framework->autoLang) and $this->config->framework->autoLang);
+ }
+
+ //-----根据请求的方式,调用sql类相应的方法(Call according method of sql class by query method. -----//
+
+ /**
+ * 设置请求模式。像findByxxx之类的方法,使用的是magic模式;其他方法使用的是raw模式。
+ * Set the query mode. If the method if like findByxxx, the mode is magic. Else, the mode is raw.
+ *
+ * @param string $mode magic|raw
+ * @access public
+ * @return void
+ */
+ public function setMode($mode = '')
+ {
+ $this->mode = $mode;
+ }
+
+ /**
+ * 设置请求方法:select|update|insert|delete|replace 。
+ * Set the query method: select|update|insert|delete|replace
+ *
+ * @param string $method
+ * @access public
+ * @return void
+ */
+ public function setMethod($method = '')
+ {
+ $this->method = $method;
+ }
+
+ /**
+ * 开始事务。
+ * Begin Transaction
+ *
+ * @access public
+ * @return void
+ */
+ public function begin()
+ {
+ $this->dbh->beginTransaction();
+ }
+
+ /**
+ * 事务回滚。
+ * Roll back
+ *
+ * @access public
+ * @return void
+ */
+ public function rollBack()
+ {
+ $this->dbh->rollBack();
+ }
+
+ /**
+ * 提交事务。
+ * Commits a transaction.
+ *
+ * @access public
+ * @return void
+ */
+ public function commit()
+ {
+ $this->dbh->commit();
+ }
+
+ /**
+ * select方法,调用sql::select()。
+ * The select method, call sql::select().
+ *
+ * @param string $fields
+ * @access public
+ * @return object the dao object self.
+ */
+ public function select($fields = '*')
+ {
+ $this->setMode('raw');
+ $this->setMethod('select');
+ $this->sqlobj = sql::select($fields);
+ return $this;
+ }
+
+ /**
+ * 获取查询记录条数。
+ * The count method, call sql::select() and from().
+ * use as $this->dao->select()->from(TABLE_BUG)->where()->count();
+ *
+ * @param string $distinctField
+ * @access public
+ * @return void
+ */
+ public function count($distinctField = '')
+ {
+ /* 获得SELECT,FROM的位置,使用count(*)替换其字段。 */
+ /* Get the SELECT, FROM position, thus get the fields, replace it by count(*). */
+ $sql = $this->get();
+ $selectPOS = strpos($sql, 'SELECT') + strlen('SELECT');
+ $fromPOS = strpos($sql, 'FROM');
+ $fields = substr($sql, $selectPOS, $fromPOS - $selectPOS );
+ $countField = $distinctField ? 'distinct ' . $distinctField : '*';
+ $sql = str_replace($fields, " COUNT($countField) AS recTotal ", substr($sql, 0, $fromPOS)) . substr($sql, $fromPOS);
+
+ /*
+ * 去掉SQL语句中order和limit之后的部分。
+ * Remove the part after order and limit.
+ **/
+ $subLength = strlen($sql);
+ $orderPOS = strripos($sql, 'order by');
+ $limitPOS = strripos($sql, 'limit');
+ if($limitPOS) $subLength = $limitPOS;
+ if($orderPOS) $subLength = $orderPOS;
+ $sql = substr($sql, 0, $subLength);
+ self::$querys[] = $sql;
+
+ /*
+ * 获取记录数。
+ * Get the records count.
+ **/
+ try
+ {
+ $row = $this->dbh->query($sql)->fetch(PDO::FETCH_OBJ);
+ }
+ catch (PDOException $e)
+ {
+ $this->sqlError($e);
+ }
+
+ return $row->recTotal;
+ }
+
+ /**
+ * update方法,调用sql::update()。
+ * The update method, call sql::update().
+ *
+ * @param string $table
+ * @access public
+ * @return object the dao object self.
+ */
+ public function update($table)
+ {
+ $this->setMode('raw');
+ $this->setMethod('update');
+ $this->sqlobj = sql::update($table);
+ $this->setTable($table);
+ return $this;
+ }
+
+ /**
+ * delete方法,调用sql::delete()。
+ * The delete method, call sql::delete().
+ *
+ * @access public
+ * @return object the dao object self.
+ */
+ public function delete()
+ {
+ $this->setMode('raw');
+ $this->setMethod('delete');
+ $this->sqlobj = sql::delete();
+ return $this;
+ }
+
+ /**
+ * insert方法,调用sql::insert()。
+ * The insert method, call sql::insert().
+ *
+ * @param string $table
+ * @access public
+ * @return object the dao object self.
+ */
+ public function insert($table)
+ {
+ $this->setMode('raw');
+ $this->setMethod('insert');
+ $this->sqlobj = sql::insert($table);
+ $this->setTable($table);
+ return $this;
+ }
+
+ /**
+ * replace方法,调用sql::replace()。
+ * The replace method, call sql::replace().
+ *
+ * @param string $table
+ * @access public
+ * @return object the dao object self.
+ */
+ public function replace($table)
+ {
+ $this->setMode('raw');
+ $this->setMethod('replace');
+ $this->sqlobj = sql::replace($table);
+ $this->setTable($table);
+ return $this;
+ }
+
+ /**
+ * 设置要操作的表。
+ * Set the from table.
+ *
+ * @param string $table
+ * @access public
+ * @return object the dao object self.
+ */
+ public function from($table)
+ {
+ $this->setTable($table);
+ if($this->mode == 'raw') $this->sqlobj->from($table);
+ return $this;
+ }
+
+ /**
+ * 设置字段。
+ * Set the fields.
+ *
+ * @param string $fields
+ * @access public
+ * @return object the dao object self.
+ */
+ public function fields($fields)
+ {
+ $this->setFields($fields);
+ return $this;
+ }
+
+ /**
+ * 表别名,相当于sql里的AS。(as是php的关键词,使用alias代替)
+ * Alias a table, equal the AS keyword. (Don't use AS, because it's a php keyword.)
+ *
+ * @param string $alias
+ * @access public
+ * @return object the dao object self.
+ */
+ public function alias($alias)
+ {
+ if(empty($this->alias)) $this->setAlias($alias);
+ $this->sqlobj->alias($alias);
+ return $this;
+ }
+
+ /**
+ * 设置需要更新或插入的数据。
+ * Set the data to update or insert.
+ *
+ * @param object $data the data object or array
+ * @access public
+ * @return object the dao object self.
+ */
+ public function data($data, $skipFields = '')
+ {
+ if(!is_object($data)) $data = (object)$data;
+ if($this->autoLang and !isset($data->lang))
+ {
+ $data->lang = $this->app->getClientLang();
+ if(defined('RUN_MODE') and RUN_MODE == 'front' and !empty($this->app->config->cn2tw)) $data->lang = str_replace('zh-tw', 'zh-cn', $data->lang);
+ }
+
+ $this->sqlobj->data($data, $skipFields);
+ return $this;
+ }
+
+ //-------------------- sql相关的方法(The sql related method) --------------------//
+
+ /**
+ * 获取sql字符串。
+ * Get the sql string.
+ *
+ * @access public
+ * @return string the sql string after process.
+ */
+ public function get()
+ {
+ return $this->processKeywords($this->processSQL());
+ }
+
+ /**
+ * 打印sql字符串。
+ * Print the sql string.
+ *
+ * @access public
+ * @return void
+ */
+ public function printSQL()
+ {
+ echo $this->processSQL();
+ }
+
+ /**
+ * 查看SQL索引。
+ * Explain sql.
+ *
+ * @param string $sql
+ * @access public
+ * @return void
+ */
+ public function explain($sql = '')
+ {
+ $sql = empty($sql) ? $this->processSQL() : $sql;
+ $result = $this->dbh->query('explain ' . $sql)->fetch();
+ a($result);
+ }
+
+ /**
+ * 处理sql语句,替换表和字段。
+ * Process the sql, replace the table, fields.
+ *
+ * @access public
+ * @return string the sql string after process.
+ */
+ public function processSQL()
+ {
+ $sql = $this->sqlobj->get();
+
+ /**
+ * 如果是magic模式,处理表和字段。
+ * If the mode is magic, process the $fields and $table.
+ **/
+ if($this->mode == 'magic')
+ {
+ if($this->fields == '') $this->fields = '*';
+ if($this->table == '') $this->app->triggerError('Must set the table name', __FILE__, __LINE__, $exit = true);
+ $sql = sprintf($this->sqlobj->get(), $this->fields, $this->table);
+ }
+
+ /* If the method if select, update or delete, set the lang condition. */
+ if($this->autoLang and $this->table != '' and $this->method != 'insert' and $this->method != 'replace')
+ {
+ $lang = $this->app->getClientLang();
+
+ /* Get the position to insert lang = ?. */
+ $wherePOS = strrpos($sql, DAO::WHERE); // The position of WHERE keyword.
+ $groupPOS = strrpos($sql, DAO::GROUPBY); // The position of GROUP BY keyword.
+ $havingPOS = strrpos($sql, DAO::HAVING); // The position of HAVING keyword.
+ $orderPOS = strrpos($sql, DAO::ORDERBY); // The position of ORDERBY keyword.
+ $limitPOS = strrpos($sql, DAO::LIMIT); // The position of LIMIT keyword.
+ $splitPOS = $orderPOS ? $orderPOS : $limitPOS; // If $orderPOS, use it instead of $limitPOS.
+ $splitPOS = $havingPOS? $havingPOS: $splitPOS; // If $havingPOS, use it instead of $orderPOS.
+ $splitPOS = $groupPOS ? $groupPOS : $splitPOS; // If $groupPOS, use it instead of $havingPOS.
+
+ /* Set the conditon to be appened. */
+ $tableName = !empty($this->alias) ? $this->alias : $this->table;
+
+ if(!empty($this->app->config->cn2tw)) $lang = str_replace('zh-tw', 'zh-cn', $lang);
+
+ $langCondition = " $tableName.lang in('{$lang}', 'all') ";
+
+ /* If $spliPOS > 0, split the sql at $splitPOS. */
+ if($splitPOS)
+ {
+ $firstPart = substr($sql, 0, $splitPOS);
+ $lastPart = substr($sql, $splitPOS);
+ if($wherePOS)
+ {
+ $sql = $firstPart . " AND $langCondition " . $lastPart;
+ }
+ else
+ {
+ $sql = $firstPart . " WHERE $langCondition " . $lastPart;
+ }
+ }
+ else
+ {
+ $sql .= $wherePOS ? " AND $langCondition" : " WHERE $langCondition";
+ }
+ }
+
+ self::$querys[] = $this->processKeywords($sql);
+ return $sql;
+ }
+
+ /**
+ * 替换sql常量关键字。
+ * Process the sql keywords, replace the constants to normal.
+ *
+ * @param string $sql
+ * @access public
+ * @return string the sql string.
+ */
+ public function processKeywords($sql)
+ {
+ return str_replace(array(DAO::WHERE, DAO::GROUPBY, DAO::HAVING, DAO::ORDERBY, DAO::LIMIT), array('WHERE', 'GROUP BY', 'HAVING', 'ORDER BY', 'LIMIT'), $sql);
+ }
+
+ //-------------------- 查询相关方法(Query related methods) --------------------//
+
+ /**
+ * 设置$dbh,数据库连接句柄。
+ * Set the dbh.
+ *
+ * You can use like this: $this->dao->dbh($dbh), thus you can handle two database.
+ *
+ * @param object $dbh
+ * @access public
+ * @return object the dao object self.
+ */
+ public function dbh($dbh)
+ {
+ $this->dbh = $dbh;
+ return $this;
+ }
+
+ /**
+ * 执行SQL语句,返回PDOStatement结果集。
+ * Query the sql, return the statement object.
+ *
+ * @access public
+ * @return object the PDOStatement object.
+ */
+ public function query($sql = '')
+ {
+ /* 如果有错误,返回一个空的PDOStatement对象,确保后续方法能够执行。*/
+ /* If any error, return an empty statement object to make sure the remain method to execute. */
+ if(!empty(dao::$errors)) return new PDOStatement();
+
+ if($sql) $this->sqlobj->sql = $sql;
+ $sql = $this->processSQL();
+ $key = md5($sql);
+
+ try
+ {
+ $method = $this->method;
+ $this->reset();
+
+ if($this->slaveDBH and $method == 'select')
+ {
+ if(isset(dao::$cache[$key])) return dao::$cache[$key];
+ $result = $this->slaveDBH->query($sql);
+ dao::$cache[$key] = $result;
+ return $result;
+ }
+ else
+ {
+ if($this->method == 'select')
+ {
+ if(isset(dao::$cache[$key])) return dao::$cache[$key];
+ $result = $this->slaveDBH->query($sql);
+ dao::$cache[$key] = $result;
+ return $result;
+ }
+
+ return $this->dbh->query($sql);
+ }
+ }
+ catch (PDOException $e)
+ {
+ $this->sqlError($e);
+ }
+ }
+
+ /**
+ * 将记录进行分页,自动设置limit语句。
+ * Page the records, set the limit part auto.
+ *
+ * @param object $pager
+ * @access public
+ * @return object the dao object self.
+ */
+ public function page($pager, $distinctField = '')
+ {
+ if(!is_object($pager)) return $this;
+
+ /*
+ * 如果$pager的总记录为0,需要计算总结果数。
+ * If the record total is 0, compute it.
+ **/
+ if($pager->recTotal == 0)
+ {
+ $recTotal = $this->count($distinctField);
+ $pager->setRecTotal($recTotal);
+ $pager->setPageTotal();
+ }
+ $this->sqlobj->limit($pager->limit());
+ return $this;
+ }
+
+ /**
+ * 执行SQL。query()会返回stmt对象,该方法只返回更改或删除的记录数。
+ * Execute the sql. It's different with query(), which return the stmt object. But this not.
+ *
+ * @param string $sql
+ * @access public
+ * @return int the modified or deleted records. 更改或删除的记录数。
+ */
+ public function exec($sql = '')
+ {
+ if(!empty(dao::$errors)) return new PDOStatement(); // If any error, return an empty statement object to make sure the remain method to execute.
+
+ if($sql) $this->sqlobj->sql = $sql;
+ $sql = $this->processSQL();
+
+ try
+ {
+ $this->reset();
+ return $this->dbh->exec($sql);
+ }
+ catch (PDOException $e)
+ {
+ $this->sqlError($e);
+ }
+ }
+
+ //-------------------- Fetch相关方法(Fetch related methods) -------------------//
+
+ /**
+ * 获取一个记录。
+ * Fetch one record.
+ *
+ * @param string $field 如果已经设置获取的字段,则只返回这个字段的值,否则返回这个记录。
+ * if the field is set, only return the value of this field, else return this record
+ * @access public
+ * @return object|mixed
+ */
+ public function fetch($field = '')
+ {
+ if(empty($field)) return $this->query()->fetch();
+ $this->setFields($field);
+ $result = $this->query()->fetch(PDO::FETCH_OBJ);
+ if($result) return $result->$field;
+ }
+
+ /**
+ * 获取所有记录。
+ * Fetch all records.
+ *
+ * @param string $keyField 返回以该字段做键的记录
+ * the key field, thus the return records is keyed by this field
+ * @access public
+ * @return array the records
+ */
+ public function fetchAll($keyField = '')
+ {
+ $stmt = $this->query();
+ if(empty($keyField)) return $stmt->fetchAll();
+ $rows = array();
+ while($row = $stmt->fetch()) $rows[$row->$keyField] = $row;
+ return $rows;
+ }
+
+ /**
+ * 获取所有记录并将按照字段分组。
+ * Fetch all records and group them by one field.
+ *
+ * @param string $groupField 分组的字段 the field to group by
+ * @param string $keyField 键字段 the field of key
+ * @access public
+ * @return array the records.
+ */
+ public function fetchGroup($groupField, $keyField = '')
+ {
+ $stmt = $this->query();
+ $rows = array();
+ while($row = $stmt->fetch())
+ {
+ empty($keyField) ? $rows[$row->$groupField][] = $row : $rows[$row->$groupField][$row->$keyField] = $row;
+ }
+ return $rows;
+ }
+
+ /**
+ * 获取的记录是以关联数组的形式
+ * Fetch array like key=>value.
+ *
+ * 如果没有设置参数,用首末两键作为参数。
+ * If the keyFiled and valueField not set, use the first and last in the record.
+ *
+ * @param string $keyField
+ * @param string $valueField
+ * @access public
+ * @return array
+ */
+ public function fetchPairs($keyField = '', $valueField = '')
+ {
+ $keyField = trim($keyField, '`');
+ $valueField = trim($valueField, '`');
+
+ $pairs = array();
+ $ready = false;
+ $stmt = $this->query();
+ while($row = $stmt->fetch(PDO::FETCH_ASSOC))
+ {
+ if(!$ready)
+ {
+ if(empty($keyField)) $keyField = key($row);
+ if(empty($valueField))
+ {
+ end($row);
+ $valueField = key($row);
+ }
+ $ready = true;
+ }
+
+ $pairs[$row[$keyField]] = $row[$valueField];
+ }
+ return $pairs;
+ }
+
+ /**
+ * 返回最后插入的ID。
+ * Return the last insert ID.
+ *
+ * @access public
+ * @return int
+ */
+ public function lastInsertID()
+ {
+ return $this->dbh->lastInsertID();
+ }
+
+ //-------------------- 魔术方法(Magic methods) --------------------//
+
+ /**
+ * 解析dao的方法名,处理魔术方法。
+ * Use it to do some convenient queries.
+ *
+ * @param string $funcName the function name to be called
+ * @param array $funcArgs the params
+ * @access public
+ * @return object the dao object self.
+ */
+ public function __call($funcName, $funcArgs)
+ {
+ $funcName = strtolower($funcName);
+
+ /*
+ * 如果是findByxxx,转换为where条件语句。
+ * findByxxx, xxx as will be in the where.
+ **/
+ if(strpos($funcName, 'findby') !== false)
+ {
+ $this->setMode('magic');
+ $field = str_replace('findby', '', $funcName);
+ if(count($funcArgs) == 1)
+ {
+ $operator = '=';
+ $value = $funcArgs[0];
+ }
+ else
+ {
+ $operator = $funcArgs[0];
+ $value = $funcArgs[1];
+ }
+ $this->sqlobj = sql::select('%s')->from('%s')->where($field, $operator, $value);
+ return $this;
+ }
+ /*
+ * 获取指定个数的记录:fetch10 获取10条记录。
+ * Fetch10.
+ **/
+ elseif(strpos($funcName, 'fetch') !== false)
+ {
+ $max = str_replace('fetch', '', $funcName);
+ $stmt = $this->query();
+
+ $rows = array();
+ $key = isset($funcArgs[0]) ? $funcArgs[0] : '';
+ $i = 0;
+ while($row = $stmt->fetch())
+ {
+ $key ? $rows[$row->$key] = $row : $rows[] = $row;
+ $i ++;
+ if($i == $max) break;
+ }
+ return $rows;
+ }
+ /*
+ * 其他的方法,转到sqlobj对象执行。
+ * Others, call the method in sql class.
+ **/
+ else
+ {
+ /*
+ * 使用$arg0, $arg1... 生成调用的参数。
+ * Create the max counts of sql class methods, and then create $arg0, $arg1...
+ **/
+ for($i = 0; $i < SQL::MAX_ARGS; $i ++)
+ {
+ ${"arg$i"} = isset($funcArgs[$i]) ? $funcArgs[$i] : null;
+ }
+ $this->sqlobj->$funcName($arg0, $arg1, $arg2);
+ return $this;
+ }
+ }
+
+ //-------------------- 条件检查( Data Checking)--------------------//
+
+ /**
+ * 检查字段是否满足条件。
+ * Check a filed is satisfied with the check rule.
+ *
+ * @param string $fieldName the field to check
+ * @param string $funcName the check rule
+ * @param string $condition the condition
+ * @access public
+ * @return object the dao object self.
+ */
+ public function check($fieldName, $funcName, $condition = '')
+ {
+ /*
+ * 如果没数据中没有该字段,直接返回。
+ * If no this field in the data, return.
+ **/
+ if(!isset($this->sqlobj->data->$fieldName)) return $this;
+
+ /* 设置字段值。 */
+ /* Set the field label and value. */
+ global $lang, $config, $app;
+ if(isset($config->db->prefix))
+ {
+ $table = strtolower(str_replace(array($config->db->prefix, '`'), '', $this->table));
+ }
+ elseif(strpos($this->table, '_') !== false)
+ {
+ $table = strtolower(substr($this->table, strpos($this->table, '_') + 1));
+ $table = str_replace('`', '', $table);
+ }
+ else
+ {
+ $table = strtolower($this->table);
+ }
+ $fieldLabel = isset($lang->$table->$fieldName) ? $lang->$table->$fieldName : $fieldName;
+ $value = isset($this->sqlobj->data->$fieldName) ? $this->sqlobj->data->$fieldName : null;
+
+ /*
+ * 检查唯一性。
+ * Check unique.
+ **/
+ if($funcName == 'unique')
+ {
+ $args = func_get_args();
+ $sql = "SELECT COUNT(*) AS count FROM $this->table WHERE `$fieldName` = " . $this->sqlobj->quote($value);
+ if($condition) $sql .= ' AND ' . $condition;
+ try
+ {
+ $row = $this->dbh->query($sql)->fetch();
+ if($row->count != 0) $this->logError($funcName, $fieldName, $fieldLabel, array($value));
+ }
+ catch (PDOException $e)
+ {
+ $this->sqlError($e);
+ }
+ }
+ else
+ {
+ /*
+ * 创建参数。
+ * Create the params.
+ **/
+ $funcArgs = func_get_args();
+ unset($funcArgs[0]);
+ unset($funcArgs[1]);
+
+ for($i = 0; $i < VALIDATER::MAX_ARGS; $i ++)
+ {
+ ${"arg$i"} = isset($funcArgs[$i + 2]) ? $funcArgs[$i + 2] : null;
+ }
+ $checkFunc = 'check' . $funcName;
+ if(validater::$checkFunc($value, $arg0, $arg1, $arg2) === false)
+ {
+ $this->logError($funcName, $fieldName, $fieldLabel, $funcArgs);
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * 检查一个字段是否满足条件。
+ * Check a field, if satisfied with the condition.
+ *
+ * @param string $condition
+ * @param string $fieldName
+ * @param string $funcName
+ * @access public
+ * @return object the dao object self.
+ */
+ public function checkIF($condition, $fieldName, $funcName)
+ {
+ if(!$condition) return $this;
+ $funcArgs = func_get_args();
+ for($i = 0; $i < VALIDATER::MAX_ARGS; $i ++)
+ {
+ ${"arg$i"} = isset($funcArgs[$i + 3]) ? $funcArgs[$i + 3] : null;
+ }
+ $this->check($fieldName, $funcName, $arg0, $arg1, $arg2);
+ return $this;
+ }
+
+ /**
+ * 批量检查字段。
+ * Batch check some fileds.
+ *
+ * @param string $fields the fields to check, join with ,
+ * @param string $funcName
+ * @access public
+ * @return object the dao object self.
+ */
+ public function batchCheck($fields, $funcName)
+ {
+ $fields = explode(',', str_replace(' ', '', $fields));
+ $funcArgs = func_get_args();
+ for($i = 0; $i < VALIDATER::MAX_ARGS; $i ++)
+ {
+ ${"arg$i"} = isset($funcArgs[$i + 2]) ? $funcArgs[$i + 2] : null;
+ }
+ foreach($fields as $fieldName) $this->check($fieldName, $funcName, $arg0, $arg1, $arg2);
+ return $this;
+ }
+
+ /**
+ * 批量检查字段是否满足条件。
+ * Batch check fields on the condition is true.
+ *
+ * @param string $condition
+ * @param string $fields
+ * @param string $funcName
+ * @access public
+ * @return object the dao object self.
+ */
+ public function batchCheckIF($condition, $fields, $funcName)
+ {
+ if(!$condition) return $this;
+ $fields = explode(',', str_replace(' ', '', $fields));
+ $funcArgs = func_get_args();
+ for($i = 0; $i < VALIDATER::MAX_ARGS; $i ++)
+ {
+ ${"arg$i"} = isset($funcArgs[$i + 2]) ? $funcArgs[$i + 2] : null;
+ }
+ foreach($fields as $fieldName) $this->check($fieldName, $funcName, $arg0, $arg1, $arg2);
+ return $this;
+ }
+
+ /**
+ * 根据数据库结构检查字段。
+ * Check the fields according the the database schema.
+ *
+ * @param string $skipFields fields to skip checking
+ * @access public
+ * @return object the dao object self.
+ */
+ public function autoCheck($skipFields = '')
+ {
+ $fields = $this->getFieldsType();
+ $skipFields = ",$skipFields,";
+
+ foreach($fields as $fieldName => $validater)
+ {
+ if(strpos($skipFields, $fieldName) !== false) continue; // skip it.
+ if(!isset($this->sqlobj->data->$fieldName)) continue;
+ if($validater['rule'] == 'skip') continue;
+ $options = array();
+ if(isset($validater['options'])) $options = array_values($validater['options']);
+ for($i = 0; $i < VALIDATER::MAX_ARGS; $i ++)
+ {
+ ${"arg$i"} = isset($options[$i]) ? $options[$i] : null;
+ }
+ $this->check($fieldName, $validater['rule'], $arg0, $arg1, $arg2);
+ }
+ return $this;
+ }
+
+ /**
+ * 记录错误到日志。
+ * Log the error.
+ *
+ * module/common/lang中定义了错误提示信息。
+ * For the error notice, see module/common/lang.
+ *
+ * @param string $checkType the check rule
+ * @param string $fieldName the field name
+ * @param string $fieldLabel the field label
+ * @param array $funcArgs the args
+ * @access public
+ * @return void
+ */
+ public function logError($checkType, $fieldName, $fieldLabel, $funcArgs = array())
+ {
+ global $lang;
+ $error = $lang->error->$checkType;
+ $replaces = array_merge(array($fieldLabel), $funcArgs); // the replace values.
+
+ /*
+ * 如果$error错误信息是一个字符串,进行替换。
+ * Just a string, cycle the $replaces.
+ **/
+ if(!is_array($error))
+ {
+ foreach($replaces as $replace)
+ {
+ $pos = strpos($error, '%s');
+ if($pos === false) break;
+ $error = substr($error, 0, $pos) . $replace . substr($error, $pos + 2);
+ }
+ }
+ /*
+ * 如果error错误信息是一个数组,选择一个%s满足替换个数的进行替换。
+ * If the error define is an array, select the one which %s counts match the $replaces.
+ **/
+ else
+ {
+ /*
+ * 去掉空值项。
+ * Remove the empty items.
+ **/
+ foreach($replaces as $key => $value) if(is_null($value)) unset($replaces[$key]);
+ $replacesCount = count($replaces);
+ foreach($error as $errorString)
+ {
+ if(substr_count($errorString, '%s') == $replacesCount)
+ {
+ $error = vsprintf($errorString, $replaces);
+ }
+ }
+ }
+ dao::$errors[$fieldName][] = $error;
+ }
+
+ /**
+ * 判断是否有错误。
+ * Judge any error or not.
+ *
+ * @access public
+ * @return bool
+ */
+ public static function isError()
+ {
+ return !empty(dao::$errors);
+ }
+
+ /**
+ * 获取错误。
+ * Get the errors.
+ *
+ * @access public
+ * @return array
+ */
+ public static function getError($join = false)
+ {
+ $errors = dao::$errors;
+ dao::$errors = array(); // 清除dao的错误信息(Must clear errors)
+
+ if(!$join) return $errors;
+
+ if(is_array($errors))
+ {
+ $message = '';
+ foreach($errors as $item)
+ {
+ is_array($item) ? $message .= join('\n', $item) . '\n' : $message .= $item . '\n';
+ }
+ return $message;
+ }
+ }
+
+ /**
+ * 获取表的字段类型。
+ * Get the defination of fields of the table.
+ *
+ * @access public
+ * @return array
+ */
+ public function getFieldsType()
+ {
+ try
+ {
+ $this->dbh->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER);
+ $sql = "DESC $this->table";
+ $rawFields = $this->dbh->query($sql)->fetchAll();
+ $this->dbh->setAttribute(PDO::ATTR_CASE, PDO::CASE_NATURAL);
+ }
+ catch (PDOException $e)
+ {
+ $this->sqlError($e);
+ }
+
+ foreach($rawFields as $rawField)
+ {
+ $firstPOS = strpos($rawField->type, '(');
+ $type = substr($rawField->type, 0, $firstPOS > 0 ? $firstPOS : strlen($rawField->type));
+ $type = str_replace(array('big', 'small', 'medium', 'tiny', 'var'), '', $type);
+ $field = array();
+
+ if($type == 'enum' or $type == 'set')
+ {
+ $rangeBegin = $firstPOS + 2; // 移除开始的引用符 Remove the first quote.
+ $rangeEnd = strrpos($rawField->type, ')') - 1; // 移除结束的引用符 Remove the last quote.
+ $range = substr($rawField->type, $rangeBegin, $rangeEnd - $rangeBegin);
+ $field['rule'] = 'reg';
+ $field['options']['reg'] = '/' . str_replace("','", '|', $range) . '/';
+ }
+ elseif($type == 'char')
+ {
+ $begin = $firstPOS + 1;
+ $end = strpos($rawField->type, ')', $begin);
+ $length = substr($rawField->type, $begin, $end - $begin);
+ $field['rule'] = 'length';
+ $field['options']['max'] = $length;
+ $field['options']['min'] = 0;
+ }
+ elseif($type == 'int')
+ {
+ $field['rule'] = 'int';
+ }
+ elseif($type == 'float' or $type == 'double')
+ {
+ $field['rule'] = 'float';
+ }
+ elseif($type == 'date')
+ {
+ $field['rule'] = 'date';
+ }
+ else
+ {
+ $field['rule'] = 'skip';
+ }
+ $fields[$rawField->field] = $field;
+ }
+ return $fields;
+ }
+
+ /**
+ * Process SQL error by code.
+ *
+ * @param object $exception
+ * @access public
+ * @return void
+ */
+ public function sqlError($exception)
+ {
+ $errorInfo = $exception->errorInfo;
+ $errorCode = $errorInfo[1];
+ $errorMsg = $errorInfo[2];
+ $message = $exception->getMessage();
+ if(strpos($this->repairCode, "|$errorCode|") !== false or ($errorCode == '1016' and strpos($errorMsg, 'errno: 145') !== false))
+ {
+ global $config;
+ if(isset($config->framework->autoRepairTable) and $config->framework->autoRepairTable) die(js::locate(helper::createLink('misc', 'checkTable')));
+ $message .= ' ' . $this->lang->repairTable;
+ }
+ $sql = $this->sqlobj->get();
+ $this->app->triggerError($message . "
The sql is: $sql
", __FILE__, __LINE__, $exit = true);
+ }
+}
+
+/**
+ * SQL类。
+ * The SQL class.
+ *
+ * @package framework
+ */
+class baseSQL
+{
+ /**
+ * 所有方法的最大参数个数。
+ * The max count of params of all methods.
+ *
+ */
+ const MAX_ARGS = 3;
+
+ /**
+ * SQL字符串。
+ * The sql string.
+ *
+ * @var string
+ * @access public
+ */
+ public $sql = '';
+
+ /**
+ * 全局变量$dbh。
+ * The global $dbh.
+ *
+ * @var object
+ * @access public
+ */
+ public $dbh;
+
+ /**
+ * 更新或插入日期。
+ * The data to update or insert.
+ *
+ * @var mix
+ * @access public
+ */
+ public $data;
+
+ /**
+ * 是否是第一次设置。
+ * Is the first time to call set.
+ *
+ * @var bool
+ * @access public;
+ */
+ public $isFirstSet = true;
+
+ /**
+ * 是否是在条件语句中。
+ * If in the logic of judge condition or not.
+ *
+ * @var bool
+ * @access public;
+ */
+ public $inCondition = false;
+
+ /**
+ * 条件是否为真。
+ * The condition is true or not.
+ *
+ * @var bool
+ * @access public;
+ */
+ public $conditionIsTrue = false;
+
+ /**
+ * WHERE条件嵌套小括号标记。
+ * If in mark or not.
+ *
+ * @var bool
+ * @access public;
+ */
+ public $inMark = false;
+
+
+ /**
+ * 是否开启特殊字符转义。
+ * Magic quote or not.
+ *
+ * @var bool
+ * @access public
+ */
+ public $magicQuote;
+
+ /**
+ * 构造方法。
+ * The construct function.
+ *
+ * @access public
+ * @return void
+ */
+ public function __construct($table = '')
+ {
+ global $dbh;
+ $this->dbh = $dbh;
+ $this->magicQuote = (version_compare(phpversion(), '5.4', '<') and function_exists('get_magic_quotes_gpc') and get_magic_quotes_gpc());
+ }
+
+ /**
+ * 工厂方法。
+ * The factory method.
+ *
+ * @param string $table
+ * @access public
+ * @return object the sql object.
+ */
+ public static function factory($table = '')
+ {
+ return new sql($table);
+ }
+
+ /**
+ * select语句。
+ * The sql is select.
+ *
+ * @param string $field
+ * @access public
+ * @return object the sql object.
+ */
+ public static function select($field = '*')
+ {
+ $sqlobj = self::factory();
+ $sqlobj->sql = "SELECT $field ";
+ return $sqlobj;
+ }
+
+ /**
+ * update语句。
+ * The sql is update.
+ *
+ * @param string $table
+ * @access public
+ * @return object the sql object.
+ */
+ public static function update($table)
+ {
+ $sqlobj = self::factory();
+ $sqlobj->sql = "UPDATE $table SET ";
+ return $sqlobj;
+ }
+
+ /**
+ * insert语句。
+ * The sql is insert.
+ *
+ * @param string $table
+ * @access public
+ * @return object the sql object.
+ */
+ public static function insert($table)
+ {
+ $sqlobj = self::factory();
+ $sqlobj->sql = "INSERT INTO $table SET ";
+ return $sqlobj;
+ }
+
+ /**
+ * replace语句。
+ * The sql is replace.
+ *
+ * @param string $table
+ * @access public
+ * @return object the sql object.
+ */
+ public static function replace($table)
+ {
+ $sqlobj = self::factory();
+ $sqlobj->sql = "REPLACE $table SET ";
+ return $sqlobj;
+ }
+
+ /**
+ * delete语句。
+ * The sql is delete.
+ *
+ * @access public
+ * @return object the sql object.
+ */
+ public static function delete()
+ {
+ $sqlobj = self::factory();
+ $sqlobj->sql = "DELETE ";
+ return $sqlobj;
+ }
+
+ /**
+ * 将关联数组转换为sql语句中 `key` = value 的形式。
+ * Join the data items by key = value.
+ *
+ * @param object $data
+ * @param string $skipFields the fields to skip.
+ * @access public
+ * @return object the sql object.
+ */
+ public function data($data, $skipFields = '')
+ {
+ $data = (object) $data;
+ if($skipFields) $skipFields = ',' . str_replace(' ', '', $skipFields) . ',';
+
+ foreach($data as $field => $value)
+ {
+ if(!preg_match('|^\w+$|', $field))
+ {
+ unset($data->$field);
+ continue;
+ }
+ if(strpos($skipFields, ",$field,") !== false) continue;
+ $this->sql .= "`$field` = " . $this->quote($value) . ',';
+ }
+
+ $this->data = $data;
+ $this->sql = rtrim($this->sql, ','); // Remove the last ','.
+ return $this;
+ }
+
+ /**
+ * 在左边添加'('。
+ * Add an '(' at left.
+ *
+ * @param int $count
+ * @access public
+ * @return ojbect the sql object.
+ */
+ public function markLeft($count = 1)
+ {
+ if($this->inCondition and !$this->conditionIsTrue) return $this;
+ $this->sql .= str_repeat('(', $count);
+ $this->inMark = true;
+ return $this;
+ }
+
+ /**
+ * 在右边增加')'。
+ * Add an ')' at right.
+ *
+ * @param int $count
+ * @access public
+ * @return object the sql object.
+ */
+ public function markRight($count = 1)
+ {
+ if($this->inCondition and !$this->conditionIsTrue) return $this;
+ $this->sql .= str_repeat(')', $count);
+ $this->inMark = false;
+ return $this;
+ }
+
+ /**
+ * SET部分。
+ * The set part.
+ *
+ * @param string $set
+ * @access public
+ * @return object the sql object.
+ */
+ public function set($set)
+ {
+ /* Add ` to avoid keywords of mysql. */
+ if(strpos($set, '=') ===false)
+ {
+ $set = str_replace(',', '', $set);
+ $set = '`' . str_replace('`', '', $set) . '`';
+ }
+
+ $this->sql .= $this->isFirstSet ? " $set" : ", $set";
+ if($this->isFirstSet) $this->isFirstSet = false;
+ return $this;
+ }
+
+ /**
+ * 创建From部分。
+ * Create the from part.
+ *
+ * @param string $table
+ * @access public
+ * @return object the sql object.
+ */
+ public function from($table)
+ {
+ $this->sql .= "FROM $table";
+ return $this;
+ }
+
+ /**
+ * 创建Alias部分,Alias转为AS。
+ * Create the Alias part.
+ *
+ * @param string $alias
+ * @access public
+ * @return object the sql object.
+ */
+ public function alias($alias)
+ {
+ $this->sql .= " AS $alias ";
+ return $this;
+ }
+
+ /**
+ * 创建LEFT JOIN部分。
+ * Create the left join part.
+ *
+ * @param string $table
+ * @access public
+ * @return object the sql object.
+ */
+ public function leftJoin($table)
+ {
+ $this->sql .= " LEFT JOIN $table";
+ return $this;
+ }
+
+ /**
+ * 创建ON部分。
+ * Create the on part.
+ *
+ * @param string $condition
+ * @access public
+ * @return object the sql object.
+ */
+ public function on($condition)
+ {
+ $this->sql .= " ON $condition ";
+ return $this;
+ }
+
+ /**
+ * 开始条件判断。
+ * Begin condition judge.
+ *
+ * @param bool $condition
+ * @access public
+ * @return object the sql object.
+ */
+ public function beginIF($condition)
+ {
+ $this->inCondition = true;
+ $this->conditionIsTrue = $condition;
+ return $this;
+ }
+
+ /**
+ * 结束条件判断。
+ * End the condition judge.
+ *
+ * @access public
+ * @return object the sql object.
+ */
+ public function fi()
+ {
+ $this->inCondition = false;
+ $this->conditionIsTrue = false;
+ return $this;
+ }
+
+ /**
+ * 创建WHERE部分。
+ * Create the where part.
+ *
+ * @param string $arg1 the field name
+ * @param string $arg2 the operator
+ * @param string $arg3 the value
+ * @access public
+ * @return object the sql object.
+ */
+ public function where($arg1, $arg2 = null, $arg3 = null)
+ {
+ if($this->inCondition and !$this->conditionIsTrue) return $this;
+ if($arg3 !== null)
+ {
+ $value = $this->quote($arg3);
+ $condition = "`$arg1` $arg2 " . $this->quote($arg3);
+ }
+ else
+ {
+ $condition = $arg1;
+ }
+
+ if(!$this->inMark) $this->sql .= ' ' . DAO::WHERE ." $condition ";
+ if($this->inMark) $this->sql .= " $condition ";
+ return $this;
+ }
+
+ /**
+ * 创建AND部分。
+ * Create the AND part.
+ *
+ * @param string $condition
+ * @access public
+ * @return object the sql object.
+ */
+ public function andWhere($condition, $addMark = false)
+ {
+ if($this->inCondition and !$this->conditionIsTrue) return $this;
+ $mark = $addMark ? '(' : '';
+ $this->sql .= " AND {$mark} $condition ";
+ return $this;
+ }
+
+ /**
+ * 创建OR部分。
+ * Create the OR part.
+ *
+ * @param bool $condition
+ * @access public
+ * @return object the sql object.
+ */
+ public function orWhere($condition)
+ {
+ if($this->inCondition and !$this->conditionIsTrue) return $this;
+ $this->sql .= " OR $condition ";
+ return $this;
+ }
+
+ /**
+ * 创建'='部分。
+ * Create the '='.
+ *
+ * @param string $value
+ * @access public
+ * @return object the sql object.
+ */
+ public function eq($value)
+ {
+ if($this->inCondition and !$this->conditionIsTrue) return $this;
+ $this->sql .= " = " . $this->quote($value);
+ return $this;
+ }
+
+ /**
+ * 创建'!='。
+ * Create '!='.
+ *
+ * @param string $value
+ * @access public
+ * @return void the sql object.
+ */
+ public function ne($value)
+ {
+ if($this->inCondition and !$this->conditionIsTrue) return $this;
+ $this->sql .= " != " . $this->quote($value);
+ return $this;
+ }
+
+ /**
+ * 创建'>'。
+ * Create '>'.
+ *
+ * @param string $value
+ * @access public
+ * @return object the sql object.
+ */
+ public function gt($value)
+ {
+ if($this->inCondition and !$this->conditionIsTrue) return $this;
+ $this->sql .= " > " . $this->quote($value);
+ return $this;
+ }
+
+ /**
+ * 创建'>='
+ * Create '>='.
+ *
+ * @param string $value
+ * @access public
+ * @return object the sql object.
+ */
+ public function ge($value)
+ {
+ if($this->inCondition and !$this->conditionIsTrue) return $this;
+ $this->sql .= " >= " . $this->quote($value);
+ return $this;
+ }
+
+ /**
+ * 创建'<'。
+ * Create '<'.
+ *
+ * @param mixed $value
+ * @access public
+ * @return object the sql object.
+ */
+ public function lt($value)
+ {
+ if($this->inCondition and !$this->conditionIsTrue) return $this;
+ $this->sql .= " < " . $this->quote($value);
+ return $this;
+ }
+
+ /**
+ * 创建 '<='。
+ * Create '<='.
+ *
+ * @param mixed $value
+ * @access public
+ * @return object the sql object.
+ */
+ public function le($value)
+ {
+ if($this->inCondition and !$this->conditionIsTrue) return $this;
+ $this->sql .= " <= " . $this->quote($value);
+ return $this;
+ }
+
+ /**
+ * 创建"between and"。
+ * Create "between and"
+ *
+ * @param string $min
+ * @param string $max
+ * @access public
+ * @return object the sql object.
+ */
+ public function between($min, $max)
+ {
+ if($this->inCondition and !$this->conditionIsTrue) return $this;
+ $min = $this->quote($min);
+ $max = $this->quote($max);
+ $this->sql .= " BETWEEN $min AND $max ";
+ return $this;
+ }
+
+ /**
+ * 创建IN部分。
+ * Create in part.
+ *
+ * @param string|array $ids ','分割的字符串或者数组 list string by ',' or an array
+ * @access public
+ * @return object the sql object.
+ */
+ public function in($ids)
+ {
+ if($this->inCondition and !$this->conditionIsTrue) return $this;
+ $this->sql .= helper::dbIN($ids);
+ return $this;
+ }
+
+ /**
+ * 创建'NOT IN'部分。
+ * Create not in part.
+ *
+ * @param string|array $ids list string by ',' or an array
+ * @access public
+ * @return object the sql object.
+ */
+ public function notin($ids)
+ {
+ if($this->inCondition and !$this->conditionIsTrue) return $this;
+ $this->sql .= ' NOT ' . helper::dbIN($ids);
+ return $this;
+ }
+
+ /**
+ * 创建LIKE部分。
+ * Create the like by part.
+ *
+ * @param string $string
+ * @access public
+ * @return object the sql object.
+ */
+ public function like($string)
+ {
+ if($this->inCondition and !$this->conditionIsTrue) return $this;
+ $this->sql .= " LIKE " . $this->quote($string);
+ return $this;
+ }
+
+ /**
+ * 创建NOT LIKE部分。
+ * Create the not like by part.
+ *
+ * @param string $string
+ * @access public
+ * @return object the sql object.
+ */
+ public function notLike($string)
+ {
+ if($this->inCondition and !$this->conditionIsTrue) return $this;
+ $this->sql .= "NOT LIKE " . $this->quote($string);
+ return $this;
+ }
+
+ /**
+ * 创建ORDER BY部分。
+ * Create the order by part.
+ *
+ * @param string $order
+ * @access public
+ * @return object the sql object.
+ */
+ public function orderBy($order)
+ {
+ $order = str_replace(array('|', '', '_'), ' ', $order);
+
+ /* Add "`" in order string. */
+ /* When order has limit string. */
+ $pos = stripos($order, 'limit');
+ $orders = $pos ? substr($order, 0, $pos) : $order;
+ $limit = $pos ? substr($order, $pos) : '';
+
+ $orders = explode(',', $orders);
+ foreach($orders as $i => $order)
+ {
+ $orderParse = explode(' ', trim($order));
+ foreach($orderParse as $key => $value)
+ {
+ $value = trim($value);
+ if(empty($value) or strtolower($value) == 'desc' or strtolower($value) == 'asc') continue;
+ $field = trim($value, '`');
+
+ /* such as t1.id field. */
+ if(strpos($value, '.') !== false) list($table, $field) = explode('.', $field);
+ /* Ignore order with function e.g. order by length(tag) asc. */
+ if(strpos($field, '(') === false) $field = "`$field`";
+
+ $orderParse[$key] = isset($table) ? $table . '.' . $field : $field;
+ unset($table);
+ }
+ $orders[$i] = join(' ', $orderParse);
+ }
+ $order = join(',', $orders) . ' ' . $limit;
+
+ $this->sql .= ' ' . DAO::ORDERBY . " $order";
+ return $this;
+ }
+
+ /**
+ * 创建LIMIT部分。
+ * Create the limit part.
+ *
+ * @param string $limit
+ * @access public
+ * @return object the sql object.
+ */
+ public function limit($limit)
+ {
+ if(empty($limit)) return $this;
+ stripos($limit, 'limit') !== false ? $this->sql .= " $limit " : $this->sql .= ' ' . DAO::LIMIT . " $limit ";
+ return $this;
+ }
+
+ /**
+ * 创建GROUP BY部分。
+ * Create the groupby part.
+ *
+ * @param string $groupBy
+ * @access public
+ * @return object the sql object.
+ */
+ public function groupBy($groupBy)
+ {
+ $this->sql .= ' ' . DAO::GROUPBY . " $groupBy";
+ return $this;
+ }
+
+ /**
+ * 创建HAVING部分。
+ * Create the having part.
+ *
+ * @param string $having
+ * @access public
+ * @return object the sql object.
+ */
+ public function having($having)
+ {
+ $this->sql .= ' ' . DAO::HAVING . " $having";
+ return $this;
+ }
+
+ /**
+ * 获取SQL字符串。
+ * Get the sql string.
+ *
+ * @access public
+ * @return string
+ */
+ public function get()
+ {
+ return $this->sql;
+ }
+
+ /**
+ * 对字段加转义。
+ * Quote a var.
+ *
+ * @param mixed $value
+ * @access public
+ * @return mixed
+ */
+ public function quote($value)
+ {
+ if($this->magicQuote) $value = stripslashes($value);
+ return $this->dbh->quote((string)$value);
+ }
+}
diff --git a/lib/base/filter/filter.class.php b/lib/base/filter/filter.class.php
new file mode 100644
index 0000000000..310ef7ebae
--- /dev/null
+++ b/lib/base/filter/filter.class.php
@@ -0,0 +1,952 @@
+ array('min_range' => $args[1], 'max_range' => $args[2]));
+ }
+ else
+ {
+ $options = array('options' => array('min_range' => $args[1]));
+ }
+
+ return filter_var($var, FILTER_VALIDATE_INT, $options);
+ }
+ else
+ {
+ return filter_var($var, FILTER_VALIDATE_INT);
+ }
+ }
+
+ /**
+ * 检查不是Int类型。
+ * Not int checking.
+ *
+ * @param int $var
+ * @static
+ * @access public
+ * @return bool
+ */
+ public static function checkNotInt($var)
+ {
+ return !self::checkInt($var);
+ }
+
+ /**
+ * 检查Float类型。
+ * Float checking.
+ *
+ * @param float $var
+ * @param string $decimal
+ * @static
+ * @access public
+ * @return bool
+ */
+ public static function checkFloat($var, $decimal = '.')
+ {
+ return filter_var($var, FILTER_VALIDATE_FLOAT, array('options' => array('decimal' => $decimal)));
+ }
+
+ /**
+ * 检查Email。
+ * Email checking.
+ *
+ * @param string $var
+ * @static
+ * @access public
+ * @return bool
+ */
+ public static function checkEmail($var)
+ {
+ return filter_var($var, FILTER_VALIDATE_EMAIL);
+ }
+
+ /**
+ * 检查电话或手机号码
+ * Check phone number.
+ *
+ * @param string $var
+ * @static
+ * @access public
+ * @return void
+ */
+ public static function checkPhone($var)
+ {
+ return (validater::checkTel($var) or validater::checkMobile($var));
+ }
+
+ /**
+ * 检查电话号码
+ * Check tel number.
+ *
+ * @param int $var
+ * @static
+ * @access public
+ * @return void
+ */
+ public static function checkTel($var)
+ {
+ return preg_match("/^([0-9]{3,4}-)?[0-9]{7,8}$/", $var);
+ }
+
+ /**
+ * 检查手机号码
+ * Check mobile number.
+ *
+ * @param string $var
+ * @static
+ * @access public
+ * @return void
+ */
+ public static function checkMobile($var)
+ {
+ return preg_match("/^1[3-5,8]{1}[0-9]{9}$/", $var);
+ }
+
+ /**
+ * 检查网址。
+ * 该规则不支持中文字符的网址。
+ *
+ * URL checking.
+ * The check rule of filter don't support chinese.
+ *
+ * @param string $var
+ * @static
+ * @access public
+ * @return bool
+ */
+ public static function checkURL($var)
+ {
+ return filter_var($var, FILTER_VALIDATE_URL);
+ }
+
+ /**
+ * 检查域名,不支持中文。
+ * Domain checking.
+ *
+ * The check rule of filter don't support chinese.
+ *
+ * @param string $var
+ * @static
+ * @access public
+ * @return bool
+ */
+ public static function checkDomain($var)
+ {
+ return preg_match('/^([a-z0-9-]+\.)+[a-z]{2,15}$/', $var);
+ }
+
+ /**
+ * 检查IP地址。
+ * IP checking.
+ *
+ * @param ip $var
+ * @param string $range all|public|static|public
+ * @static
+ * @access public
+ * @return bool
+ */
+ public static function checkIP($var, $range = 'all')
+ {
+ if($range == 'all') return filter_var($var, FILTER_VALIDATE_IP);
+ if($range == 'public static') return filter_var($var, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE);
+ if($range == 'public')
+ {
+ if($var == '127.0.0.1' or filter_var($var, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE) === false) return true;
+ return false;
+ }
+ }
+
+ /**
+ * 日期检查。注意,2009-09-31是一个合法日期,系统会将它转换为2009-10-01。
+ * Date checking. Note: 2009-09-31 will be an valid date, because strtotime auto fixed it to 10-01.
+ *
+ * @param date $date
+ * @static
+ * @access public
+ * @return bool
+ */
+ public static function checkDate($date)
+ {
+ if($date == '0000-00-00') return true;
+ $stamp = strtotime($date);
+ if(!is_numeric($stamp)) return false;
+ return checkdate(date('m', $stamp), date('d', $stamp), date('Y', $stamp));
+ }
+
+ /**
+ * 检查正则表达式。
+ * REG checking.
+ *
+ * @param string $var
+ * @param string $reg
+ * @static
+ * @access public
+ * @return bool
+ */
+ public static function checkREG($var, $reg)
+ {
+ return filter_var($var, FILTER_VALIDATE_REGEXP, array('options' => array('regexp' => $reg)));
+ }
+
+ /**
+ * 检查长度。
+ * Length checking.
+ *
+ * @param string $var
+ * @param string $max
+ * @param int $min
+ * @static
+ * @access public
+ * @return bool
+ */
+ public static function checkLength($var, $max, $min = 0)
+ {
+ $length = function_exists('mb_strlen') ? mb_strlen($var, 'utf-8') : strlen($var);
+ return self::checkInt($length, $min, $max);
+ }
+
+ /**
+ * 检查不为空。
+ * Not empty checking.
+ *
+ * @param mixed $var
+ * @static
+ * @access public
+ * @return bool
+ */
+ public static function checkNotEmpty($var)
+ {
+ return !empty($var);
+ }
+
+ /**
+ * 检查为空。
+ * Empty checking.
+ *
+ * @param mixed $var
+ * @static
+ * @access public
+ * @return bool
+ */
+ public static function checkEmpty($var)
+ {
+ return empty($var);
+ }
+
+ /**
+ * 检查用户名。
+ * Account checking.
+ *
+ * @param string $var
+ * @static
+ * @access public
+ * @return bool
+ */
+ public static function checkAccount($var)
+ {
+ global $config;
+ $accountRule = empty($config->accountRule) ? '|^[a-zA-Z0-9_]{1}[a-zA-Z0-9_\.]{1,}[a-zA-Z0-9_]{1}$|' : $config->accountRule;
+ return self::checkREG($var, $accountRule);
+ }
+
+ /**
+ * 检查Code。
+ * Check code.
+ *
+ * @param string $var
+ * @static
+ * @access public
+ * @return bool
+ */
+ public static function checkCode($var)
+ {
+ return self::checkREG($var, '|^[A-Za-z0-9]+$|');
+ }
+
+ /**
+ * 检查验证码。
+ * Check captcha.
+ *
+ * @param mixed $var
+ * @static
+ * @access public
+ * @return bool
+ */
+ public static function checkCaptcha($var)
+ {
+ if(!isset($_SESSION['captcha'])) return false;
+ return $var == $_SESSION['captcha'];
+ }
+
+ /**
+ * 是否等于给定的值。
+ * Must equal a value.
+ *
+ * @param mixed $var
+ * @param mixed $value
+ * @static
+ * @access public
+ * @return bool
+ */
+ public static function checkEqual($var, $value)
+ {
+ return $var == $value;
+ }
+
+ /**
+ * 检查不等于给定的值
+ * Must not equal a value.
+ *
+ * @param mixed $var
+ * @param mixed $value
+ * @static
+ * @access public
+ * @return bool
+ */
+ public static function checkNotEqual($var, $value)
+ {
+ return $var != $value;
+ }
+
+ /**
+ * 检查大于给定的值。
+ * Must greater than a value.
+ *
+ * @param mixed $var
+ * @param mixed $value
+ * @static
+ * @access public
+ * @return bool
+ */
+ public static function checkGT($var, $value)
+ {
+ return $var > $value;
+ }
+
+ /**
+ * 检查小于给定的值
+ * Must less than a value.
+ *
+ * @param mixed $var
+ * @param mixed $value
+ * @static
+ * @access public
+ * @return bool
+ */
+ public static function checkLT($var, $value)
+ {
+ return $var < $value;
+ }
+
+ /**
+ * 检查大于等于给定的值
+ * Must greater than a value or equal a value.
+ *
+ * @param mixed $var
+ * @param mixed $value
+ * @static
+ * @access public
+ * @return bool
+ */
+ public static function checkGE($var, $value)
+ {
+ return $var >= $value;
+ }
+
+ /**
+ * 检查小于等于给定的值
+ * Must less than a value or equal a value.
+ *
+ * @param mixed $var
+ * @param mixed $value
+ * @static
+ * @access public
+ * @return bool
+ */
+ public static function checkLE($var, $value)
+ {
+ return $var <= $value;
+ }
+
+ /**
+ * 检查是否在给定的列表里面。
+ * Must in value list.
+ *
+ * @param mixed $var
+ * @param mixed $value
+ * @static
+ * @access public
+ * @return bool
+ */
+ public static function checkIn($var, $value)
+ {
+ if(!is_array($value)) $value = explode(',', $value);
+ return in_array($var, $value);
+ }
+
+ /**
+ * 检查文件名。
+ * Check file name.
+ *
+ * @param string $var
+ * @static
+ * @access public
+ * @return bool
+ */
+ public static function checkFileName($var)
+ {
+ return !preg_match('/>+|:+|<+/', $var);
+ }
+
+ /**
+ * 检查敏感词。
+ * Check sensitive words.
+ *
+ * @param object $vars
+ * @param array $dicts
+ * @static
+ * @access public
+ * @return void
+ */
+ public static function checkSensitive($vars, $dicts)
+ {
+ foreach($vars as $var)
+ {
+ if(!$var) continue;
+ foreach($dicts as $dict)
+ {
+ if(strpos($var, $dict) === false) continue;
+ if(strpos($var, $dict) !== false) return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * 调用一个方法进行检查。
+ * Call a function to check it.
+ *
+ * @param mixed $var
+ * @param string $func
+ * @static
+ * @access public
+ * @return bool
+ */
+ public static function call($var, $func)
+ {
+ return filter_var($var, FILTER_CALLBACK, array('options' => $func));
+ }
+}
+
+/**
+ * fixer类,处理数据。
+ * fixer class, to fix data types.
+ *
+ * @package framework
+ */
+class baseFixer
+{
+ /**
+ * 处理的数据。
+ * The data to be fixed.
+ *
+ * @var ojbect
+ * @access public
+ */
+ public $data;
+
+ /**
+ * 跳过处理的字段。
+ * The fields to striped.
+ *
+ * @var array
+ * @access public
+ */
+ public $stripedFields = array();
+
+ /**
+ * 构造方法,将超级全局变量转换为对象。
+ * The construction function, according the scope, convert it to object.
+ *
+ * @param string $scope the scope of the var, should be post|get|server|session|cookie|env
+ * @access public
+ * @return void
+ */
+ public function __construct($scope)
+ {
+ switch($scope)
+ {
+ case 'post':
+ $this->data = (object)$_POST;
+ break;
+ case 'server':
+ $this->data = (object)$_SERVER;
+ break;
+ case 'get':
+ $this->data = (object)$_GET;
+ break;
+ case 'session':
+ $this->data = (object)$_SESSION;
+ break;
+ case 'cookie':
+ $this->data = (object)$_COOKIE;
+ break;
+ case 'env':
+ $this->data = (object)$_ENV;
+ break;
+ case 'file':
+ $this->data = (object)$_FILES;
+ break;
+
+ default:
+ die('scope not supported, should be post|get|server|session|cookie|env');
+ }
+ }
+
+ /**
+ * 工厂方法。
+ * The factory function.
+ *
+ * @param string $scope
+ * @access public
+ * @return object fixer object.
+ */
+ public static function input($scope)
+ {
+ return new fixer($scope);
+ }
+
+ /**
+ * 处理Email。
+ * Email fix.
+ *
+ * @param string $fieldName
+ * @access public
+ * @return object fixer object.
+ */
+ public function cleanEmail($fieldName)
+ {
+ $fields = $this->processFields($fieldName);
+ foreach($fields as $fieldName) $this->data->$fieldName = filter_var($this->data->$fieldName, FILTER_SANITIZE_EMAIL);
+ return $this;
+ }
+
+ /**
+ * url编码。
+ * urlencode.
+ *
+ * @param string $fieldName
+ * @access public
+ * @return object fixer object.
+ */
+ public function encodeURL($fieldName)
+ {
+ $fields = $this->processFields($fieldName);
+ $args = func_get_args();
+ foreach($fields as $fieldName)
+ {
+ $this->data->$fieldName = isset($args[1]) ? filter_var($this->data->$fieldName, FILTER_SANITIZE_ENCODED, $args[1]) : filter_var($this->data->$fieldName, FILTER_SANITIZE_ENCODED);
+ }
+ return $this;
+ }
+
+ /**
+ * 清理网址。
+ * Clean the url.
+ *
+ * @param string $fieldName
+ * @access public
+ * @return object fixer object.
+ */
+ public function cleanURL($fieldName)
+ {
+ $fields = $this->processFields($fieldName);
+ foreach($fields as $fieldName) $this->data->$fieldName = filter_var($this->data->$fieldName, FILTER_SANITIZE_URL);
+ return $this;
+ }
+
+ /**
+ * 处理Float类型。
+ * Float fixer.
+ *
+ * @param string $fieldName
+ * @access public
+ * @return object fixer object.
+ */
+ public function cleanFloat($fieldName)
+ {
+ $fields = $this->processFields($fieldName);
+ foreach($fields as $fieldName) $this->data->$fieldName = filter_var($this->data->$fieldName, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION|FILTER_FLAG_ALLOW_THOUSAND);
+ return $this;
+ }
+
+ /**
+ * 处理Int类型。
+ * Int fixer.
+ *
+ * @param string $fieldName
+ * @access public
+ * @return object fixer object.
+ */
+ public function cleanINT($fieldName = '')
+ {
+ $fields = $this->processFields($fieldName);
+ foreach($fields as $fieldName) $this->data->$fieldName = filter_var($this->data->$fieldName, FILTER_SANITIZE_NUMBER_INT);
+ return $this;
+ }
+
+ /**
+ * 将字符串转换为可以在浏览器查看的编码。
+ * Special chars.
+ *
+ * @param string $fieldName
+ * @access public
+ * @return object fixer object
+ */
+ public function specialChars($fieldName)
+ {
+ $fields = $this->processFields($fieldName);
+ foreach($fields as $fieldName)
+ {
+ if(empty($this->stripedFields) or !in_array($fieldName, $this->stripedFields)) $this->data->$fieldName = $this->specialArray($this->data->$fieldName);
+ }
+ return $this;
+ }
+
+ /**
+ * Special array
+ *
+ * @param mix $data
+ * @access public
+ * @return mix
+ */
+ public function specialArray($data)
+ {
+ if(!is_array($data)) return htmlspecialchars($data, ENT_QUOTES);
+
+ foreach($data as &$value) $value = $this->specialArray($value);
+
+ return $data;
+ }
+
+ /**
+ * 忽略该标签。
+ * Strip tags
+ *
+ * @param string $fieldName
+ * @param string $allowableTags
+ * @access public
+ * @return object fixer object
+ */
+ public function stripTags($fieldName, $allowedTags = '')
+ {
+ global $app, $config;
+ if(empty($allowedTags) and isset($config->allowedTags)) $allowedTags = $config->allowedTags;
+ $usePurifier = isset($config->framework->purifier) ? $config->framework->purifier : false;
+ if($usePurifier)
+ {
+ $app->loadClass('purifier', true);
+ $purifierConfig = HTMLPurifier_Config::createDefault();
+ $purifierConfig->set('Filter.YouTube', 1);
+
+ /* Disable caching. */
+ $purifierConfig->set('Cache.DefinitionImpl', null);
+
+ $purifier = new HTMLPurifier($purifierConfig);
+ $def = $purifierConfig->getHTMLDefinition(true);
+ $def->addAttribute('a', 'target', 'Enum#_blank,_self,_target,_top');
+ }
+
+ $fields = $this->processFields($fieldName);
+ foreach($fields as $fieldName)
+ {
+ if(version_compare(phpversion(), '5.4', '<') and get_magic_quotes_gpc()) $this->data->$fieldName = stripslashes($this->data->$fieldName);
+
+ if(!in_array($fieldName, $this->stripedFields))
+ {
+ if(!defined('RUN_MODE') or RUN_MODE != 'admin')
+ {
+ /*
+ * purifier会把 替换空格,kindeditor在会吧行首的空格去掉。
+ * purifier will change to ' ', and edit it will no space in line head use kindeditor.
+ **/
+ if($usePurifier) $this->data->$fieldName = str_replace(' ', '&spnb;', $this->data->$fieldName);
+ $this->data->$fieldName = $usePurifier ? $purifier->purify($this->data->$fieldName) : strip_tags($this->data->$fieldName, $allowedTags);
+ if($usePurifier) $this->data->$fieldName = str_replace('&spnb;', ' ', $this->data->$fieldName);
+ }
+ }
+ $this->stripedFields[] = $fieldName;
+ }
+ return $this;
+ }
+
+ /**
+ * 忽略处理给定的字段。
+ * Skip special chars check.
+ *
+ * @param string $filename
+ * @access public
+ * @return object fixer object
+ */
+ public function skipSpecial($fieldName)
+ {
+ $fields = $this->processFields($fieldName);
+ foreach($fields as $fieldName) $this->stripedFields[] = $fieldName;
+ return $this;
+ }
+
+ /**
+ * 给字段添加引用,防止字符与关键字冲突。
+ * Quote
+ *
+ * @param string $fieldName
+ * @access public
+ * @return object fixer object
+ */
+ public function quote($fieldName)
+ {
+ $fields = $this->processFields($fieldName);
+ foreach($fields as $fieldName) $this->data->$fieldName = filter_var($this->data->$fieldName, FILTER_SANITIZE_MAGIC_QUOTES);
+ return $this;
+ }
+
+ /**
+ * 设置字段的默认值。
+ * Set default value of some fileds.
+ *
+ * @param string $fields
+ * @param mixed $value
+ * @access public
+ * @return object fixer object
+ */
+ public function setDefault($fields, $value)
+ {
+ $fields = strpos($fields, ',') ? explode(',', str_replace(' ', '', $fields)) : array($fields);
+ foreach($fields as $fieldName)if(!isset($this->data->$fieldName) or empty($this->data->$fieldName)) $this->data->$fieldName = $value;
+ return $this;
+ }
+
+ /**
+ * 如果条件为真,则为字段赋值。
+ * Set value of a filed on the condition is true.
+ *
+ * @param bool $condition
+ * @param string $fieldName
+ * @param string $value
+ * @access public
+ * @return object fixer object
+ */
+ public function setIF($condition, $fieldName, $value)
+ {
+ if($condition) $this->data->$fieldName = $value;
+ return $this;
+ }
+
+ /**
+ * 强制给字段赋值。
+ * Set the value of a filed in force.
+ *
+ * @param string $fieldName
+ * @param mixed $value
+ * @access public
+ * @return object fixer object
+ */
+ public function setForce($fieldName, $value)
+ {
+ $this->data->$fieldName = $value;
+ return $this;
+ }
+
+ /**
+ * 移除一个字段。
+ * Remove a field.
+ *
+ * @param string $fieldName
+ * @access public
+ * @return object fixer object
+ */
+ public function remove($fieldName)
+ {
+ $fields = $this->processFields($fieldName);
+ foreach($fields as $fieldName) unset($this->data->$fieldName);
+ return $this;
+ }
+
+ /**
+ * 如果条件为真,移除该字段。
+ * Remove a filed on the condition is true.
+ *
+ * @param bool $condition
+ * @param string $fields
+ * @access public
+ * @return object fixer object
+ */
+ public function removeIF($condition, $fields)
+ {
+ $fields = $this->processFields($fields);
+ if($condition) foreach($fields as $fieldName) unset($this->data->$fieldName);
+ return $this;
+ }
+
+ /**
+ * 为数据添加新的项。
+ * Add an item to the data.
+ *
+ * @param string $fieldName
+ * @param mixed $value
+ * @access public
+ * @return object fixer object
+ */
+ public function add($fieldName, $value)
+ {
+ $this->data->$fieldName = $value;
+ return $this;
+ }
+
+ /**
+ * 如果条件为真,则为数据添加新的项。
+ * Add an item to the data on the condition if true.
+ *
+ * @param bool $condition
+ * @param string $fieldName
+ * @param mixed $value
+ * @access public
+ * @return object fixer object
+ */
+ public function addIF($condition, $fieldName, $value)
+ {
+ if($condition) $this->data->$fieldName = $value;
+ return $this;
+ }
+
+ /**
+ * 为指定字段增加值。
+ * Join the field.
+ *
+ * @param string $fieldName
+ * @param string $value
+ * @access public
+ * @return object fixer object
+ */
+ public function join($fieldName, $value)
+ {
+ if(!isset($this->data->$fieldName) or !is_array($this->data->$fieldName)) return $this;
+ $this->data->$fieldName = join($value, $this->data->$fieldName);
+ return $this;
+ }
+
+ /**
+ * 调用一个方法来处理数据。
+ * Call a function to fix it.
+ *
+ * @param string $fieldName
+ * @param string $func
+ * @access public
+ * @return object fixer object
+ */
+ public function callFunc($fieldName, $func)
+ {
+ $fields = $this->processFields($fieldName);
+ foreach($fields as $fieldName) $this->data->$fieldName = filter_var($this->data->$fieldName, FILTER_CALLBACK, array('options' => $func));
+ return $this;
+ }
+
+ /**
+ * 处理完成后返回数据。
+ * Get the data after fixing.
+ *
+ * @param string $fieldName
+ * @access public
+ * @return object
+ */
+ public function get($fields = '')
+ {
+ $fields = str_replace(' ', '', trim($fields));
+ foreach($this->data as $field => $value) $this->specialChars($field);
+
+ if(empty($fields)) return $this->data;
+ if(strpos($fields, ',') === false) return $this->data->$fields;
+
+ $fields = array_flip(explode(',', $fields));
+ foreach($this->data as $field => $value)
+ {
+ if(!isset($fields[$field])) unset($this->data->$field);
+ if(!in_array($field, $this->stripedFields)) $this->data->$field = $this->specialChars($this->data->field);
+ }
+
+ return $this->data;
+ }
+
+ /**
+ * 处理字段,如果字段中含有',',拆分成数组。如果字段不在$data中,删除掉。
+ * Process fields, if contains ',', split it to array. If not in $data, remove it.
+ *
+ * @param string $fields
+ * @access public
+ * @return array
+ */
+ public function processFields($fields)
+ {
+ $fields = strpos($fields, ',') ? explode(',', str_replace(' ', '', $fields)) : array($fields);
+ foreach($fields as $key => $fieldName) if(!isset($this->data->$fieldName)) unset($fields[$key]);
+ return $fields;
+ }
+}
diff --git a/lib/base/front/front.class.php b/lib/base/front/front.class.php
new file mode 100644
index 0000000000..737c1aae3f
--- /dev/null
+++ b/lib/base/front/front.class.php
@@ -0,0 +1,1178 @@
+$title\n";
+ }
+
+ /**
+ * 生成meta标签。
+ * Create a meta.
+ *
+ * @param mixed $name the meta name
+ * @param mixed $value the meta value
+ * @static
+ * @access public
+ * @return string
+ */
+ public static function meta($name, $value)
+ {
+ if($name == 'charset') return "\n";
+ return "\n";
+ }
+
+ /**
+ * 生成favicon标签。
+ * Create favicon tag
+ *
+ * @param mixed $url the url of the icon.
+ * @static
+ * @access public
+ * @return string
+ */
+ public static function favicon($url)
+ {
+ return "\n\n";
+ }
+
+ /**
+ * 创建图标。
+ * Create icon.
+ *
+ * @param name $name the name of the icon.
+ * @param cssClass $class the extra css class of the icon.
+ * @static
+ * @access public
+ * @return string
+ */
+ public static function icon($name, $class = '')
+ {
+ $class = empty($class) ? ('icon-' . $name) : ('icon-' . $name . ' ' . $class);
+ return "";
+
+ }
+
+ /**
+ * 生成rss标签。
+ * Create the rss tag.
+ *
+ * @param string $url
+ * @param string $title
+ * @static
+ * @access public
+ * @return string
+ */
+ public static function rss($url, $title = '')
+ {
+ return "";
+ }
+
+ /**
+ * 生成超链接。
+ * Create tags like text
+ *
+ * @param string $href the link url.
+ * @param string $title the link title.
+ * @param string $misc other params.
+ * @param string $newline
+ * @static
+ * @access public
+ * @return string
+ */
+ static public function a($href = '', $title = '', $target = "_self", $misc = '', $newline = true)
+ {
+ global $config;
+ if(empty($title)) $title = $href;
+ $newline = $newline ? "\n" : '';
+
+ /* if page has onlybody param then add this param in all link. the param hide header and footer. */
+ if(strpos($href, 'onlybody=yes') === false and isonlybody())
+ {
+ $onlybody = strpos($link, '?') === false ? "?onlybody=yes" : "&onlybody=yes";
+ $href .= $onlybody;
+ }
+
+ if($target == '_self') return "$title$newline";
+ return "$title$newline";
+ }
+
+ /**
+ * 生成邮件链接。
+ * Create tags like text
+ *
+ * @param string $mail the email address
+ * @param string $title the email title.
+ * @static
+ * @access public
+ * @return string
+ */
+ static public function mailto($mail = '', $title = '')
+ {
+ $html = '';
+ $mails = explode(',', $mail);
+ $titles = explode(',', $title);
+ foreach($mails as $key => $m)
+ {
+ if(empty($m)) continue;
+ $t = empty($titles[$key]) ? $mail : $titles[$key];
+ $html .= " $t";
+ }
+ return $html;
+ }
+
+ /**
+ * 生成select标签。
+ * Create tags like ""
+ *
+ * @param string $name the name of the select tag.
+ * @param array $options the array to create select tag from.
+ * @param string $selectedItems the item(s) to be selected, can like item1,item2.
+ * @param string $attrib other params such as multiple, size and style.
+ * @param string $append adjust if add options[$selectedItems].
+ * @static
+ * @access public
+ * @return string
+ */
+ static public function select($name = '', $options = array(), $selectedItems = "", $attrib = "", $append = false)
+ {
+ $options = (array)($options);
+ if($append and !isset($options[$selectedItems])) $options[$selectedItems] = $selectedItems;
+ if(!is_array($options) or empty($options)) return false;
+
+ /* The begin. */
+ $id = $name;
+ if(strpos($name, '[') !== false) $id = trim(str_replace(']', '', str_replace('[', '', $name)));
+ $id = "id='{$id}'";
+ if(strpos($attrib, 'id=') !== false) $id = '';
+
+ $string = "\n";
+ }
+
+ /**
+ * 生成带optgroup标签的select标签。
+ * Create select with optgroup.
+ *
+ * @param string $name the name of the select tag.
+ * @param array $groups the option groups.
+ * @param string $selectedItems the item(s) to be selected, can like item1,item2.
+ * @param string $attrib other params such as multiple, size and style.
+ * @static
+ * @access public
+ * @return string
+ */
+ static public function selectGroup($name = '', $groups = array(), $selectedItems = "", $attrib = "")
+ {
+ if(!is_array($groups) or empty($groups)) return false;
+
+ /* The begin. */
+ $id = $name;
+ if(strpos($name, '[') !== false) $id = trim(str_replace(']', '', str_replace('[', '', $name)));
+ $string = "\n";
+ }
+
+ /**
+ * 生成单选按钮。
+ * Create tags like ""
+ *
+ * @param string $name the name of the radio tag.
+ * @param array $options the array to create radio tag from.
+ * @param string $checked the value to checked by default.
+ * @param string $attrib other attribs.
+ * @param string $type inline or block
+ * @static
+ * @access public
+ * @return string
+ */
+ static public function radio($name = '', $options = array(), $checked = '', $attrib = '', $type = 'inline')
+ {
+ $options = (array)($options);
+ if(!is_array($options) or empty($options)) return false;
+ $isBlock = $type == 'block';
+
+ $string = '';
+ foreach($options as $key => $value)
+ {
+ if($isBlock) $string .= "