]> 4ch.mooo.com Git - test.git/blob - lib/pio/pio.mysql.php
modified: data/js/script.js
[test.git] / lib / pio / pio.mysql.php
1 <?php\r
2 /**\r
3  * PIO MySQL API\r
4  *\r
5  * 提供存取以 MySQL 資料庫構成的資料結構後端的物件\r
6  *\r
7  * @package PMCLibrary\r
8  * @version $Id: pio.mysql.php 671 2008-09-20 05:54:15Z scribe $\r
9  * @date $Date: 2008-09-20 13:54:15 +0800 (星期六, 20 九月 2008) $\r
10  */\r
11 \r
12 class PIOmysql{\r
13         var $ENV, $username, $password, $server, $dbname, $tablename; // Local Constant\r
14         var $con, $prepared, $useTransaction; // Local Global\r
15 \r
16         function PIOmysql($connstr='', $ENV){\r
17                 $this->ENV = $ENV;\r
18                 $this->prepared = 0;\r
19                 if($connstr) $this->dbConnect($connstr);\r
20         }\r
21 \r
22         /* private 攔截SQL錯誤 */\r
23         function _error_handler($errarray, $query=''){\r
24                 $err = 'Pixmicat! SQL Error: '.$errarray[0].' on line '.$errarray[1];\r
25                 error_log($err."\n".mysql_errno().': '.mysql_error()."\n".$query."\n\n", 3, 'error.log');\r
26                 trigger_error($err, E_USER_ERROR);\r
27                 exit();\r
28         }\r
29 \r
30         /* private 使用SQL字串和MySQL伺服器要求 */\r
31         function _mysql_call($query, $errarray=false){\r
32                 $resource = mysql_query($query);\r
33                 if(is_array($errarray) && $resource===false) $this->_error_handler($errarray, $query);\r
34                 else return $resource;\r
35         }\r
36 \r
37         /* private 由資源輸出陣列 */\r
38         function _ArrangeArrayStructure($line){\r
39                 $posts = array();\r
40                 while($row = mysql_fetch_array($line, MYSQL_ASSOC)) $posts[] = $row;\r
41                 mysql_free_result($line);\r
42                 return $posts;\r
43         }\r
44 \r
45         /* PIO模組版本 */\r
46         function pioVersion(){\r
47                 return '0.6 (v20100404)';\r
48         }\r
49 \r
50         /* 處理連線字串/連接 */\r
51         function dbConnect($connStr){\r
52                 // 格式: mysql://帳號:密碼@伺服器位置:埠號(可省略)/資料庫/資料表/\r
53                 // 示例: mysql://yotsubanome:pass@localhost/yotsubanome/img_loog/\r
54                 if(preg_match('/^mysql:\/\/(.*)\:(.*)\@(.*(?:\:[0-9]+)?)\/(.*)\/(.*)\/$/i', $connStr, $linkinfos)){\r
55                         $this->username = $linkinfos[1]; // 登入帳號\r
56                         $this->password = $linkinfos[2]; // 登入密碼\r
57                         $this->server = $linkinfos[3]; // 登入伺服器 (含埠號)\r
58                         $this->dbname = $linkinfos[4]; // 資料庫名稱\r
59                         $this->tablename = $linkinfos[5]; // 資料表名稱\r
60                 }\r
61         }\r
62
63         /* 初始化 */\r
64         function dbInit($isAddInitData=true){\r
65                 $this->dbPrepare();\r
66                 if(mysql_num_rows(mysql_query("SHOW TABLES LIKE '".$this->tablename."'"))!=1){ // 資料表不存在\r
67                 $result = "CREATE TABLE ".$this->tablename." (primary key(no),\r
68         index (resto),index (root),index (time),\r
69         no int(1) not null auto_increment,\r
70         resto int(1) not null,\r
71         root timestamp(14) null DEFAULT 0,\r
72         time int(1) not null,\r
73         md5chksum varchar(32) not null,\r
74         category varchar(255) not null,\r
75         tim bigint(1) not null,\r
76         ext varchar(4) not null,\r
77         imgw smallint(1) not null,\r
78         imgh smallint(1) not null,\r
79         imgsize varchar(10) not null,
80         filename varchar(255) not null,\r
81         tw smallint(1) not null,\r
82         th smallint(1) not null,\r
83         pwd varchar(8) not null,\r
84         now varchar(255) not null,\r
85         name varchar(255) not null,\r
86         email varchar(255) not null,\r
87         sub varchar(255) not null,\r
88         com text not null,\r
89         host varchar(255) not null,\r
90         status varchar(255) not null)\r
91         TYPE = MYISAM\r
92         COMMENT = 'PIO Structure V4'";
93                         $result2 = @mysql_query("SHOW CHARACTER SET like 'utf8'"); // 是否支援UTF-8 (MySQL 4.1.1開始支援)\r
94                         if($result2 && mysql_num_rows($result2)){\r
95                                 $result .= ' CHARACTER SET utf8 COLLATE utf8_general_ci'; // 資料表追加UTF-8編碼\r
96                                 mysql_free_result($result2);\r
97                         }
98                         mysql_query($result); // 正式新增資料表
99                         // 追加一筆新資料
100                         if($isAddInitData) $this->addPost(0, 0, '', '', 0, '', 0, 0, '', '', 0, 0, '', '08/11/08(土) 10:24:04', '【スパーキー(④ ^ヮ^)】', '', $this->ENV['NOTITLE'], $this->ENV['NOCOMMENT'], ''); // 追加一筆新資料料\r
101                         $this->dbCommit();\r
102                 }\r
103         }\r
104 \r
105         /* 準備/讀入 */\r
106         function dbPrepare($transaction=false){\r
107                 if($this->prepared) return true;\r
108 \r
109                 if(@!$this->con = mysql_pconnect($this->server, $this->username, $this->password)) $this->_error_handler(array('Open database failed', __LINE__));\r
110                 @mysql_select_db($this->dbname, $this->con);\r
111                 @mysql_query("SET NAMES 'utf8'"); // MySQL資料以UTF-8模式傳送\r
112                 $this->useTransaction = $transaction;\r
113                 if($transaction) @mysql_query('START TRANSACTION'); // 啟動交易性能模式\r
114 \r
115                 $this->prepared = 1;\r
116         }\r
117 \r
118         /* 提交/儲存 */\r
119         function dbCommit(){\r
120                 if(!$this->prepared) return false;\r
121                 if($this->useTransaction) @mysql_query('COMMIT'); // 交易性能模式提交\r
122         }\r
123 \r
124         /* 資料表維護 */\r
125         function dbMaintanence($action, $doit=false){\r
126                 switch($action) {\r
127                         case 'optimize':\r
128                                 if($doit){\r
129                                         $this->dbPrepare(false);\r
130                                         if($this->_mysql_call('OPTIMIZE TABLES '.$this->tablename)) return true;\r
131                                         else return false;\r
132                                 }else return true; // 支援最佳化資料表\r
133                                 break;\r
134                         case 'check':\r
135                                 if($doit){\r
136                                         $this->dbPrepare(false);\r
137                                         if($rs=$this->_mysql_call('CHECK TABLE '.$this->tablename)){\r
138                                                 mysql_data_seek($rs, mysql_num_rows($rs)-1);\r
139                                                 $row = mysql_fetch_assoc($rs);\r
140                                                 return 'Table '.$row['Table'].': '.$row['Msg_type'].' = '.$row['Msg_text'];\r
141                                         }\r
142                                         else return false;\r
143                                 }else return true; // 支援檢查資料表\r
144                                 break;\r
145                         case 'repair':\r
146                                 if($doit){\r
147                                         $this->dbPrepare(false);\r
148                                         if($rs=$this->_mysql_call('REPAIR TABLE '.$this->tablename)){\r
149                                                 mysql_data_seek($rs, mysql_num_rows($rs)-1);\r
150                                                 $row = mysql_fetch_assoc($rs);\r
151                                                 return 'Table '.$row['Table'].': '.$row['Msg_type'].' = '.$row['Msg_text'];\r
152                                         }\r
153                                         else return false;\r
154                                 }else return true; // 支援修復資料表\r
155                                 break;\r
156                         case 'export':\r
157                                 if($doit){\r
158                                         $this->dbPrepare(false);\r
159                                         $gp = gzopen('piodata.log.gz', 'w9');\r
160                                         gzwrite($gp, $this->dbExport());\r
161                                         gzclose($gp);\r
162                                         return '<a href="piodata.log.gz">下載 piodata.log.gz 中介檔案</a>';\r
163                                 }else return true; // 支援匯出資料\r
164                                 break;\r
165                         default: return false; // 不支援\r
166                 }\r
167         }\r
168 \r
169         /* 匯入資料來源 */\r
170         function dbImport($data){\r
171                 $this->dbInit(false); // 僅新增結構不新增資料\r
172                 $data = explode("\r\n", $data);\r
173                 $data_count = count($data) - 1;\r
174                 $replaceComma = create_function('$txt', 'return str_replace("&#44;", ",", $txt);');\r
175                 for($i = 0; $i < $data_count; $i++){\r
176                         $line = array_map($replaceComma, explode(',', $data[$i])); // 取代 &#44; 為 ,\r
177                         $SQL = 'INSERT INTO '.$this->tablename.' (no,resto,root,time,md5chksum,category,tim,ext,imgw,imgh,imgsize,filename,tw,th,pwd,now,name,email,sub,com,host,status) VALUES ('.\r
178         $line[0].','.\r
179         $line[1].',\''.\r
180         $line[2].'\','.\r
181         substr($line[5], 0, 10).',\''.\r
182         mysql_real_escape_string($line[3], $this->con).'\',\''.\r
183         mysql_real_escape_string($line[4], $this->con).'\','.\r
184         $line[5].',\''.mysql_real_escape_string($line[6], $this->con).'\','.\r
185         $line[7].','.$line[8].',\''.mysql_real_escape_string($line[9], $this->con).','.mysql_real_escape_string($line[10], $this->con).'\','.$line[11].','.$line[12].',\''.\r
186         mysql_real_escape_string($line[13], $this->con).'\',\''.\r
187         mysql_real_escape_string($line[14], $this->con).'\',\''.\r
188         mysql_real_escape_string($line[15], $this->con).'\',\''.\r
189         mysql_real_escape_string($line[16], $this->con).'\',\''.\r
190         mysql_real_escape_string($line[17], $this->con).'\',\''.\r
191         mysql_real_escape_string($line[18], $this->con).'\',\''.\r
192         mysql_real_escape_string($line[19], $this->con).'\',\''.\r
193         mysql_real_escape_string($line[20], $this->con).'\')';\r
194                         $this->_mysql_call($SQL, array('Import a new post failed', __LINE__));\r
195                 }\r
196                 $this->dbCommit(); // 送交\r
197                 return true;\r
198         }\r
199 \r
200         /* 匯出資料來源 */\r
201         function dbExport(){\r
202                 if(!$this->prepared) $this->dbPrepare();\r
203                 $line = $this->_mysql_call('SELECT no,resto,root,md5chksum,category,tim,ext,imgw,imgh,imgsize,filename,tw,th,pwd,now,name,email,sub,com,host,status FROM '.$this->tablename.' ORDER BY no DESC',\r
204                         array('Export posts failed', __LINE__));\r
205                 $data = '';\r
206                 $replaceComma = create_function('$txt', 'return str_replace(",", "&#44;", $txt);');\r
207                 while($row = mysql_fetch_array($line, MYSQL_ASSOC)){\r
208                         $row = array_map($replaceComma, $row); // 取代 , 為 &#44;\r
209                         if($row['root']=='0000-00-00 00:00:00') $row['root'] = '0'; // 初始值設為 0\r
210                         $data .= rtrim(implode(',', $row)).",\r\n";\r
211                 }\r
212                 mysql_free_result($line);\r
213                 return $data;\r
214         }\r
215 \r
216         /* 文章數目 */\r
217         function postCount($resno=0){\r
218                 if(!$this->prepared) $this->dbPrepare();\r
219 \r
220                 if($resno){ // 回傳討論串總文章數目\r
221                         $line = $this->_mysql_call('SELECT COUNT(no) FROM '.$this->tablename.' WHERE resto = '.intval($resno),\r
222                                 array('Fetch count in thread failed', __LINE__));\r
223                         $countline = mysql_result($line, 0) + 1;\r
224                 }else{ // 回傳總文章數目\r
225                         $line = $this->_mysql_call('SELECT COUNT(no) FROM '.$this->tablename, array('Fetch count of posts failed', __LINE__));\r
226                         $countline = mysql_result($line, 0);\r
227                 }\r
228                 mysql_free_result($line);\r
229                 return $countline;\r
230         }\r
231 \r
232         /* 討論串數目 */\r
233         function threadCount(){\r
234                 if(!$this->prepared) $this->dbPrepare();\r
235 \r
236                 $tree = $this->_mysql_call('SELECT COUNT(no) FROM '.$this->tablename.' WHERE resto = 0',\r
237                         array('Fetch count of threads failed', __LINE__));\r
238                 $counttree = mysql_result($tree, 0); mysql_free_result($tree); // 計算討論串目前資料筆數\r
239                 return $counttree;\r
240         }\r
241 \r
242         /* 取得最後文章編號 */\r
243         function getLastPostNo($state){\r
244                 if(!$this->prepared) $this->dbPrepare();\r
245 \r
246                 if($state=='afterCommit'){ // 送出後的最後文章編號\r
247                         $tree = $this->_mysql_call('SELECT MAX(no) FROM '.$this->tablename, array('Get the last No. failed', __LINE__));\r
248                         $lastno = mysql_result($tree, 0); mysql_free_result($tree);\r
249                         return $lastno;\r
250                 }else return 0; // 其他狀態沒用\r
251         }\r
252 \r
253         /* 輸出文章清單 */\r
254         function fetchPostList($resno=0, $start=0, $amount=0){\r
255                 if(!$this->prepared) $this->dbPrepare();\r
256 \r
257                 $line = array();\r
258                 $resno = intval($resno);\r
259                 if($resno){ // 輸出討論串的結構 (含自己, EX : 1,2,3,4,5,6)\r
260                         $tmpSQL = 'SELECT no FROM '.$this->tablename.' WHERE no = '.$resno.' OR resto = '.$resno.' ORDER BY no';\r
261                 }else{ // 輸出所有文章編號,新的在前\r
262                         $tmpSQL = 'SELECT no FROM '.$this->tablename.' ORDER BY no DESC';\r
263                         $start = intval($start); $amount = intval($amount);\r
264                         if($amount) $tmpSQL .= " LIMIT {$start}, {$amount}"; // 有指定數量才用 LIMIT\r
265                 }\r
266                 $tree = $this->_mysql_call($tmpSQL, array('Fetch post list failed', __LINE__));\r
267                 while($rows = mysql_fetch_row($tree)) $line[] = $rows[0]; // 迴圈\r
268                 mysql_free_result($tree);\r
269                 return $line;\r
270         }\r
271 \r
272         /* 輸出討論串清單 */\r
273         function fetchThreadList($start=0, $amount=0, $isDESC=false){\r
274                 if(!$this->prepared) $this->dbPrepare();\r
275 \r
276                 $start = intval($start); $amount = intval($amount);\r
277                 $treeline = array();\r
278                 $tmpSQL = 'SELECT no FROM '.$this->tablename.' WHERE resto = 0 ORDER BY '.($isDESC ? 'no' : 'root').' DESC';\r
279                 if($amount) $tmpSQL .= " LIMIT {$start}, {$amount}"; // 有指定數量才用 LIMIT\r
280                 $tree = $this->_mysql_call($tmpSQL, array('Fetch thread list failed', __LINE__));\r
281                 while($rows = mysql_fetch_row($tree)) $treeline[] = $rows[0]; // 迴圈\r
282                 mysql_free_result($tree);\r
283                 return $treeline;\r
284         }\r
285 \r
286         /* 輸出文章 */\r
287         function fetchPosts($postlist){\r
288                 if(!$this->prepared) $this->dbPrepare();\r
289 \r
290                 if(is_array($postlist)){ // 取多串\r
291                         $pno = implode(', ', $postlist); // ID字串\r
292                         $tmpSQL = 'SELECT * FROM '.$this->tablename.' WHERE no IN ('.$pno.') ORDER BY no';\r
293                         if(count($postlist) > 1){ if($postlist[0] > $postlist[1]) $tmpSQL .= ' DESC'; } // 由大排到小\r
294                 }else $tmpSQL = 'SELECT * FROM '.$this->tablename.' WHERE no = '.intval($postlist); // 取單串\r
295                 $line = $this->_mysql_call($tmpSQL, array('Fetch the post content failed', __LINE__));\r
296                 return $this->_ArrangeArrayStructure($line); // 輸出陣列結構\r
297         }\r
298 \r
299         /* 刪除舊附件 (輸出附件清單) */\r
300         function delOldAttachments($total_size, $storage_max, $warnOnly=true){\r
301                 global $FileIO;\r
302                 if(!$this->prepared) $this->dbPrepare();\r
303 \r
304                 $arr_warn = $arr_kill = array(); // 警告 / 即將被刪除標記陣列\r
305                 $result = $this->_mysql_call('SELECT no,ext,tim FROM '.$this->tablename.' WHERE ext <> \'\' ORDER BY no',\r
306                         array('Get old posts failed', __LINE__));\r
307                 while(list($dno, $dext, $dtim) = mysql_fetch_row($result)){ // 個別跑舊文迴圈\r
308                         $dfile = $dtim.$dext; // 附加檔案名稱\r
309                         $dthumb = $dtim.'s.jpg'; // 預覽檔案名稱\r
310                         if($FileIO->imageExists($dfile)){ $total_size -= $FileIO->getImageFilesize($dfile) / 1024; $arr_kill[] = $dno; $arr_warn[$dno] = 1; } // 標記刪除\r
311                         if($FileIO->imageExists($dthumb)) $total_size -= $FileIO->getImageFilesize($dthumb) / 1024;\r
312                         if($total_size < $storage_max) break;\r
313                 }\r
314                 mysql_free_result($result);\r
315                 return $warnOnly ? $arr_warn : $this->removeAttachments($arr_kill);\r
316         }\r
317 \r
318         /* 刪除文章 */\r
319         function removePosts($posts){\r
320                 if(!$this->prepared) $this->dbPrepare();\r
321                 if(count($posts)==0) return array();\r
322 \r
323                 $files = $this->removeAttachments($posts, true); // 先遞迴取得刪除文章及其回應附件清單\r
324                 $pno = implode(', ', $posts); // ID字串\r
325                 $this->_mysql_call('DELETE FROM '.$this->tablename.' WHERE no IN ('.$pno.') OR resto IN('.$pno.')',\r
326                         array('Delete old posts and replies failed', __LINE__)); // 刪掉文章\r
327                 return $files;\r
328         }\r
329 \r
330         /* 刪除附件 (輸出附件清單) */\r
331         function removeAttachments($posts, $recursion=false){\r
332                 global $FileIO;\r
333                 if(!$this->prepared) $this->dbPrepare();\r
334                 if(count($posts)==0) return array();\r
335 \r
336                 $files = array();\r
337                 $pno = implode(', ', $posts); // ID字串\r
338                 if($recursion) $tmpSQL = 'SELECT ext,tim FROM '.$this->tablename.' WHERE (no IN ('.$pno.') OR resto IN('.$pno.")) AND ext <> ''"; // 遞迴取出 (含回應附件)\r
339                 else $tmpSQL = 'SELECT ext,tim FROM '.$this->tablename.' WHERE no IN ('.$pno.") AND ext <> ''"; // 只有指定的編號\r
340 \r
341                 $result = $this->_mysql_call($tmpSQL, array('Get attachments of the post failed', __LINE__));\r
342                 while(list($dext, $dtim) = mysql_fetch_row($result)){ // 個別跑迴圈\r
343                         $dfile = $dtim.$dext; // 附加檔案名稱\r
344                         $dthumb = $dtim.'s.jpg'; // 預覽檔案名稱\r
345                         if($FileIO->imageExists($dfile)) $files[] = $dfile;\r
346                         if($FileIO->imageExists($dthumb)) $files[] = $dthumb;\r
347                 }\r
348                 mysql_free_result($result);\r
349                 return $files;\r
350         }\r
351
352         /* 新增文章/討論串 */\r
353         function addPost($no, $resto, $md5chksum, $category, $tim, $ext, $imgw, $imgh, $imgsize, $filename, $tw, $th, $pwd, $now, $name, $email, $sub, $com, $host, $age=false, $status='') {\r
354                 if(!$this->prepared) $this->dbPrepare();\r\r
355                 $time = (int)substr($tim, 0, -3); // 13位數的數字串是檔名,10位數的才是時間數值\r
356                 $updatetime = gmdate('Y-m-d H:i:s'); // 更動時間 (UTC)\r
357                 $resto = intval($resto);\r
358                 if($resto){ // 新增回應\r
359                         $root = '0';\r
360                         if($age){ // 推文\r
361                                 $this->_mysql_call('UPDATE '.$this->tablename.' SET root = "'.$updatetime.'" WHERE no = '.$resto,\r
362                                         array('Push the post failed', __LINE__)); // 將被回應的文章往上移動\r
363                         }\r              }else $root = $updatetime; // 新增討論串, 討論串最後被更新時間\r
364
365                 if($no === 0){ // init post 0
366                         $query = 'INSERT INTO '.$this->tablename.' (no,resto,root,time,md5chksum,category,tim,ext,imgw,imgh,imgsize,tw,th,pwd,now,name,email,sub,com,host,status) VALUES ('.
367                 -1,'. // 回應編號
368                 $resto.','. // 回應編號
369                 "'$root',". // 最後更新時間
370                 $time.','. // 發文時間數值
371                 "'$md5chksum',". // 附加檔案md5
372                 "'".mysql_real_escape_string($category, $this->con)."',". // 分類標籤
373                 "'$tim', '$ext',". // 附加檔名
374                 (int)$imgw.','.(int)$imgh.",'".$imgsize."','".$filename."',".(int)$tw.','.(int)$th.','. // 圖檔長寬及檔案大小;預覽圖長寬
375                 "'".mysql_real_escape_string($pwd, $this->con)."',".\r
376                 "'$now',". // 時間(含ID)字串
377                 "'".mysql_real_escape_string($name, $this->con)."',".\r
378                 "'".mysql_real_escape_string($email, $this->con)."',".\r
379                 "'".mysql_real_escape_string($sub, $this->con)."',".\r
380                 "'".mysql_real_escape_string($com, $this->con)."',".\r
381                 "'".mysql_real_escape_string($host, $this->con)."', '".mysql_real_escape_string($status, $this->con)."')";
382                 }else{\r
383                         $query = 'INSERT INTO '.$this->tablename.' (resto,root,time,md5chksum,category,tim,ext,imgw,imgh,imgsize,tw,th,pwd,now,name,email,sub,com,host,status) VALUES ('.\r
384                 $resto.','. // 回應編號
385                 "'$root',". // 最後更新時間
386                 $time.','. // 發文時間數值
387                 "'$md5chksum',". // 附加檔案md5
388                 "'".mysql_real_escape_string($category, $this->con)."',". // 分類標籤
389                 "'$tim', '$ext',". // 附加檔名
390                 (int)$imgw.','.(int)$imgh.",'".$imgsize."','".$filename."',".(int)$tw.','.(int)$th.','. // 圖檔長寬及檔案大小;預覽圖長寬
391                 "'".mysql_real_escape_string($pwd, $this->con)."',".\r
392                 "'$now',". // 時間(含ID)字串
393                 "'".mysql_real_escape_string($name, $this->con)."',".\r
394                 "'".mysql_real_escape_string($email, $this->con)."',".\r
395                 "'".mysql_real_escape_string($sub, $this->con)."',".\r
396                 "'".mysql_real_escape_string($com, $this->con)."',".\r
397                 "'".mysql_real_escape_string($host, $this->con)."', '".mysql_real_escape_string($status, $this->con)."')";
398                 }
399                 $this->_mysql_call($query, array('Insert a new post failed', __LINE__));\r
400         }\r
401 \r
402         /* 檢查是否連續投稿 */\r
403         function isSuccessivePost($lcount, $com, $timestamp, $pass, $passcookie, $host, $isupload){\r
404                 global $FileIO;\r
405                 if(!$this->prepared) $this->dbPrepare();\r
406 \r
407                 if(!$this->ENV['PERIOD.POST']) return false; // 關閉連續投稿檢查\r
408                 $timestamp = intval($timestamp);\r
409                 $tmpSQL = 'SELECT pwd,host FROM '.$this->tablename.' WHERE time > '.($timestamp - (int)$this->ENV['PERIOD.POST']); // 一般投稿時間檢查\r
410                 if($isupload) $tmpSQL .= ' OR time > '.($timestamp - (int)$this->ENV['PERIOD.IMAGEPOST']); // 附加圖檔的投稿時間檢查 (與下者兩者擇一)\r
411                 else $tmpSQL .= ' OR md5(com) = "'.md5($com).'"'; // 內文一樣的檢查 (與上者兩者擇一)\r
412 \r
413                 $result = $this->_mysql_call($tmpSQL, array('Get the post to check the succession failed', __LINE__));\r
414                 while(list($lpwd, $lhost) = mysql_fetch_row($result)){\r
415                         // 判斷為同一人發文且符合連續投稿條件\r
416                         if($host==$lhost || $pass==$lpwd || $passcookie==$lpwd) return true;\r
417                 }\r
418                 return false;\r
419         }\r
420 \r
421         /* 檢查是否重複貼圖 */\r
422         function isDuplicateAttachment($lcount, $md5hash){\r
423                 global $FileIO;\r
424                 if(!$this->prepared) $this->dbPrepare();\r
425 \r
426                 $result = $this->_mysql_call('SELECT tim,ext FROM '.$this->tablename." WHERE ext <> '' AND md5chksum = '$md5hash' ORDER BY no DESC",\r
427                         array('Get the post to check the duplicate attachment failed', __LINE__));\r
428                 while(list($ltim, $lext) = mysql_fetch_row($result)){\r
429                         if($FileIO->imageExists($ltim.$lext)) return true; // 有相同檔案\r
430                 }\r
431                 return false;\r
432         }\r
433 \r
434         /* 有此討論串? */\r
435         function isThread($no){\r
436                 if(!$this->prepared) $this->dbPrepare();\r
437 \r
438                 $result = $this->_mysql_call('SELECT no FROM '.$this->tablename.' WHERE no = '.intval($no).' AND resto = 0');\r
439                 return mysql_fetch_array($result) ? true : false;\r
440         }\r
441 \r
442         /* 搜尋文章 */\r
443         function searchPost($keyword, $field, $method){\r
444                 if(!$this->prepared) $this->dbPrepare();\r
445 \r
446                 $keyword_cnt = count($keyword);\r
447                 $SearchQuery = 'SELECT * FROM '.$this->tablename." WHERE {$field} LIKE '%".mysql_real_escape_string($keyword[0], $this->con)."%'";\r
448                 if($keyword_cnt > 1){\r
449                         for($i = 1; $i < $keyword_cnt; $i++){\r
450                                 $SearchQuery .= " {$method} {$field} LIKE '%".mysql_real_escape_string($keyword[$i], $this->con)."%'"; // 多重字串交集 / 聯集搜尋\r
451                         }\r
452                 }\r
453                 $SearchQuery .= ' ORDER BY no DESC'; // 按照號碼大小排序\r
454                 $line = $this->_mysql_call($SearchQuery, array('Search the post failed', __LINE__));\r
455                 return $this->_ArrangeArrayStructure($line); // 輸出陣列結構\r
456         }\r
457 \r
458         /* 搜尋類別標籤 */\r
459         function searchCategory($category){\r
460                 if(!$this->prepared) $this->dbPrepare();\r
461 \r
462                 $foundPosts = array();\r
463                 $SearchQuery = 'SELECT no FROM '.$this->tablename." WHERE lower(category) LIKE '%,".strtolower(mysql_real_escape_string($category, $this->con)).",%' ORDER BY no DESC";\r
464                 $line = $this->_mysql_call($SearchQuery, array('Search the category failed', __LINE__));\r
465                 while($rows = mysql_fetch_row($line)) $foundPosts[] = $rows[0];\r
466                 mysql_free_result($line);\r
467                 return $foundPosts;\r
468         }\r
469 \r
470         /* 取得文章屬性 */\r
471         function getPostStatus($status){\r
472                 return new FlagHelper($status); // 回傳 FlagHelper 物件\r
473         }\r
474 \r
475         /* 更新文章 */\r
476         function updatePost($no, $newValues){\r
477                 if(!$this->prepared) $this->dbPrepare();\r
478 \r
479                 $no = intval($no);\r
480                 $chk = array('resto', 'md5chksum', 'category', 'tim', 'ext', 'imgw', 'imgh', 'imgsize', 'filename', 'tw', 'th', 'pwd', 'now', 'name', 'email', 'sub', 'com', 'host', 'status');\r
481                 foreach($chk as $c){\r
482                         if(isset($newValues[$c])){\r
483                                 $this->_mysql_call('UPDATE '.$this->tablename." SET $c = '".mysql_real_escape_string($newValues[$c], $this->con)."', root = root WHERE no = ".$no,\r
484                                         array('Update the field of the post failed', __LINE__)); // 更新討論串屬性\r
485                         }\r
486                 }\r
487         }\r
488 \r
489         /* 設定文章屬性 */\r
490         function setPostStatus($no, $newStatus){\r
491                 $this->updatePost($no, array('status' => $newStatus));\r
492         }\r
493 }\r
494 ?>