<? /** * 文件數據庫函數 * 約定: * 數據庫名為同名目錄 * 數據表名后綴為 tab * 索引文件后綴為 ind * 管理文件名為 數據庫同名目錄/manage.ini * 備注型字段以獨立文件存在,表中保留文件名 * 字段以定長方式或csv方式保存,由管理文件指定 * 每行一條記錄 * 索引文件以二進制方式包存鍵值(定長)和偏移量(長整型) *
** 函數列表(前面有:+ 為已實現,- 為部分實現,其余為尚未實現) 套用 MySQL 函數集 取名 FILE_DB
* file_affected_rows: 得到 FILE_DB 最后操作影響的列數目。 *-file_close: 關閉 FILE_DB 服務器連接。 * file_connect: 打開 FILE_DB 服務器連接。 *+file_create_db: 建立一個 FILE_DB 新數據庫。 * file_data_seek: 移動內部返回指針。 * file_db_query: 送查詢字符串 (query) 到 FILE_DB 數據庫。 * file_drop_db: 移除數據庫。 * file_errno: 返回錯誤信息代碼。 * file_error: 返回錯誤信息。 *+file_fetch_array: 返回數組資料。 * file_fetch_field: 取得字段信息。 * file_fetch_lengths: 返回單列各欄資料最大長度。 * file_fetch_object: 返回類資料。 *+file_fetch_row: 返回單列的各字段。 *+file_field_name: 返回指定字段的名稱。 * file_field_seek: 配置指針到返回值的某字段。 * file_field_table: 獲得目前字段的資料表 (table) 名稱。 * file_field_type: 獲得目前字段的類型。 * file_field_flags: 獲得目前字段的標志。 * file_field_len: 獲得目前字段的長度。 * file_free_result: 釋放返回占用內存。 * file_insert_id: 返回最后一次使用 INSERT 指令的 ID。 * file_list_fields: 列出指定資料表的字段 (field)。 * file_list_dbs: 列出 FILE_DB 服務器可用的數據庫 (database)。 * file_list_tables: 列出指定數據庫的資料表 (table)。 *+file_num_fields: 取得返回字段的數目。 *+file_num_rows: 取得返回列的數目。 * file_pconnect: 打開 FILE_DB 服務器持續連接。 *-file_query: 送出一個 query 字符串。 * file_result: 取得查詢 (query) 的結果。 * file_select_db: 選擇一個數據庫。 * file_tablename: 取得資料表名稱。 */
/** * * $cmp_key;
/** 連結至 FILE_DB 資料庫 * @param 數據庫名 */ function &file_connect($dbname) { $filename = $dbname."/manage.ini"; if(!file_exists($filename)) die("數據庫:$dbnamee不存在"); $fp = fopen($filename,"r"); $s = fgets($fp,filesize($filename)+1); fclose($fp); $db = unserialize($s); return $db; }
/** 關閉 FILE_DB 連結 * */ function file_close(&$connection_id) { unset($connection_id); }
/** 建立 FILE_DB 數據庫 * @param 數據庫名 */ function file_create_db($dbname) { if(! @mkdir($dbname,0700)) $err = "目錄已存在"; $filename = $dbname."/manage.ini"; $ar[path] = "$dbname/"; $s = serialize($ar); $fp = fopen($filename,"w"); fputs($fp,$s); fclose($fp); }
/** 執行 SQL 指令 * */ function file_query($query,&$connection_id,$_line = __LINE__) { // 解析 $query $query = eregi_replace("[ ]+"," ",$query); $ar = split(" ",trim(str_replace(""," ",$query))); $query = eregi_replace("\r?\n","",$query); $ch = each($ar); switch(strtoupper($ch[1])) { case "CREATE": if(! eregi("create table (.+) [(] *(.+)[)] *$",$query,$pp)) die("SQL表達式錯,$_line"); $table = $pp[1]; if(empty($connection_id[$table])) { // 解析字段表達式 $ar = split(",",$pp[2]); while(list($key,$value) = each($ar)) { $str = split(" ",trim($value)); eregi("([a-z0-9]+) ([a-z]+) ?([(]([0-9]+)[)])?(.+)?",$value,$pp); $field[name] = $pp[1]; $field[type] = $pp[2]; $field[len] = $pp[4]; $field[style] = trim($pp[5]); $sss[] = $field; } $connection_id[$table] = array( "fields" => $sss, "filename" => $table.".tab", "type" => "CSV" ); } $fp = fopen($connection_id[path]."manage.ini","w"); fputs($fp,serialize($connection_id)); fclose($fp); break; case "SELECT": if(! eregi("select (.+) from ([^ ]+) *(.+)*$",$query,$pp)) die("SQL表達式錯,$_line");
// 解析SQL語句的控制部分 $exte = $pp[3]; if(! eregi("where ",$exte)) $exte = "where true ".$exte; if(! eregi("order ",$exte)) $exte .= "order by 0"; if(! eregi("group ",$exte)) $exte = eregi_replace("order ","group by _ order ",$exte); eregi("where (.+) *group by (.+) order by (.+)",$exte,$regs); $filter = trim($regs[1]); $group = trim($regs[2]); $order = trim($regs[3]); if($group == "_") $group = ""; if($order == "0") $order = ""; // 讀取數據文件 if(empty($connection_id[$pp[2]])) die("表".$pp[2]."不存在"); $table = $connection_id[$pp[2]]; if(!file_exists($connection_id[path].$table[filename])) { // 數據表尚未建立 return false; }else { // 獲取表定義字段名 for($i=0;$i<count($table[fields]);$i++) $defaultfield[] = $table[fields][$i][name]; $defaultfield = array_flip($defaultfield);
// 解析篩選表達式 if($filter != "true") { $filter = eregi_replace(" and "," && ",$filter); $filter = eregi_replace(" or "," || ",$filter); $filter = eregi_replace("=","==",$filter); $filter = eregi_replace("==>","=>",$filter); $filter = eregi_replace("<==","<=",$filter); $filter = eregi_replace("===","==",$filter); while (ereg ('([a-z][a-z0-9_]*)', $filter, $regs)) { $found = $regs[1]; $filter = eregi_replace("$found","[". $defaultfield][$found]."]", $filter); } $filter = eregi_replace("\[","\$tmp][",$filter); $filter = "\$key=($filter);"; }else $filter ="";
// 裝入數據 $fp = fopen($connection_id][path].$table[filename],"r"); $key = true; while($tmp = fgetcsv($fp,4096,"`")) { if(!empty($filter)) eval($filter); if($key) $temp[] = $tmp; } fclose($fp); } // 解析輸出字段 $f = split(",",$pp[1]); $expr = ""; while(list($key,$value) = each($f)) { if(eregi("(.+)[(](.+)[)]( as (.+))?",$value,$pp)) { // 有函數 switch(strtoupper($pp[1])) { case "COUNT": if(empty($pp[4])) $n = "cnt"; else $n = $pp[4]; $expr .= "\$rs[$n]=1;"; $sumname[] = $n; break; } }else if(eregi("(.+) as (.+)",$value,$pp)) { // 有重命名 $n = $defaultfield[$pp[1]]; if(!isset($n)) die("字段名 $n 非法"); $expr .= "\$rs[$pp[2]]=\$temp[\$i][$n];"; }else if($value == "*") { for($i=0;$i<count($table[fields]);$i++) { $value = $table[fields][$i][name]; $expr .= "\$rs[$value]=\$temp[\$i][$i];"; } }else { $n = $defaultfield[$value]; if(!isset($n)) die("SQL error"); $expr .= "\$rs[$value]=\$temp[\$i][$n];"; } }
// 取得輸出字段列表 $i=0; eval($expr); $outfield = array_keys($rs);
// 解析分組 if($group) { $groups = split(",",$group); for($i=0;$i<count($groups);$i++) if(eregi("[0-9]+",$groups[$i])) { $n = $groups[$i]>0?$groups[$i]-1:0; $groups[$i] = $outfield[$n]; } }
// 過錄數據 for($i=0;$i<count($temp);$i++) { eval($expr); if(!$group) $result[] = $rs; else { $n = $rs[$groups[0]]; if($sumname) { for($ii=0;$ii<count($sumname);$ii++) $sumdata[$sumname][$ii]] = $result[$n][$sumname][$ii]]; $result[$n] = $rs; for($ii=0;$ii<count($sumname);$ii++) $result[$n][$sumname][$ii]] += $sumdata[$sumname][$ii]]; }else $result[$n] = $rs; } } unset($temp);
// 解析排序 if($order) { global $cmp_key; $orders = split(",",$order); for($i=count($orders)-1;$i>=0;$i--) { eregi("([0-9]+)?([a-z_][a-z0-9_]*)? *(desc)?",$orders[$i],$regs); if(!empty($regs[1])) { $n = $regs[1]-1; if($n<0) $n = 0; $cmp_key = $outfield[$n]; }else $cmp_key = $regs[2]; if(empty($regs[3])) usort($result, cmp_asc); else usort($result, cmp_desc); } } return $result; break; case "INSERT": if(! eregi("insert into table (.+) [(](.+)[)] *values? *[(](.+)[)]",$query,$pp)) die("SQL表達式錯,$_line"); if(empty($connection_id[$pp[1]])) die("表".$pp[1]."不存在"); $table = $connection_id[$pp[1]]; // 解析目標字段名 $f = split(",",$pp[2]); // 檢查字段是否合法 for($i=0;$i<count($f);$i++) if(!array_scan($table[fields],$f[$i],"name")) die("字段名非法 ".$f[$i]); // 根據表字段表構造數據數組 for($i=0;$i<count($table[fields]);$i++) $data[$table][fields][$i][name]] = ""; // 解析數據 eval("\$d=array($pp[3]);"); // 填表 for($i=0;$i<count($f);$i++) { $data[$f[$i]] = $d[$i]; } $fp = fopen($connection_id[path].$table[filename],"a"); fputs($fp,join("`",$data)."\n"); fclose($fp); break; case "UPDATE": break; default: die("錯誤的SQL指令,在".$_line."行"); }
}
/** file_fetch_row: 返回單列的各字段 * */ function file_fetch_row(&$result) { $ar = each($result); if(! $ar) return false; while(list($k,$ch) = each($ar[1])) $br[] = $ch; return $br; }
/** file_fetch_array: 返回數組資料 * */ function file_fetch_array(&$result) { $ar = each($result); if(! $ar) return false; while(list($k,$ch) = each($ar[1])) { $br[] = $ch; $br[$k] = $ch; } return $br; }
/** file_field_name: 返回指定字段的名稱 * */ function file_field_name(&$result,$n=0) { $outfield = array_keys($result[0]); return $outfield[$n]; }
/** file_num_rows: 取得返回列的數目 * */ function file_num_rows(&$result) { return count($result); }
/** file_num_fields: 取得返回字段的數目 * */ function file_num_fields(&$result) { return count($result[0]); }
/** 工作函數集 */
/** 在數組中檢索 * @param $ar 數組 * @param $val 待檢索的值 * @param $key 鍵 */ function array_scan($ar,$val,$key=0) { for($i=0;$i<count($ar);$i++) if($ar[$i][$key] == $val) return true; return false; }
/** 排序用工作函數(降序 由usort()調用) */ function cmp_desc($a,$b) { global $cmp_key; if ($a[$cmp_key] == $b[$cmp_key]) return 0; return ($a[$cmp_key] > $b[$cmp_key]) ? -1 : 1; }
/** 排序用工作函數(升序 由usort()調用) */ function cmp_asc($a,$b) { global $cmp_key; if ($a[$cmp_key] == $b[$cmp_key]) return 0; return ($a[$cmp_key] > $b[$cmp_key]) ? 1 : -1; }
// 應用實例
file_create_db("test"); $conn = file_connect("test");
$s = "create table board ( sn int primary key auto_increment, name varchar(15) not null, email varchar(30), ip varchar(15), time datetime, content tinyblob not null)"; file_query($s,$conn); //file_query("insert into table board (sn,name,ip) value (15,'w,r,r,oi','$REMOTE_ADDR')",$conn);
//$rs = file_query("select * from board",$conn); $rs = file_query("select * from board where true group by 2 order by 2 desc",$conn); //$rs = file_query("select count(*) as js,time as hj,ip as pi,name,sn from board group by name order by sn desc",$conn); //$rs = file_query("select sn,name,email,io from board where true group by 1 order by 2 desc",$conn); file_close($conn);
echo "<table border = 1>"; echo "<tr>"; for($i=0;$i<file_num_fields($rs);$i++) echo "<th>".file_field_name($rs,$i)."</th>"; echo "</tr>"; for($j=0;$j<file_num_rows($rs);$j++) { echo "<tr>"; $d = file_fetch_row($rs); for($i=0;$i<file_num_fields($rs);$i++) echo "<td>".$d[$i]."</td>"; echo "</tr>"; } echo ""; ?>
|