gusucode.com > 同城苏州黄页系统php源码程序 > lib/Query.class.php

    <?
/**
 * 用于設置多樣條件,並完成數據庫查詢的類,2005/7/19 整理
 *
 * @author		alee <alee201@163.com>
 * @version	1.1.0	2005/7/19	第一个稳定版本,具备基本功能
 * @version	1.1.1	2005/7/20	修正了getCnt()函數在dbtable屬性爲數組的情況下,如果結果為0,被認定出錯
 * @version	1.2.0	2005/8/10	增加了union 聯合查詢時,爲不同數據表指定不同的字段
 * @version	1.2.1	2005/9/2	增加了set_regexp 方法
 * @version	1.2.2	2005/9/5	directCondition方法增加了field 參數
 * @version	1.2.3	2005/9/8	增加了dateCondition 方法,修正了mathCondition方法
 * @version	2.0.1	2005/10/18	增加了 條件組,Query.class 的內部機制 發生了很大的變化,所以 版本號定爲 2.x ,以示區別
 * @version	2.1.0	2005/10/21	增加了 currentTable 屬性 和 相關的 setCurTable()/ clearCurTable() 兩個函數,以支持 在 union 查詢時 可爲 不同的 table 指定不同的條件。設置條件前,使用 setCurTable() 指明該條件 僅作用于那些 數據表 , 設置完畢 可使用 clearCurTable() 清除
 * @version	3.0.0	2005/10/26	修改了 get_result() 的调用参数,因此不再向下兼容
 * @version	3.1.0	2005/10/28	增加了 save() 和 revert() 函数
 * @package 	Query Class 數據庫條件查詢類
 */
class Query
{
	/**
	 * @ignore
	 */
	var $logic				= "";
	
	/**
	 * 連接多次利用directCondition()、set_like()等函數設定的條件的邏輯關系
	 *
	 * 前後必須有一個空格,以便直接在sql中使用,如:<code>$q->cut=" and ";</code>
	 *
	 * @var		string	" and "," or "
	 * @see		areaCondition()
	 * @see		directCondition()
	 * @see		mathCondition()
	 * @see		set_keyworld()
	 * @see		set_like()
	 * @see		set_where() 
	 */

	/**
	 * @ignore
	 */
	var $sql				= "";
	
	/**
	 * @ignore
	 */
	var $dbtable			= array();
	var $tempTableName		= '';
	
	/**
	 * @ignore
	 */
	var $primaryKey			= "id";
	

	/**
	 * @ignore 
	 */
	var $order_sql			= "";
	
	/**
	 * @ignore
	 */
	var $limit_sql			= "";
	
	var $noLimit			= false;
	/**
	 * @ignore
	 */
	var $limit_len			= 30;

	/**
	 * @ignore
	 */
	var $returnFlds			= "*";
	
	/**
	 * @ignore
	 * 所有字段,他是 $publicFld的元素值 和 $privateFld的鍵名,以及sql where子句中出現的字段名  的合集
	 */
	var $totalFld			= array();

	/**
	 * @ignore
	 * 公共字段,在多個數據表中使用
	 */
	var $publicFld			= array();
	
	/**
	 * @ignore
	 * 私有字段,僅在個別數據表中
	 */
	var $privateFld			= array();

	/**
	 * @ignore
	 */
	var $where				= "";

	var $conditions			= array(
								'type'	=> 'group',
								'name'	=> 'root',
								'logic'	=> ' AND ',
								'level'	=> 0,
								'member'=> array()
							  );
	var $conditionIndex		= array();
	var $currentGroup		= null;
	var $selectOrd			= array();
	
	var $save;
	
	/**
	 * 當 調用 $this->condition() 和 其它設置條件的 函數時,如果沒有指定 數據表,則使用此變量,說明設置的條件 作用的數據表
	 *
	 * @var unknown_type
	 */
	var $currentTable		= array();

// private function =============================================
	
	
	function setFld($fldList)
	{
		# 清空變量
		$this->totalFld=array();
		$this->privateFld=array();
		$this->publicFld=array();
		
		if(!is_array($fldList))
			$fldList=array($fldList);

		foreach ($fldList as $key=>$item)
		{
			if(!is_array($item))
				$this->totalFld[]=$this->publicFld[]=$item;
			else
			{
				$this->totalFld[]=$key;
				$this->privateFld[$key]=$item;
			}	
		}

	}

	function getFld($table)
	{
		if( $this->publicFld == '*' )
			return $this->returnFlds='*';
		if( count($this->publicFld)==1 and $this->publicFld[0]=='*' )
			return $this->returnFlds='*';
		
		# 共有字段
		$pubFlds = array();
		foreach ($this->publicFld as $item)
			$pubFlds[] = "`$item`";
		
		
		# 分別私有字段
		$spFlds = array();
		foreach ($this->privateFld as $key=>$item)
		{

			if( in_array($table,$item) or $table==$this->tempTableName)
				$spFlds[] = "`{$key}`";
			elseif( (is_array($this->dbtable) and count($this->dbtable)>1) )
				$spFlds[] = "'' as `{$key}'";
			else
				continue;
		}
		
		// 合併 公共字段
		$flds = array_merge($pubFlds,$spFlds);

		// 合並共有和私有字段,並返回		
		return $this->returnFlds=implode(",",$flds);
			
			
			
		/*# 分別私有字段
		$spFlds='';
		foreach ($this->privateFld as $key=>$item)
		{

			if( in_array($table,$item) or $table==$this->tempTableName)
				$spFlds.=(empty($spFlds)?null:',').'`'.$key.'`';
			elseif( (is_array($this->dbtable) and count($this->dbtable)>1) )
				$spFlds.=(empty($spFlds)?null:',')."'' as `".$key.'`';
			else
				continue;
		}

			
		
		// 合併 公共字段
		$pubFlds="`".implode("`,`",$this->publicFld)."`";

		// 合並共有和私有字段,並返回
		if( !empty($pubFlds) and !empty($spFlds))
			return $this->returnFlds=$pubFlds.','.$spFlds;
		else
			return $this->returnFlds=$pubFlds.$spFlds;		*/
		
	}

	# 如果存在 私有 字段,在數據庫中 創建一個臨時表,以便于 union 查詢時,使用相同的 field list
	function createTempTable_4_union()
	{
		if(count($this->privateFld))
		{
			// 獲得條件子句中的 字段
			if(preg_match_all("/`([^`]+)`[^\.]?/",$this->make_where(),$regr))
			{
				
				foreach ($regr[1] as $item)
				{
					if( !in_array($item,$this->totalFld) )
						$this->totalFld[]=$item;
				}
			}

			$this->tempTableName='tmp_table4union_'.(rand(0,10000)*rand(0,10000));
			$creat_Temp="CREATE TEMPORARY TABLE {$this->tempTableName} (";
			foreach ($this->totalFld as $key=>$fn)
			{
				if($key>0)
					$creat_Temp.=',';
				$creat_Temp.="\n`{$fn}` text NOT NULL";
			}
			$creat_Temp.="\n);";
			$this->Execute_SQL( __FUNCTION__ , $creat_Temp );
			return array_merge(array($this->tempTableName),$this->dbtable);
		}
		else
			return $this->dbtable;
	}
	
	
	function ifIgnoreCondition($value)
	{
		if( $value=='' or $value=='-ignore-' )
			return true;
		else
			return false;
	}
	/**
	 * @ignore
	 */
	function condition( $sql,$table=array() )
	{
		$sql = trim($sql);
		if( empty( $sql ) )
			return ;

		if( !empty($this->currentTable) )	// 使用全局屬性
			$table=$this->currentTable;
		
		if( empty($table) )					//  如果未指定 參數 $table 和 $this->currentTable ,則該條件 作用于全部 數據表
			$table=$this->dbtable;

		$this->currentGroup['member'][] = array(
			'type'	=> 'condition',
			'table'	=> $table,
			'sql'	=> ' ( '.$sql.' ) '
		);
	}

	function get_where( $table = null )
	{
		$where=$this->make_where( null,$table );

		if( empty($where) )
			$where="1";
		
		return $where;
	}

	function make_where($group=null,$table=null)
	{
		($group===null)?$group=$this->conditions:null;				// 如果未指定條件組,則使用全部

		if( count($group['member'])==0 )
			return '';

		$cds=array();
		foreach ( $group['member'] as $theMmb )
		{
			// 條件組成員
			if( $theMmb['type'] == 'group' )
			{
				if( ( $w=$this->make_where($theMmb) )=='' )			// 遞歸獲得 條件組成員 的 where子句
					continue;										// 如果此 條件組成員 返回的 子句爲空,則忽略次成員
				
				$cds[] = $w;
			}

			// 條件成員
			else
			{
				if( empty($theMmb['sql']) )
					continue;
	
				if( $table and !in_array($table,$theMmb['table']) )	// 該條件 不可用于 指定的數據表
					continue;
				
				
				$cds[]=$theMmb['sql'];
			}
		}
		
		if( !count($cds) )		// 返回空值
			return '';

		$rstr = "\r\n";
		$rstr.= "\r\n" . str_repeat("\t",$group['level']) . "-- Condition Group: \"{$group['name']}\" Start --";
		$rstr.= "\r\n(\r\n";
		$rstr.= implode( $group['logic'],$cds );
		$rstr.= "\r\n)\r\n";
		$rstr.= "\r\n" . str_repeat("\t",$group['level']) . "-- Condition Group: \"{$group['name']}\" Over --";
		$rstr.= "\r\n";

		return $rstr;
	}

	/**
	 * 獲取相關記錄數
	 *
	 * @param	string		$type		返回類型:"total"
	 * @return	integer
	 */
	function getCnt($type="total")
	{
		$cnt=0;

		$tablebac=$this->dbtable;
		foreach($this->dbtable as $table)
		{			
			$this->make_sql($this->primaryKey,true,$table);
			$re = $this->Execute_SQL( __FUNCTION__ );
			$arr=@mysql_fetch_assoc($re);
			$cnt+=intval($arr["queryResultCnt"]);
		}

		
		if($cnt!=="")
		{
			$result=intval($cnt);
			if( $type=="thisPge" and $result>$this->limit_len )
				return $this->limit_len;
			else
				return $result;
		}
		else
			return -1;

	}

//	# 檢驗一個字段是否存在
//	function field_exists($table)
//	{
//		$r=mysql_query("select * from `$table` limit 0,1");
//		
//		mysql_field_name($r);
//	}
// public function =============================================

	/**
	 * 構造函數,初始化一些屬性
	 *
	 * @param	string、array	$dbtable			需查詢的數據表,如果使用array類型變量傳遞多個數據表,則make_sql()函數將使用union 進行聯合查詢
	 * @param	unknown_type 	[$logic]			查詢邏輯,true 爲匹配,false 爲過濾
	 * @param	unknown_type 	[$primaryKey]		數據表主鍵鍵名
	 * @return	void
	 */
	function Query($dbtable="post",$logic=true,$primaryKey="id")
	{
		$this->dbtable=$dbtable;
		if( !is_array($this->dbtable) )
			$this->dbtable=array($this->dbtable);
		
		$this->logic=$logic;
		$this->primaryKey=$primaryKey;

		// 初始化 條件組 索引
		$this->clearCondition();
	}


	/**
	 * 設置 "字段='值'" 類型的直接條件,可一次設置多個條件,可重複調用,直到使用get_result()
	 * 
	 * 用例:
	 * <code># 網頁上有多個 表單:
	 * <form>查詢條件:<br>
	 * 作者:<input name="directCondition[author]" type="text">
	 * 欄目:<select name="directCondition[class]">
	 * 	<option value="class1">時事政治</option>
	 * 	<option value="class2">焦點訪談</option>
     * </select>
	 * </form>
	 * ..
	 * # 服務器接受查詢的 php 腳本:
	 * <?
	 * $q=new Query("news");
	 * $q->directCondition($_POST["directCondition"]);
	 * $a=$q->get_result();
	 * dump_var($a);
	 * ?>
	 * </code>
	 *
	 * @param	array		$Condition		數組的鍵名作爲條件的字段名,數組的元素值爲條件的值
	 * @param	string		$logic			多個條件之間的邏輯關系
	 * @param 	boolean		$ingEmpty		是否忽略空值的數組元素
	 * @return	void
	 */
	function directCondition($Condition,$logic=" AND ",$ingEmpty=true,$field='')
	{
		if( !is_array($Condition) )
			exit("Query::directCondition 的參數 \$Condition 必須爲數組。<br>");
		
		if($this->logic)
			$operator="=";
		else
			$operator="!=";

		$thisC="";
		foreach ($Condition as $fld=>$value)
		{
			if(!empty($field))
				$fld=$field;

			if( $ingEmpty and $this->ifIgnoreCondition($value) )
				continue;

			if($thisC)
				$thisC.=" $logic ";

			$thisC.="(`$fld` $operator '$value')";
		}
		
		if(empty($thisC))
			$thisC='1';

		$this->condition($thisC);
		return $thisC;

	}

	
	/**
	 * 設置全文匹配 like 字句
	 *
	 * 用例1:在文章正文字段`txt`中查詢“外灘”:
	 * <code>$q->set_like(array("txt"=>"外灘"))</code>
	 * 用例2:在文章正文字段`txt`中查詢“外灘”或“淮海路”
	 * <code>$q->set_like(array("外灘","淮海路")," or ","txt")</code>
	 * 
	 * @param 	array	$Condition		數組,每個元素采用:"字段名"=>"條件值",可設置多個like子句
	 * @param 	string	[$logic]		各 like 子句之間的邏輯值
	 * @param 	string	$feild			若$Condition 需要在同一個字段設置多個like子句,則此參數說明爲何字段,它將導致$Condition 裏的鍵名沒有作用
	 */
	function set_like($Condition,$logic=" AND ",$feild="")
	{
		if( !is_array($Condition) )
			exit("Query::set_like 的參數 \$Condition 必須爲數組。<br>");

		if($this->logic)
			$operator="LIKE";
		else
			$operator="NOT LIKE";

		$thisC="";
		foreach ($Condition as $fld=>$value)
		{
			if( empty($value) )
				continue;

			if($thisC)
				$thisC.=" $logic ";
			
			if(empty($feild))
				$thisC.="(`$fld` $operator '%$value%')";
			else
			{
				if(is_array($feild))
					$thisC.="(`{$feild[$fld]}` $operator '%$value%')";
				else
					$thisC.="(`$feild` $operator '%$value%')";
			}
		}

		$this->condition($thisC);

	}
	
	
	/**
	 * 設置 RegExp 字句
	 * 
	 * @param 	array	$Condition		數組,每個元素采用:"字段名"=>"條件值(正則表達式)",可設置多個like子句
	 */
	function set_regexp($Condition)
	{
		if( !is_array($Condition) )
			exit("Query::set_like 的參數 \$Condition 必須爲數組。<br>");

		if($this->logic)
			$operator="REGEXP";
		else
			$operator="NOT REGEXP";

		$thisC="";
		foreach ($Condition as $fld=>$value)
		{
			if($thisC)
				$thisC.=" {$this->logic} ";

			$thisC.="(`$fld` $operator '%$value%')";
		}
		
		$this->condition($thisC);

	}
	
	
	
	/**
	 * 設置關鍵詞
	 *
	 * 多個關鍵詞之間可用參數 $keyworlds_logic 來指明邏輯關系;被查詢的字段之間爲邏輯或關系,即一個關鍵詞在其中任何一個字段中出現,即符合條件。
	 * 用例,在軟件下載系統中查詢"windows 2000":<code>$q->set_keyworld(array("windows","2000","下載"),array("softIntro","softTitle"),"and");</code>
	 *
	 * @param	array		$keyworlds				關鍵詞,必須爲數組,可設置多個
	 * @param	array		$keyworlds4flds			關鍵詞將在被用于查詢的字段,必須爲數組
	 * @param	string		$keyworlds_logic		關鍵詞之間的邏輯關系
	 */
	function set_keyworld($keyworlds,$keyworlds4flds,$keyworlds_logic="or")
	{
		if( !is_array($keyworlds) or !is_array($keyworlds4flds) )
			exit("Query::set_keyworld 的參數 \$keyworlds,\$keyworlds4flds 必須爲數組。<br>");
		
		if($keyworlds_logic!="or" and $keyworlds_logic!="and")
			exit("Query::set_keyworld 的參數 \$keyworlds_logic 必須爲 \"or\" 或 \"and\"。$keyworlds_logic<br>");
	
		if($this->logic)
			$operator="LIKE";
		else
			$operator="NOT LIKE";

		$thisC="";
		foreach($keyworlds as $thekey)
		{
			if(!empty($thisC))
				$thisC.=" {$keyworlds_logic} ";
			
			$thisC.="( ";
			
			$thisFldSql="";
			foreach($keyworlds4flds as $theFld)
			{
				if( !empty($thisFldSql) )
					$thisFldSql.=" or ";
				
				$thisFldSql.="(`$theFld` $operator '%$thekey%')";
				
			}
			
			$thisC.=$thisFldSql." )";
		}
		
		$this->condition($thisC);

	}
	
	/**
	 * 設置 整數或浮點 字段條件
	 *
	 * 用例:字段`id`大于等于10的記錄
	 * <code>$q->mathCondition(array("id"=>"10"),">=")</code>
	 *
	 * @param 	array		$Condition		數組,每個元素采用:"字段名"=>"條件值",可設置多個條件
	 * @param 	string		$type			條件類型,可以有以下選擇:“<”、“>”、“=”、“<=”、“>=”
	 * @param 	string		[$logic]		多個條件之間的邏輯關系
	 */
	function mathCondition($Condition,$type,$logic=" AND ",$column='')
	{
		if( !is_array($Condition) )
			exit("Query::mathCondition 的參數 \$Condition 必須爲數組。<br>");
		if(!is_array($type))
			$type=array($type);

		$thisC="";
		$idx=0;

		foreach ($Condition as $fld=>$value)
		{
			if( preg_match('/^\d*$/',$fld) )
				$fld=$column;

			if( $type[$idx]!="<" && $type[$idx]!="<" && $type[$idx]!="=" && $type[$idx]!="<=" && $type[$idx]!=">=")
				exit("Query::mathCondition 的參數 \$type 必須爲:“<”、“>”、“=”、“<=”、“>=”。<br>");

			if(!$this->logic)		// 過濾
			{
				switch($type[$idx])
				{
					case "<":
						$operator=">=";
						break;
					case ">":
						$operator="<=";
						break;
					case "=":
						$operator="!=";
						break;
					case ">=":
						$operator="<";
						break;
					case "<=":
						$operator=">";
						break;
				}
			}
			else				// 匹配
				$operator=$type[$idx];
			

			if($thisC)
				$thisC.=$logic;

			$thisC.="(`$fld` $operator $value)";
			$idx++;
		}
		
		$this->condition($thisC);

	}
	

	/**
	 * 設置“10-100”格式的範圍條件
	 * 
	 * 參數 $value 的格式 可以爲以下三種類型:“數字-”,“-數字”,“數字-數字”。
	 * <code>// `id` 大于 10 的記錄
	 * $q->areaCondition("id","10-");
	 * 
	 * // `id` 小于 100 的記錄
	 * $q->areaCondition("id","-100");
	 * 
	 * // `id` 大于 10,小于 100 的記錄
	 * $q->areaCondition("id","10-100");
	 * </code>
	 * 
	 * @param	string		$fld	查詢的字段名
	 * @param	string		$value	範圍,必須爲 "[數字]-[數字]" 格式
	 * @return	boolean				當參數無效時,返回false,否則無論查詢結果如何,由此産生的sql是否正確,均返回true,僅表示條件設置成功
	 */
	function areaCondition($condition,$value='')
	{
		if(!is_array($condition))
			$condition=array($condition=>$value);
		
		foreach ($condition as $fld=>$value)
		{
			if( $this->ifIgnoreCondition($value) )
				continue;

			if( isset($value) and preg_match("/^(\d+\-\d+)|(\d+\-)|(\-\d+)$/",$value) )
			{
				$value=explode("-",$value);

				# 類如 20-63,則取20到63只閒的值
				if( $value[0]!=='' and $value[1]!=='' and  $value[0]<=$value[1] )
					$this->mathCondition(array($value[0],$value[1]),array(">=","<=")," and ",$fld);
				# 類如 23-14,則取 負無窮到14,23到正無窮的合集
				elseif ($value[0]!=='' and $value[1]!=='' and  $value[0]>$value[1])
					$this->mathCondition(array($value[0],$value[1]),array(">=","<=")," or ",$fld);
				elseif ($value[0]==='' and $value[1]!=='')
				# 類如 -45 ,則取45以下的集合
					$this->mathCondition(array($fld=>$value[1]),"<=");
				elseif ($value[0]!=='' and $value[1]==='')
				# 類如 65- ,則取65以上的集合
					$this->mathCondition(array($fld=>$value[0]),">=");
	
			}
			else
				return false;
		}
		
		return true;
	}

	function set_where($sql)
	{
		$this->condition( $sql );
	}

	/**
	 * 設置 返回記錄的排列方式,及設置 ORDER BY 子句
	 *
	 * @param 	string		$fld		按照哪一個字段來排列
	 * @param 	string		$order		排列順序,缺省爲有小到大,或使用“desc”有大到小
	 */
	function set_order($fld="id",$order="")
	{
		if( is_array($fld) )
			$fld = implode( '`,`', $fld ) ;
		$this->order_sql=" ORDER BY `$fld` $order";
	}

	/**
	 * 設置 LIMIT 子句,通常是爲了實現分頁,Query 中有專門設施分頁的函數 set_page()
	 *
	 * @param 	integer		[$len]		返回長度,用作limit 字句中第二個參數
	 * @param 	integer		[$start]	其實記錄數,從零開始,用作limit 字句中第一個參數
	 * @see 	set_page()
	 */
	function set_limit($len=1,$start=0)
	{
		$this->limit_len=$len;
		$this->limit_sql="LIMIT $start,{$this->limit_len}";
	}
	
	/**
	 * 設置分頁 及當前頁碼,它通過 SQL 的 LIMIT 子句實現
	 *
	 * @param 	integer		$recordPerPge		每頁記錄數
	 * @param 	integer		[$pgeNum]			當前第幾頁
	 * @see 	set_limit()
	 */
	function set_page($recordPerPge,$pgeNum=1)
	{
		$start=$recordPerPge*($pgeNum-1);
		$len=$recordPerPge;
		$this->limit_sql="LIMIT $start,$len";
	}

	/**
	 * 查詢並返回結果集,它返回三種形式的結果:數組、xml、serialize()序列化以後的數組
	 *
	 * 如果第三個參數采取默認值,則返回二維數組,僅包含元素[records]的內容,記錄集結構如下
	 * <code>	array(
	 * 		[0]	=>array(
	 * 				[field1]=>"",
	 * 				[field2]=>"",
	 * 				[field3]=>"",
	 * 				[field4]=>""
	 * 		),
	 * 		[1]	=>array(
	 * 				[field1]=>"",
	 * 				[field2]=>"",
	 * 				[field3]=>"",
	 * 				[field4]=>""
	 * 		),
	 * 		……
	 * 	)
	 * </code>
	 * 如果第三個參數爲 true ,則返回三維數組,第一維包含四個元素:
	 * 	[records]		(或第四個參數指定的鍵值)記錄集;
	 * 	[totalCnt]		記錄總數;
	 * 	[thisPgeCnt]	當前分頁記錄數;
	 * 	[totalPgeCnt]	分頁總數
	 *
	 * @param	array、string		[$returnFlds]				需返回的字段
	 * @param	string				[$returnType]				返回值類型:"array","xml","serialize"
	 * @param	string				[$returnKey]				如果返回記錄數量,記錄集的鍵值,或返回 xml 結構中
	 * @return	array,string(xml),string(array serialize)		返回數組、xml格式字串、serialize()序列化數組後的字串
	 */
	function get_result(&$result_set,$returnFlds=array("*"),$returnType="array")
	{
		$this->make_sql($returnFlds);							// 产生sql
		$result=$this->Execute_SQL(__FUNCTION__,$this->sql);	// 执行查询
		
		$result_set=array();
		while($array=mysql_fetch_assoc($result))
		{
			if(!empty($returnKey) and $ifCnt)
				$result_set[$returnKey][]=$array;
			else
				$result_set[]=$array;
		}														// 获得数据集
		
		switch ($returnType)
		{
			case "xml":
				$returnxml="<?xml version=\"1.0\" encoding=\"gb2312\"?>\n<postCollection>\n";				
				foreach($result_set as $thepost)
				{
					$returnxml.="\t</post>\n";					
					foreach ($thepost as $fld=>$value)
						$returnxml.="\t\t<$fld>$value</$fld>\n";					
					$returnxml.="\t</post>\n";
				}	
				$returnxml.="</postCollection>";				
				$result_set = $returnxml;
				break;
			
			case "serialize":
				$result_set = serialize($result_set);
				break;				
			default:
				
				break;
		}
		
		$return["totalCnt"]=$this->getCnt("total");
		$return["thisPgeCnt"]=count( $result_set );
		$return["totalPgeCnt"]=ceil( $return["totalCnt"] / $this->limit_len );
		
		return $return;		
	}
	
	/**
	 * dateCondition 設置日期條件
	 *
	 * param 	string、array		$startTime		開始時刻  格式:"2005-9-24 12:55:12" 或 array([y]=>2005,[m]=>9,[d]=>24,[G]=>12,[i]=>55,[s]=>12) 年月日時分秒 各參數均可省略,第一種形式 可滿足用戶 在 文本框中 直接填寫日期,第二種 形式,可滿足用戶通過下拉菜單填寫日期
	 * param 	string、array		$endTime		結束時刻  各式同 $startTime
	 */
	function dateCondition($field,$startTime,$endTime='')
	{
		if(!is_array($startTime) )
		{
			if( preg_match("/^\d{10}$/i",$startTime) )
				$startTime = date('Y-m-d G:i:s',$startTime);

			if( !preg_match("/^((\d{4})(\-(\d{1,2})(\-(\d{1,2})( (\d{1,2})(:(\d{1,2})(:(\d{1,2}))?)?)?)?)?)?$/",$startTime,$r) )
				exit("Query::dateCondition()函數的參數必須為數組、2004-6-24 23:12:24 格式字符串、或Unix 时间戳。");
		
			$startTime=array(
				'y'=>@$r[2],
				'm'=>@$r[4],
				'd'=>@$r[6],
				'G'=>@$r[8],
				'i'=>@$r[10],
				's'=>@$r[12],
			);
		}
		
		if(!is_array($endTime) )
		{
			if( preg_match("/^\d{10}$/i",$endTime) )
				$endTime = date('Y-m-d G:i:s',$endTime);

			if( !preg_match("/^((\d{4})(\-(\d{1,2})(\-(\d{1,2})( (\d{1,2})(:(\d{1,2})(:(\d{1,2}))?)?)?)?)?)?$/",$endTime,$r) )
				exit("Query::dateCondition()函數的參數必須為數組、2004-6-24 23:12:24 格式字符串、或Unix 时间戳。");
		
			$endTime=array(
				'y'=>@$r[2],
				'm'=>@$r[4],
				'd'=>@$r[6],
				'G'=>@$r[8],
				'i'=>@$r[10],
				's'=>@$r[12],
			);
		}
		
		if( empty($startTime['y']) )
			$st='';
		elseif ( empty($startTime['m']) )
			$st=mktime(0,0,0,0,0,$startTime['y']);
		elseif ( empty($startTime['d']) )
			$st=mktime(0,0,0,$startTime['m'],0,$startTime['y']);
		elseif ( empty($startTime['G']) )
			$st=mktime(0,0,0,$startTime['m'],$startTime['d'],$startTime['y']);
		elseif ( empty($startTime['i']) )
			$st=mktime($startTime['G'],0,0,$startTime['m'],$startTime['d'],$startTime['y']);
		elseif ( empty($startTime['s']) )
			$st=mktime($startTime['G'],$startTime['i'],0,$startTime['m'],$startTime['d'],$startTime['y']);
		else
			$st=mktime($startTime['G'],$startTime['i'],$startTime['s'],$startTime['m'],$startTime['d'],$startTime['y']);
		
		if( empty($endTime['y']) )
			$et='';
		elseif ( empty($endTime['m']) )
			$et=mktime(23,59,59,12,30,$endTime['y']);
		elseif ( empty($endTime['d']) )
			$et=mktime(23,59,59,$endTime['m'],30,$endTime['y']);
		elseif ( empty($endTime['G']) )
			$et=mktime(23,59,59,$endTime['m'],$endTime['d'],$endTime['y']);
		elseif ( empty($endTime['i']) )
			$et=mktime($endTime['G'],59,59,$endTime['m'],$endTime['d'],$endTime['y']);
		elseif ( empty($endTime['s']) )
			$et=mktime($endTime['G'],$endTime['i'],59,$endTime['m'],$endTime['d'],$endTime['y']);
		else
			$et=mktime($endTime['G'],$endTime['i'],$endTime['s'],$endTime['m'],$endTime['d'],$endTime['y']);
			
		$this->areaCondition($field,"$st-$en");
	}

	/**
	 * 組裝 SQL 語句,get_result(),getCnt() 會首先調用此函數獲得sql
	 *
	 * @param	array、string	$returnFlds		需要返回的字段,多個字段可用數組,單個字段可用字串
	 * @param	boolean			$getCnt			是否僅返回記錄數,此參數將導致參數 $returnFlds 無效
	 * @param	string			$table			當 $getCnt = true 時 此參數有效,說在返回 那一個 數據表的 記錄數
	 * @return	string							返回一個sql語句
	 */
	function make_sql($returnFlds=array("*"), $getCnt=false, $table='')
	{

		$this->setFld($returnFlds);

		if($getCnt)
		{
			if( empty($table) )
				$table = $this->dbtable[0];

			$where = $this->get_where( $table );			

			return $this->sql="\r\n-- In table `{$table}` \r\nSELECT count(`{$this->primaryKey}`) as `queryResultCnt` FROM `{$table}` WHERE {$where}";
		}
		else
		{
			if( !$this->noLimit and empty($this->limit_sql) )
				$this->set_page(30);

			if( count($this->dbtable) > 1 )
			# 多個數據表  利用 union 聯合查詢
			{
				$this->sql="";

				$dbtable=$this->createTempTable_4_union();

				foreach($this->dbtable as $theTab)
				{
					$where = $this->get_where($theTab);

					if(!empty($this->sql))
						$this->sql.="\nUNION\n";

					$this->getFld($theTab);

					$this->sql.="(\r\n-- In table `{$theTab}` \r\nSELECT {$this->returnFlds} FROM `{$theTab}` WHERE {$where}\n)";

				}
				
				$this->sql.="\n{$this->order_sql} {$this->limit_sql}";
			}
			else
			# 單一數據表查詢
			{
				$where = $this->get_where( $this->dbtable[0] );

				$this->getFld( $this->dbtable[0] );
				$this->sql="\r\n-- In table `{$this->dbtable[0]}` \r\nSELECT {$this->returnFlds} FROM `{$this->dbtable[0]}` WHERE {$where} {$this->order_sql} {$this->limit_sql}";
			}

			return $this->sql;
		}
	}


	function addGroup($name=null,$logic=' or ')
	{
		if( $name==null )
			$name='ConditionGroup_'.( count( $this->conditionIndex )+1 );

		if( key_exists($name,$this->conditionIndex) )
		{
			print "\r\n<br />".__CLASS__."::".__FILE__."() 遇到錯誤:名爲 {$name} 的條件組已經存在,不能創建名稱相同的條件組。\r\n<br \>";
			exit();
		}

		$new_grp=array(
			'type'	=> 'group',
			'name'	=> $name,
			'logic'	=> strtoupper($logic),
			'level'	=> $this->currentGroup['level'] + 1,
			'member'=> array()
		);

		$this->currentGroup['member'][$name] = $new_grp;

		// 注冊新增的條件組
		$this->conditionIndex[$name] = &$this->currentGroup['member'][$name];

		// 設置爲 當前條件組
		$this->select_group($name);
		
	}
	
	function select_group($name)
	{
		if( !isset($this->conditionIndex[$name]) )
		{
			print "\r\n<br />".__CLASS__."::".__FILE__."() 遇到錯誤:制定的條件組 {$name} 尚未創建。\r\n<br \>";
			exit();
		}
		
		$this->currentGroup = &$this->conditionIndex[$name];
		
		
		// 重設當前使用 條件組 的路徑
		if( ( $idx=array_search($name,$this->selectOrd) )!==false )
			$this->selectOrd = array_slice($this->selectOrd,0,$idx+1);
		else
			$this->selectOrd[]=$name;
	}
	
	function back()
	{
		if( count( $this->selectOrd )>1 )
		{
			array_pop( $this->selectOrd );
			$name = end($this->selectOrd);
			$this->currentGroup = &$this->conditionIndex[$name];
			
			return true;
		}
		else
			return false;
	}
	
	function today($fld)
	{
		$start=mktime( 0,0,0,date('m'),date('d'),date('Y') );
		$end=mktime( 23,59,59,date('m'),date('d'),date('Y') );

		$sql=" `$fld` >= '$start' and `$fld` <= '$end' ";
		$this->condition($sql);
	}
	
	function setCurTable()
	{
		$this->currentTable = func_get_args();
	}
	function clearCurTable()
	{
		$this->currentTable = array();
	}
	
	function Execute_SQL( $function = null , $sql = null )
	{
		if( empty($sql) )
			$sql = $this->sql ;		
		
		if( $re=mysql_query($sql) )
			return $re;
		else
		{
			print __CLASS__.'::'.__FUNCTION__."() 函數在執行一條".(empty($function)?'':'由'.__CLASS__."::{$function}()函數傳遞的 ")." SQL 語句時遇到錯誤:".mysql_error()."\r\n\r\n<br /><br />正在執行的 SQL 爲:\r\n<br />".$sql;
			exit();
		}
	}
	
	function setGroupLogic($logic=' OR ',$group=null)
	{
		if( empty($group) )
			$group=&$this->currentGroup;
		else
			$group=&$this->conditionIndex[$group];
		
		$group['logic']=strtoupper($logic);
	}
	
	
	
	function clearCondition()
	{
		$this->conditions=array(
			'type'	=> 'group',
			'name'	=> 'root',
			'logic'	=> ' AND ',
			'level'	=> 0,
			'member'=> array()
		);
		$this->conditionIndex	= array( 'root'=>& $this->conditions );
		$this->currentGroup		= & $this->conditions;
		$this->selectOrd		= (array)'root';
		
		$this->order_sql='';
		$this->limit_sql='';
		$this->privateFld=array();
		$this->publicFld=array();
		$this->totalFld=array();
		$this->tempTableName='';
		$this->sql='';
	}
	
	function save()
	{
		$this->save = serialize($this) ;
	}
	
	function revert()
	{
		$this = unserialize($this->save) ;
	}

}


$Query_class_declare=true;
?>