]> 4ch.mooo.com Git - test.git/blob - yotsubanome.php
021abc31b4285f2ba1fc018d5eda4e8dece5f1f2
[test.git] / yotsubanome.php
1 <?php
2 /********************************
3     四葉の芽画像掲示板
4
5 yotsubanome.php*/$ver = "v0.7.8.1.0004 β lot.100404";/*
6
7 これがコアシステムです。 四葉の芽スクリプト
8 このスクリプトはレッツPHP!<http://php.s3.to/>のgazou.phpを改造したものです。
9 配布条件はレッツPHP!に準じます。改造、再配布は自由にどうぞ。
10 このスクリプトに関する質問はレッツPHP!にしないようにお願いします。
11 最新版は<http://4ch.irc.su/+4/script/>で配布しています。
12 ご質問は準備板@四葉の芽<http://4ch.irc.su/+4/test/>までどうぞ。
13
14 --【スパーキー(④ ^ヮ^)】◆FCr.DTJy2k◆◆/ODv/gdbGrBJVTTiLB/IBFugUUM=◆四葉の芽◇ちゃんねる ## 管理者 ##
15 ********************************
16 */
17 define("PIXMICAT_VER", 'yotsubanome '.$ver); // 版本資訊文字
18 /*
19 Pixmicat! : 圖咪貓貼圖版程式
20 http://pixmicat.openfoundry.org/
21 版權所有 © 2005-2009 Pixmicat! Development Team
22
23 版權聲明:
24 此程式是基於レッツPHP!<http://php.s3.to/>的gazou.php、
25 双葉ちゃん<http://www.2chan.net>的futaba.php所改寫之衍生著作程式,屬於自由軟體,
26 以The Clarified Artistic License作為發佈授權條款。
27 您可以遵照The Clarified Artistic License來自由使用、散播、修改或製成衍生著作。
28 更詳細的條款及定義請參考隨附"LICENSE"條款副本。
29
30 發佈這一程式的目的是希望它有用,但沒有任何擔保,甚至沒有適合特定目的而隱含的擔保。
31 關於此程式相關的問題請不要詢問レッツPHP!及双葉ちゃん。
32
33 如果您沒有隨著程式收到一份The Clarified Artistic License副本,
34 請瀏覽http://pixmicat.openfoundry.org/license/以取得一份。
35
36 最低運行需求:
37 PHP 4.3.0 / 27 December 2002
38 GD Version 2.0.28 / 21 July 2004
39
40 建議運行環境:
41 PHP 4.4.9 或更高版本並開啟 GD 和 Zlib 支援,如支援 ImageMagick 建議使用
42 安裝 PHP 編譯快取套件 (如eAccelerator, XCache, APC) 或其他快取套件 (如memcached) 更佳
43 如伺服器支援 SQLite, MySQL, PostgreSQL 等請盡量使用
44
45 設置方法:
46 根目錄的權限請設為777,
47 首先將pixmicat.php執行過一遍,必要的檔案和資料夾權限皆會自動設定,
48 自動設定完成後請刪除或註解起來此檔案底部之init(); // ←■■!程式環境初始化(略)一行,
49 然後再執行一遍pixmicat.php,即完成初始化程序,可以開始使用。
50
51 細部的設定請打開config.php參考註解修改,另有 Wiki (http://pixmicat.wikidot.com/pmcuse:config)
52 說明條目可資參考。
53 */
54
55 /* Enviorment Settings */
56 // Do not change unless you renamed the directories
57 define("PHP_DIRECTORY", '../test/'); // yotsubanome "C:\windows\system\"
58
59 /* Include */
60 include_once(PHP_DIRECTORY.'lib/lib_env.php'); // Enviorment Settings
61 include_once(PHP_DIRECTORY.'config.php'); // 引入設定檔
62 include_once(PHP_DIRECTORY.'lib/lib_language.php'); // 引入語系
63 include_once(PHP_DIRECTORY.'lib/lib_common.php'); // 引入共通函式檔案
64 include_once(PHP_DIRECTORY.'lib/lib_fileio.php'); // 引入FileIO
65 include_once(PHP_DIRECTORY.'lib/lib_pio.php'); // 引入PIO
66 include_once(PHP_DIRECTORY.'lib/lib_pms.php'); // 引入PMS
67 include_once(PHP_DIRECTORY.'lib/lib_pte.php'); // 引入PTE外部函式庫
68
69 $PTE = new PTELibrary(TEMPLATE_FILE); // PTE Library
70
71 if(version_compare(PHP_VERSION, '5.0.0', '>=')){ // PHP5+
72         set_error_handler('PMCCore_errorHandler', E_ERROR | E_WARNING | E_USER_ERROR); // Handle Errors
73 }else{
74         //---- set_error_handler('PMCCore_errorHandler');
75         error_reporting(E_ALL); // show all errors for debugging
76 }
77
78 /* Lockdown [prevents posting] */
79 if(file_exists(PHP_DIRECTORY.'lockdown')){
80         if($_POST['mode'] == 'usrdel' || $_GET['mode'] == 'latest' || $_GET['res']){
81                 echo "";
82         }else{
83                 die('Posting temporarily disabled. Come back later!<br/>&mdash;四葉の芽チーム');
84         }
85 }
86
87 /* 更新記錄檔檔案/輸出討論串 */
88 /* ログの全体更新 */
89 function updatelog($resno=0,$page_num=-1,$single_page=false){
90         global $config, $PIO, $FileIO, $PTE, $PMS, $language, $LIMIT_SENSOR, $style_bar;
91
92         $adminMode = adminAuthenticate('check') && $page_num != -1 && !$single_page; // 前端管理模式
93         $adminFunc = ''; // 前端管理選擇
94         if($adminMode){
95                 $adminFunc = '<select name="func"><option value="delete">'._T('admin_delete').'</option>';
96                 $funclist = array();
97                 $PMS->useModuleMethods('AdminFunction', array('add', &$funclist, null, null)); // "AdminFunction" Hook Point
98                 foreach($funclist as $f) $adminFunc .= '<option value="'.$f[0].'">'.$f[1].'</option>'."\n";
99                 $adminFunc .= '</select>';
100         }
101         $resno = intval($resno); // 編號數字化
102         $page_start = $page_end = 0; // 靜態頁面編號
103         $inner_for_count = 1; // 內部迴圈執行次數
104         $RES_start = $RES_amount = $hiddenReply = $tree_count = $hiddenImage = $hiddenImagP = 0;
105         $hiddenImagRP = 1; // o++
106         $kill_sensor = $old_sensor = false; // 預測系統啟動旗標
107         $arr_kill = $arr_old = array(); // 過舊編號陣列
108         $pte_vals = array('{$THREADFRONT}'=>'','{$THREADREAR}'=>'','{$SELF}'=>PHP_SELF,
109                 '{$DEL_HEAD_TEXT}' => '<input type="hidden" name="mode" value="usrdel" />'._T('del_head'),
110                 '{$DEL_IMG_ONLY_FIELD}' => '<input type="checkbox" name="onlyimgdel" id="onlyimgdel" value="on" />',
111                 '{$DEL_IMG_ONLY_TEXT}' => _T('del_img_only'),
112                 '{$DEL_PASS_TEXT}' => ($adminMode ? $adminFunc : '')._T('del_pass'),
113                 '{$DEL_PASS_FIELD}' => '<input class="inputtext" type="password" name="pwd" size="8" value="" />',
114                 '{$DEL_SUBMIT_BTN}' => '<input type="submit" value="'._T('del_btn').'" />');
115         if(is_file(DATA_DIR.CSV_SS)) $pte_vals += array('{$STYLE_BAR}' => '<br />Style '.$style_bar);
116
117         if($resno) $pte_vals['{$RESTO}'] = $resno;
118
119         if(!$resno){
120                 if($page_num==-1){ // remake模式 (PHP動態輸出多頁份)
121                         $threads = $PIO->fetchThreadList(); // 取得全討論串列表
122                         $PMS->useModuleMethods('ThreadOrder', array($resno,$page_num,$single_page,&$threads)); // "ThreadOrder" Hook Point
123                         $threads_count = count($threads);
124                         $inner_for_count = $threads_count > PAGE_DEF ? PAGE_DEF : $threads_count;
125                         $page_end = ceil($threads_count / PAGE_DEF) - 1; // 頁面編號最後值
126                 }else{ // 討論串分頁模式 (PHP動態輸出一頁份)
127                         $threads_count = $PIO->threadCount(); // 討論串個數
128                         //---- if($page_num < 0 || ($page_num * PAGE_DEF) >= $threads_count) error(_T('page_not_found')); // $page_num超過範圍
129                         //++++---- Page 0 bug fix
130                         if($page_num!=0) if($page_num < 0 || ($page_num * PAGE_DEF) >= $threads_count) error(_T('page_not_found')); // $page_num超過範圍
131                         //++++----
132                         $page_start = $page_end = $page_num; // 設定靜態頁面編號
133                         $threads = $PIO->fetchThreadList($page_num * PAGE_DEF, PAGE_DEF); // 取出分頁後的討論串首篇列表
134                         $PMS->useModuleMethods('ThreadOrder', array($resno,$page_num,$single_page,&$threads)); // "ThreadOrder" Hook Point
135                         $inner_for_count = count($threads); // 討論串個數就是迴圈次數
136                 }
137         }else{
138                 if(!$PIO->isThread($resno)){ error(_T('thread_not_found')); }
139                 $AllRes = isset($_GET['page_num']) && $_GET['page_num']=='all'; // 是否使用 ALL 全部輸出
140
141                 // 計算回應分頁範圍
142                 $tree_count = $PIO->postCount($resno) - 1; // 討論串回應個數
143                 if($tree_count && RE_PAGE_DEF){ // 有回應且RE_PAGE_DEF > 0才做分頁動作
144                         if($page_num==='all'){ // show all
145                                 $page_num = 0;
146                                 $RES_start = 1;
147                                 $RES_amount = $tree_count;
148                         }else{
149                                 if($page_num==='RE_PAGE_MAX') $page_num = ceil($tree_count / RE_PAGE_DEF) - 1; // 特殊值:最末頁
150                                 if($page_num < 0) $page_num = 0; // 負數
151                                 if($page_num * RE_PAGE_DEF >= $tree_count) error(_T('page_not_found'));
152                                 $RES_start = $page_num * RE_PAGE_DEF + 1; // 開始
153                                 $RES_amount = RE_PAGE_DEF; // 取幾個
154                         }
155                 }elseif($page_num > 0) error(_T('page_not_found')); // 沒有回應的情況只允許page_num = 0 或負數
156                 else{ $RES_start = 1; $RES_amount = $tree_count; $page_num = 0; } // 輸出全部回應
157
158                 if(USE_RE_CACHE && !$adminMode){ // 檢查快取是否仍可使用 / 頁面有無更動
159                         $cacheETag = md5(($AllRes ? 'all' : $page_num).'-'.$tree_count); // 最新狀態快取用 ETag
160                         $cacheFile = './cache/'.$resno.'-'.($AllRes ? 'all' : $page_num).'.'; // 暫存快取檔位置
161                         $cacheGzipPrefix = extension_loaded('zlib') ? 'compress.zlib://' : ''; // 支援 Zlib Compression Stream 就使用
162                         $cacheControl = isset($_SERVER['HTTP_CACHE_CONTROL']) ? $_SERVER['HTTP_CACHE_CONTROL'] : ''; // 瀏覽器快取控制
163                         if(isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] == '"'.$cacheETag.'"'){ // 再度瀏覽而快取無更動
164                                 header('HTTP/1.1 304 Not Modified');
165                                 header('ETag: "'.$cacheETag.'"');
166                                 return;
167                         }elseif(file_exists($cacheFile.$cacheETag) && $cacheControl != 'no-cache'){ // 有(更新的)暫存快取檔存在 (未強制no-cache)
168                                 header('X-Cache: HIT from Pixmicat');
169                                 header('ETag: "'.$cacheETag.'"');
170                                 header('Connection: close');
171                                 readfile($cacheGzipPrefix.$cacheFile.$cacheETag); return;
172                         }else{
173                                 header('X-Cache: MISS from Pixmicat');
174                         }
175                 }
176         }
177
178         //++++---- Page 0 bug fix
179         if($tree_count==0 && $page_end==-1) $page_end = 0;
180         //++++----
181         // 預測過舊文章和將被刪除檔案
182         if(PIOSensor::check('predict', $LIMIT_SENSOR)){ // 是否需要預測
183                 $old_sensor = true; // 標記打開
184                 $arr_old = array_flip(PIOSensor::listee('predict', $LIMIT_SENSOR)); // 過舊文章陣列
185         }
186         $tmp_total_size = total_size(); // 目前附加圖檔使用量
187         $tmp_STORAGE_MAX = STORAGE_MAX * (($tmp_total_size >= STORAGE_MAX) ? 1 : 0.96); // 預估上限值
188         if(STORAGE_LIMIT && STORAGE_MAX > 0 && ($tmp_total_size >= $tmp_STORAGE_MAX)){
189                 $kill_sensor = true; // 標記打開
190                 $arr_kill = $PIO->delOldAttachments($tmp_total_size, $tmp_STORAGE_MAX); // 過舊附檔陣列
191         }
192
193         $PMS->useModuleMethods('ThreadFront', array(&$pte_vals['{$THREADFRONT}'], $resno)); // "ThreadFront" Hook Point
194         $PMS->useModuleMethods('ThreadRear', array(&$pte_vals['{$THREADREAR}'], $resno)); // "ThreadRear" Hook Point
195
196         // 生成靜態頁面一頁份內容
197         for($page = $page_start; $page <= $page_end; $page++){
198                 $dat = ''; $pte_vals['{$THREADS}'] = '';
199                 head($dat, $resno);
200                 form($dat, $resno);
201                 // 輸出討論串內容
202                 for($i = 0; $i < $inner_for_count; $i++){
203                         // 取出討論串編號
204                         if($resno) $tID = $resno; // 單討論串輸出 (回應模式)
205                         else{
206                                 if($page_num == -1 && ($page * PAGE_DEF + $i) >= $threads_count) break; // remake 超出索引代表已全部完成
207                                 $tID = ($page_start==$page_end) ? $threads[$i] : $threads[$page * PAGE_DEF + $i]; // 一頁內容 (一般模式) / 多頁內容 (remake模式)
208                                 $tree_count = $PIO->postCount($tID) - 1; // 討論串回應個數
209                                 $RES_start = $tree_count - RE_DEF + 1; if($RES_start < 1) $RES_start = 1; // 開始
210                                 $RES_amount = RE_DEF; // 取幾個
211                                 $hiddenReply = $RES_start - 1; // 被隱藏回應數
212                         }
213
214                         // $RES_start, $RES_amount 拿去算新討論串結構 (分頁後, 部分回應隱藏)
215                         $tree = $PIO->fetchPostList($tID); // 整個討論串樹狀結構
216                         $tree_cut = array_slice($tree, $RES_start, $RES_amount); array_unshift($tree_cut, $tID); // 取出特定範圍回應
217                         $posts = $PIO->fetchPosts($tree_cut); // 取得文章架構內容
218                         $posts_img = $PIO->fetchPosts($tree); // o++
219                         $pte_vals['{$THREADS}'] .= arrangeThread($PTE, $tree, $tree_cut, $posts, $hiddenReply, $resno, $arr_kill, $arr_old, $kill_sensor, $old_sensor, true, $adminMode, $hiddenImage, $hiddenImagP, $hiddenImagRP, $posts_img); // 交給這個函式去搞討論串印出
220                 }
221                 $pte_vals['{$PAGENAV}'] = '<div id="page_switch">';
222
223                 // 換頁判斷
224                 $prev = ($resno ? $page_num : $page) - 1;
225                 $next = ($resno ? $page_num : $page) + 1;
226                 if($resno){ // 回應分頁
227                         if(RE_PAGE_DEF > 0){ // 回應分頁開啟
228                                 $pte_vals['{$PAGENAV}'] .= '<table class="pages" border="1"><tr><td style="white-space: nowrap;">';
229                                 $pte_vals['{$PAGENAV}'] .= ($prev >= 0) ? '<a href="'.PHP_SELF.'?res='.$resno.'&amp;page_num='.$prev.'">'._T('prev_page').'</a>' : _T('first_page');
230                                 $pte_vals['{$PAGENAV}'] .= "</td><td>";
231                                 if($tree_count==0) $pte_vals['{$PAGENAV}'] .= '[<b>0</b>] '; // 無回應
232                                 else{
233                                         for($i = 0, $len = $tree_count / RE_PAGE_DEF; $i < $len; $i++){
234                                                 if(!$AllRes && $page_num==$i) $pte_vals['{$PAGENAV}'] .= '[<b>'.$i.'</b>] ';
235                                                 else $pte_vals['{$PAGENAV}'] .= '[<a href="'.PHP_SELF.'?res='.$resno.'&amp;page_num='.$i.'">'.$i.'</a>] ';
236                                         }
237                                         $pte_vals['{$PAGENAV}'] .= $AllRes ? '[<b>'._T('all_pages').'</b>] ' : ($tree_count > RE_PAGE_DEF ? '[<a href="'.PHP_SELF.'?res='.$resno.'&amp;page_num=all">'._T('all_pages').'</a>] ' : '');
238                                 }
239                                 $pte_vals['{$PAGENAV}'] .= '</td><td style="white-space: nowrap;">';
240                                 $pte_vals['{$PAGENAV}'] .= (!$AllRes && $tree_count > $next * RE_PAGE_DEF) ? '<a href="'.PHP_SELF.'?res='.$resno.'&amp;page_num='.$next.'">'._T('next_page').'</a>' : _T('last_page');
241                                 $pte_vals['{$PAGENAV}'] .= '</td></tr></table>'."\n";
242                         }
243                 }else{ // 一般分頁
244                         $pte_vals['{$PAGENAV}'] .= '<table class="pages" border="1"><tr>';
245                         if($prev >= 0){
246                                 if(!$adminMode && $prev==0) $pte_vals['{$PAGENAV}'] .= '<td><form action="'.PHP_SELF2.'" method="get">';
247                                 else{
248                                         if($adminMode || (STATIC_HTML_UNTIL != -1) && ($prev > STATIC_HTML_UNTIL)) $pte_vals['{$PAGENAV}'] .= '<td><form action="'.PHP_SELF.'?page_num='.$prev.'" method="post">';
249                                         else $pte_vals['{$PAGENAV}'] .= '<td><form action="'.$prev.PHP_EXT.'" method="get">';
250                                 }
251                                 $pte_vals['{$PAGENAV}'] .= '<div><input type="submit" value="'._T('prev_page').'" /></div></form></td>';
252                         }else $pte_vals['{$PAGENAV}'] .= '<td style="white-space: nowrap;">'._T('first_page').'</td>';
253                         $pte_vals['{$PAGENAV}'] .= '<td>';
254                         for($i = 0, $len = $threads_count / PAGE_DEF; $i < $len; $i++){
255                                 if($page==$i) $pte_vals['{$PAGENAV}'] .= "[<b>".$i."</b>] ";
256                                 else{
257                                         $pageNext = ($i==$next) ? ' rel="next"' : '';
258                                         if(!$adminMode && $i==0) $pte_vals['{$PAGENAV}'] .= '[<a href="'.PHP_SELF2.'?">0</a>] ';
259                                         elseif($adminMode || (STATIC_HTML_UNTIL != -1 && $i > STATIC_HTML_UNTIL)) $pte_vals['{$PAGENAV}'] .= '[<a href="'.PHP_SELF.'?page_num='.$i.'"'.$pageNext.'>'.$i.'</a>] ';
260                                         else $pte_vals['{$PAGENAV}'] .= '[<a href="'.$i.PHP_EXT.'?"'.$pageNext.'>'.$i.'</a>] ';
261                                 }
262                         }
263                         $pte_vals['{$PAGENAV}'] .= '</td>';
264                         if($threads_count > $next * PAGE_DEF){
265                                 if($adminMode || (STATIC_HTML_UNTIL != -1) && ($next > STATIC_HTML_UNTIL)) $pte_vals['{$PAGENAV}'] .= '<td><form action="'.PHP_SELF.'?page_num='.$next.'" method="post">';
266                                 else $pte_vals['{$PAGENAV}'] .= '<td><form action="'.$next.PHP_EXT.'" method="get">';
267                                 $pte_vals['{$PAGENAV}'] .= '<div><input type="submit" value="'._T('next_page').'" /></div></form></td>';
268                         }else $pte_vals['{$PAGENAV}'] .= '<td style="white-space: nowrap;">'._T('last_page').'</td>';
269                         $pte_vals['{$PAGENAV}'] .= '</tr></table>'."\n";
270                 }
271                 $pte_vals['{$PAGENAV}'] .= '<br style="clear: left;" />
272 </div>';
273                 $dat .= $PTE->ParseBlock('MAIN', $pte_vals);
274                 foot($dat); // the foot is a special core function wwww --sparky4
275
276                 // 存檔 / 輸出
277                 if($single_page || ($page_num == -1 && !$resno)){ // 靜態快取頁面生成
278                         if($page==0) $logfilename = PHP_SELF2;
279                         else $logfilename = $page.PHP_EXT;
280                         $fp = fopen($logfilename, 'w');
281                         stream_set_write_buffer($fp, 0);
282                         fwrite($fp, $dat);
283                         fclose($fp);
284                         @chmod($logfilename, 0666);
285                         if(STATIC_HTML_UNTIL != -1 && STATIC_HTML_UNTIL==$page) break; // 頁面數目限制
286                 }else{ // PHP 輸出 (回應模式/一般動態輸出)
287                         if(USE_RE_CACHE && !$adminMode && $resno && !isset($_GET['upseries'])){ // 更新快取
288                                 if($oldCaches = glob($cacheFile.'*')){
289                                         foreach($oldCaches as $o) unlink($o); // 刪除舊快取
290                                 }
291                                 $fp = fopen($cacheGzipPrefix.$cacheFile.$cacheETag, 'w');
292                                 fwrite($fp, $dat);
293                                 fclose($fp);
294                                 @chmod($cacheFile.$cacheETag, 0666);
295                                 header('ETag: "'.$cacheETag.'"');
296                                 header('Connection: close');
297                         }
298                         echo $dat;
299                         break;
300                 }
301         }
302 }
303
304 /* 輸出討論串架構 */
305 function arrangeThread($PTE, $tree, $tree_cut, $posts, $hiddenReply, $resno=0, $arr_kill, $arr_old, $kill_sensor, $old_sensor, $showquotelink=true, $adminMode=false, $hiddenImage, $hiddenImagP, $hiddenImagRP, $posts_img){
306         global $config, $PIO, $FileIO, $PMS, $language;
307
308         $thdat = ''; // 討論串輸出碼
309         $posts_count = count($posts); // 迴圈次數
310         if($hiddenReply) $posts_img_count = count($posts_img); // o++
311         if(gettype($tree_cut) == 'array') $tree_cut = array_flip($tree_cut); // array_flip + isset 搜尋法
312         if(gettype($tree) == 'array') $tree_clone = array_flip($tree);
313         if($hiddenReply){ // o++
314                 // $o = 0 (首篇), $o = 1~n (回應) //++++----
315                 for($o = 0; $o < $posts_img_count; $o++){ // o++
316                         extract($posts_img[$o]); // o++
317                         if($ext && $FileIO->imageExists($tim.$ext)) $hiddenImage++; // o++ all images in thread
318                 }
319                 // $oo = 0 (首篇), $oo = 1~n (回應) //++++----
320                 for($oo = 0; $oo < $posts_count; $oo++){ // o++
321                         extract($posts[$oo]); // o++
322                         if($oo) if($ext && $FileIO->imageExists($tim.$ext)) $hiddenImagP++; // o++ reply images in index
323                         elseif(!$ext && !$FileIO->imageExists($tim.$ext)) $hiddenImagRP = 0; // o++ opening thread image in index
324                 }
325
326                 // A little math is done to get the total number of omitted images
327                 $hiddenImgs = ($hiddenImage - $hiddenImagP) - $hiddenImagRP; // o++
328         }
329
330         // Actually beginning the REAL post extraction
331         // $i = 0 (首篇), $i = 1~n (回應)
332         for($i = 0; $i < $posts_count; $i++){
333                 $imgsrc = $img_thumb = $imgwh_bar = $imgfn_bar = '';
334                 $IMG_BAR = $REPLYBTN = $QUOTEBTN = $WARN_OLD = $WARN_BEKILL = $WARN_ENDREPLY = $WARN_HIDEPOST = '';
335                 extract($posts[$i]); // 取出討論串文章內容設定變數
336
337                 if($no == 0) break; // Do not display post 0
338
339                 // 設定欄位值
340                 $name = str_replace('&'.TRIP_KEY, '&amp;'.TRIP_KEY, $name); // 避免 &#xxxx; 後面被視為 Trip 留下 & 造成解析錯誤
341                 if(CLEAR_SAGE) $email = preg_replace('/^sage( *)/i', '', trim($email)); // 清除E-mail中的「sage」關鍵字
342                 // Tripcode indicator // t++ //++++----
343                 // This may be a blob of code but it apparently works >< please help me here
344                 $tripkeycount = substr_count($name, TRIP_KEY);
345                 if($config['ALLOW_NONAME']==3){
346                         if($name || $tripkeycount) $name = $config['DEFAULT_NONAME'];
347                         if($email) $now = "<a href=\"mailto:$email\" class=\"linkmail\">$now</a>";
348                 }else
349                 if($config['ALLOW_NONAME']==2){ // 強制砍名
350                         if($tripkeycount==1) $name = preg_match('/(\\'.TRIP_KEY.'.{10})/', $name, $matches) ? '<span class="postertrip">'.$matches[1].'</span>' : '';
351                         if($tripkeycount==2) $name = preg_match('/(\\'.TRIP_KEY.TRIP_KEY.'.{16})/', $name, $matches) ? '<span class="postertrip">'.$matches[1].'</span>' : '';
352                         if($tripkeycount==3) $name = preg_match('/(\\'.TRIP_KEY.'.{32})/', $name, $matches) ? '<span class="postertrip">'.$matches[1].'</span>' : '';
353                         if($email) $now = "<a href=\"mailto:$email\" class=\"linkmail\">$now</a>";
354                 }else{
355                         if($tripkeycount==1) $name = preg_replace('/(\\'.TRIP_KEY.'.{10})/', '<span class="postertrip">$1</span>', $name); // Trip取消粗體
356                         if($tripkeycount==2) $name = preg_replace('/(\\'.TRIP_KEY.TRIP_KEY.'.{16})/', '<span class="postertrip">$1</span>', $name); // Trip取消粗體
357                         if($tripkeycount==3) $name = preg_replace('/(\\'.TRIP_KEY.'.{32})/', '<span class="postertrip">$1</span>', $name); // Trip取消粗體
358                         if($email) $name = "<a href=\"mailto:$email\" class=\"linkmail\">$name</a>";
359                 }
360
361                 if(AUTO_LINK) $com = auto_link($com);
362                 $com = quoteLight($com);
363                 $com = quoteLight2($com);
364                 if(!$resno && $config['LINE_NUMBER']) list($com, $abbreviated) = abbreviate($com, $config['LINE_NUMBER']);
365                 if(isset($abbreviated) && $abbreviated && $config['LINE_NUMBER']) $com .= '<br /><span class="abbrev">'._T('long_comment').'<a href="'.PHP_SELF.'?res='.$tree[0].'#r'.$no.'">'._T('long_here').'</a>'._T('long_see').'</span>';
366
367                 if(USE_QUOTESYSTEM && $i){ // 啟用引用瀏覽系統
368                         if(preg_match_all('/((?:&gt;|>)+)(?:No\.)?(\d+)/i', $com, $matches, PREG_SET_ORDER)){ // 找尋>>No.xxx
369                                 $matches_unique = array();
370                                 foreach($matches as $val){ if(!in_array($val, $matches_unique)) array_push($matches_unique, $val); }
371                                 foreach($matches_unique as $val){
372                                         if(isset($tree_clone[$val[2]])){
373                                                 $r_page = $tree_clone[$val[2]]; // 引用回應在整體討論串中的位置
374                                                 // 在此頁顯示區間內,輸出錨點即可
375                                                 if(isset($tree_cut[$val[2]])) $com = str_replace($val[0], '<span class="reflink"><a class="qlink" href="#r'.$val[2].'" onclick="replyhl('.$val[2].');">'.$val[0].'</a></span>', $com);
376                                                 // 非此頁顯示區間,輸出完整頁面位置
377                                                 else $com = str_replace($val[0], '<span class="reflink"><a class="qlink" href="'.PHP_SELF.'?res='.$tree[0].(RE_PAGE_DEF ? '&amp;page_num='.floor(($r_page - 1) / RE_PAGE_DEF) : '').'#r'.$val[2].'">'.$val[0].'</a></span>', $com);
378                                         }
379                                 }
380                         }
381                 }
382
383                 // 設定附加圖檔顯示
384                 if($ext && !$FileIO->imageExists($tim.$ext)){
385                         $imgsrc = '<img src="'.ICON_DIR.'filedeleted.gif" class="img" alt="'.$imgsize.'" title="'.$imgsize.'" />';
386                 }elseif($ext && $FileIO->imageExists($tim.$ext)){
387                         $imageURL = $FileIO->getImageURL($tim.$ext); // image URL
388                         $thumbURL = $FileIO->getImageURL($tim.'s.jpg'); // thumb URL
389
390                         //----$imgsrc = '<a href="'.$imageURL.'" rel="_blank"><img src="'.ICON_DIR.'nothumb.gif" class="img" alt="'.$imgsize.'" title="'.$imgsize.'" /></a>'; // 預設顯示圖樣式 (無預覽圖時)
391                         $imgsrc = '<a href="'.$imageURL.'" rel="_blank"><span class="tn_reply" title="'.$imgsize.'">'._T('nothumb').'</span></a>'; // 預設顯示圖樣式 (無預覽圖時)
392                         if($tw && $th){
393                                 if($FileIO->imageExists($tim.'s.jpg')){ // 有預覽圖
394                                         $img_thumb = '<br /><small><span class="thumbnailmsg">'._T('img_sample').'</span></small>';
395                                         $imgsrc = '<a href="'.$imageURL.'" rel="_blank"><img src="'.$thumbURL.'" style="width: '.$tw.'px; height: '.$th.'px;" class="img" alt="'.$imgsize.'" title="'.$imgsize.'" /></a>';
396                                 }elseif($ext=='.swf') $imgsrc = ''; // swf檔案不需預覽圖
397                         }
398                         if(SHOW_IMGWH) $imgwh_bar = ', '.$imgw.'x'.$imgh; // 顯示附加圖檔之原檔長寬尺寸
399                         if(SHOW_FILENAME){
400                                 $longname = $shortname = '';
401                                 if($filename){
402                                         $longname = $filename.$ext;
403                                         if(strlen($filename) > 40) $shortname = substr($filename, 0, 40).'(....)'.$ext;
404                                         else $shortname = $longname;
405                                 }
406                         }
407                         if($longname) $imgfn_bar = ', <span title="'.$longname.'">'.$shortname.'</span>';
408                         $IMG_BAR = '<span class="filesize">'._T('img_filename').'<a href="'.$imageURL.'" rel="_blank">'.$tim.$ext.'</a>-('.$imgsize.$imgwh_bar.$imgfn_bar.')</span>'.$img_thumb;
409                 }
410
411                 // 設定回應 / 引用連結
412                 if($resno){ // 回應模式
413                         if($showquotelink) $QUOTEBTN = '<span class="reflink"><a href="'.PHP_SELF.'?res='.$tree[0].'#r'.$no.'" onclick="return replyhl('.$no.');">No.</a><a href="javascript:quote('.$no.');" class="qlink">'.$no.'</a></span>';
414                         else $QUOTEBTN = '<span class="reflink"><a href="'.PHP_SELF.'?res='.$tree[0].'#r'.$no.'" onclick="return replyhl('.$no.');">No.</a><a href="'.PHP_SELF.'?res='.$tree.'&amp;page_num=all#r'.$no.'" class="qlink">'.$no.'</a></span>';
415                 }else{
416                         if(!$i) $REPLYBTN = '[<a href="'.PHP_SELF.'?res='.$no.'">'._T('reply_btn').'</a>]'; // 首篇
417                         $QUOTEBTN = '<span class="reflink"><a href="'.PHP_SELF.'?res='.$tree[0].'#r'.$no.'">No.</a><a href="'.PHP_SELF.'?res='.$tree[0].'#q'.$no.'" class="qlink">'.$no.'</a></span>';
418                 }
419                 if($adminMode){ // 前端管理模式
420                         $modFunc = '';
421                         $PMS->useModuleMethods('AdminList', array(&$modFunc, $posts[$i], $resto)); // "AdminList" Hook Point
422                         $QUOTEBTN .= $modFunc;
423                 }
424
425                 // 設定討論串屬性
426                 if(STORAGE_LIMIT && $kill_sensor) if(isset($arr_kill[$no])) $WARN_BEKILL = '<span class="warn_txt">'._T('warn_sizelimit').'</span><br />'."\n"; // 預測刪除過大檔
427                 if(!$i){ // 首篇 Only
428                         if($old_sensor) if(isset($arr_old[$no])) $WARN_OLD = '<span class="oldpost">'._T('warn_oldthread').'</span><br />'."\n"; // 快要被刪除的提示
429                         $flgh = $PIO->getPostStatus($status);
430                         if($flgh->exists('TS')) $WARN_ENDREPLY = '<span class="warn_txt">'._T('warn_locked').'</span><br />'."\n"; // 被標記為禁止回應
431                         if($hiddenReply) $WARN_HIDEPOST = '<span class="omittedposts">'._res($hiddenReply, $hiddenImgs)._T('notice_omitted_reply').'</span><br />'."\n"; // 有隱藏的回應
432                 }
433
434                 // 對類別標籤作自動連結
435                 if(USE_CATEGORY){
436                         $ary_category = explode(',', str_replace('&#44;', ',', $category)); $ary_category = array_map('trim', $ary_category);
437                         $ary_category_count = count($ary_category);
438                         $ary_category2 = array();
439                         for($p = 0; $p < $ary_category_count; $p++){
440                                 if($c = $ary_category[$p]) $ary_category2[] = '<a href="'.PHP_SELF.'?mode=category&amp;c='.urlencode($c).'">'.$c.'</a>';
441                         }
442                         $category = implode(', ', $ary_category2);
443                 }else $category = '';
444
445                 // 最終輸出處
446                 if($i){ // 回應
447                         $arrLabels = array('{$NO}'=>$no, '{$SUB}'=>$sub, '{$NAME}'=>$name, '{$NOW}'=>$now, '{$COM}'=>$com, '{$CATEGORY}'=>$category, '{$QUOTEBTN}'=>$QUOTEBTN, '{$IMG_BAR}'=>$IMG_BAR, '{$IMG_SRC}'=>$imgsrc, '{$WARN_BEKILL}'=>$WARN_BEKILL, '{$QUOTEBTN}'=>$QUOTEBTN, '{$NAME_TEXT}'=>_T('post_name'), '{$CATEGORY_TEXT}'=>_T('post_category'), '{$SELF}'=>PHP_SELF);
448                         if($resno) $arrLabels['{$RESTO}']=$resno;
449                         $PMS->useModuleMethods('ThreadReply', array(&$arrLabels, $posts[$i], $resno)); // "ThreadReply" Hook Point
450                         $thdat .= $PTE->ParseBlock('REPLY',$arrLabels);
451                 }else{ // 首篇
452                         $arrLabels = array('{$NO}'=>$no, '{$SUB}'=>$sub, '{$NAME}'=>$name, '{$NOW}'=>$now, '{$COM}'=>$com, '{$CATEGORY}'=>$category, '{$QUOTEBTN}'=>$QUOTEBTN, '{$REPLYBTN}'=>$REPLYBTN, '{$IMG_BAR}'=>$IMG_BAR, '{$IMG_SRC}'=>$imgsrc, '{$WARN_OLD}'=>$WARN_OLD, '{$WARN_BEKILL}'=>$WARN_BEKILL, '{$WARN_ENDREPLY}'=>$WARN_ENDREPLY, '{$WARN_HIDEPOST}'=>$WARN_HIDEPOST, '{$NAME_TEXT}'=>_T('post_name'), '{$CATEGORY_TEXT}'=>_T('post_category'), '{$SELF}'=>PHP_SELF);
453                         if($resno) $arrLabels['{$RESTO}']=$resno;
454                         $PMS->useModuleMethods('ThreadPost', array(&$arrLabels, $posts[$i], $resno)); // "ThreadPost" Hook Point
455                         $thdat .= $PTE->ParseBlock('THREAD',$arrLabels);
456                 }
457         }
458         $thdat .= $PTE->ParseBlock('THREADSEPARATE',($resno)?array('{$RESTO}'=>$resno):array());
459         return $thdat;
460 }
461
462 /* 寫入記錄檔 */
463 /* 記事書き込み */
464 function regist(){
465         global $config, $PIO, $FileIO, $PMS, $language, $BAD_STRING, $BAD_FILEMD5, $BAD_IPADDR, $LIMIT_SENSOR;
466         $dest = ''; $mes = ''; $up_incomplete = 0; $is_admin = false;
467         $path = realpath('.').DIRECTORY_SEPARATOR; // 此目錄的絕對位置
468
469         if($_SERVER['REQUEST_METHOD'] != 'POST') error(_T('regist_notpost')); // 非正規POST方式
470         // 欄位陷阱
471         $FTname = isset($_POST['name']) ? $_POST['name'] : '';
472         $FTemail = isset($_POST['email']) ? $_POST['email'] : '';
473         $FTsub = isset($_POST['sub']) ? $_POST['sub'] : '';
474         $FTcom = isset($_POST['com']) ? $_POST['com'] : '';
475         $FTreply = isset($_POST['reply']) ? $_POST['reply'] : '';
476         if($FTname != 'spammer' || $FTemail != 'foo@foo.bar' || $FTsub != 'DO NOT FIX THIS' || $FTcom != 'EID OG SMAPS' || $FTreply != '') error(_T('regist_nospam'));
477
478         $name = isset($_POST[FT_NAME]) ? CleanStr($_POST[FT_NAME]) : '';
479         $email = isset($_POST[FT_EMAIL]) ? CleanStr($_POST[FT_EMAIL]) : '';
480         $sub = isset($_POST[FT_SUBJECT]) ? CleanStr($_POST[FT_SUBJECT]) : '';
481         $com = isset($_POST[FT_COMMENT]) ? $_POST[FT_COMMENT] : '';
482         $pwd = isset($_POST['pwd']) ? $_POST['pwd'] : '';
483         $category = isset($_POST['category']) ? CleanStr($_POST['category']) : '';
484         $resto = isset($_POST['resto']) ? intval($_POST['resto']) : 0;
485         $upfile = isset($_FILES['upfile']['tmp_name']) ? $_FILES['upfile']['tmp_name'] : '';
486         $upfile_path = isset($_POST['upfile_path']) ? $_POST['upfile_path'] : '';
487         $upfile_name = isset($_FILES['upfile']['name']) ? $_FILES['upfile']['name'] : false;
488         $ext_ = ereg_replace("^.*\\.", ".", $upfile_name); // filename extention
489         $basename = basename($upfile_name, $ext_); // filename
490         $filename = isset($basename) ? CleanStr($basename) : ''; // cleaned filename
491         $upfile_status = isset($_FILES['upfile']['error']) ? $_FILES['upfile']['error'] : 4;
492         $pwdc = isset($_COOKIE['pwdc']) ? $_COOKIE['pwdc'] : '';
493         $ip = getREMOTE_ADDR(); $host = gethostbyaddr($ip);
494
495         $PMS->useModuleMethods('RegistBegin', array(&$name, &$email, &$sub, &$com, array('file'=>&$upfile, 'path'=>&$upfile_path, 'name'=>&$upfile_name, 'status'=>&$upfile_status), array('ip'=>$ip, 'host'=>$host), $resto)); // "RegistBegin" Hook Point
496         // 封鎖:IP/Hostname/DNSBL 檢查機能
497         $baninfo = '';
498         if(BanIPHostDNSBLCheck($ip, $host, $baninfo)) error(_T('regist_ipfiltered', $baninfo));
499         // 封鎖:限制出現之文字
500         foreach($BAD_STRING as $value){
501                 if(strpos($com, $value)!==false || strpos($sub, $value)!==false || strpos($name, $value)!==false || strpos($email, $value)!==false){
502                         error(_T('regist_wordfiltered'));
503                 }
504         }
505
506         // 檢查是否輸入櫻花日文假名
507         foreach(array($name, $email, $sub, $com) as $anti) if(anti_sakura($anti)) error(_T('regist_sakuradetected'));
508
509         // 時間
510         $time = time();
511         $tim = $time.substr(microtime(),2,3);
512         $tome = time()+0*60*60;
513
514         // 判斷上傳狀態
515         switch($upfile_status){
516                 case 1:
517                         error(_T('regist_upload_exceedphp'));
518                         break;
519                 case 2:
520                         error(_T('regist_upload_exceedcustom'));
521                         break;
522                 case 3:
523                         error(_T('regist_upload_incompelete'));
524                         break;
525                 case 6:
526                         error(_T('regist_upload_direrror'));
527                         break;
528                 case 4: // 無上傳
529                         if(NO_TEXTONLY == 2){
530                                 if(!$resto) error(_T('regist_upload_noimg'));
531                         }elseif(NO_TEXTONLY == 1){
532                                 if(!$resto && !isset($_POST['noimg'])) error(_T('regist_upload_noimg'));
533                         }
534                         break;
535                 case 0: // 上傳正常
536                 default:
537         }
538
539         // 如果有上傳檔案則處理附加圖檔
540         if($upfile && (@is_uploaded_file($upfile) || @is_file($upfile))){
541                 // 一‧先儲存檔案
542                 $dest = $path.TEMP_DIR.$tim.'.temp';
543                 @move_uploaded_file($upfile, $dest) or @copy($upfile, $dest);
544                 @chmod($dest, 0666);
545                 if(!is_file($dest)) error(_T('regist_upload_filenotfound'), $dest);
546
547                 // 二‧判斷上傳附加圖檔途中是否有中斷
548                 $upsizeTTL = $_SERVER['CONTENT_LENGTH'];
549                 if(isset($_FILES['upfile'])){ // 有傳輸資料才需要計算,避免作白工
550                         $upsizeHDR = 0;
551                         // 檔案路徑:IE附完整路徑,故得從隱藏表單取得
552                         $tmp_upfile_path = $upfile_name;
553                         if($upfile_path) $tmp_upfile_path = get_magic_quotes_gpc() ? stripslashes($upfile_path) : $upfile_path;
554                         list(,$boundary) = explode('=', $_SERVER['CONTENT_TYPE']);
555                         foreach($_POST as $header => $value){ // 表單欄位傳送資料
556                                 $upsizeHDR += strlen('--'.$boundary."\r\n");
557                                 $upsizeHDR += strlen('Content-Disposition: form-data; name="'.$header.'"'."\r\n\r\n".(get_magic_quotes_gpc()?stripslashes($value):$value)."\r\n");
558                         }
559                         // 附加圖檔欄位傳送資料
560                         $upsizeHDR += strlen('--'.$boundary."\r\n");
561                         $upsizeHDR += strlen('Content-Disposition: form-data; name="upfile"; filename="'.$tmp_upfile_path."\"\r\n".'Content-Type: '.$_FILES['upfile']['type']."\r\n\r\n");
562                         $upsizeHDR += strlen("\r\n--".$boundary."--\r\n");
563                         $upsizeHDR += $_FILES['upfile']['size']; // 傳送附加圖檔資料量
564                         // 上傳位元組差值超過 HTTP_UPLOAD_DIFF:上傳附加圖檔不完全
565                         if(($upsizeTTL - $upsizeHDR) > HTTP_UPLOAD_DIFF){
566                                 if(KILL_INCOMPLETE_UPLOAD){
567                                         unlink($dest);
568                                         die(_T('regist_upload_killincomp')); // 給瀏覽器的提示,假如使用者還看的到的話才不會納悶
569                                 }else $up_incomplete = 1;
570                         }
571                 }
572
573                 // 三‧檢查是否為可接受的檔案
574                 $size = @getimagesize($dest);
575                 if(!is_array($size)) error(_T('regist_upload_notimage'), $dest); // $size不為陣列就不是圖檔
576                 $imgsize = @filesize($dest); // 檔案大小
577                 if(!$config['KB']) $imgsize .= ' B'; // Bytes only
578                 else $imgsize = ($imgsize>=1024) ? (int)($imgsize/1024).' KB' : $imgsize.' B'; // KB和B的判別
579                 switch($size[2]){ // 判斷上傳附加圖檔之格式
580                         case 1 : $ext = ".gif"; break;
581                         case 2 : $ext = ".jpg"; break;
582                         case 3 : $ext = ".png"; break;
583                         case 4 : $ext = ".swf"; break;
584                         case 5 : $ext = ".psd"; break;
585                         case 6 : $ext = ".bmp"; break;
586                         case 7 : $ext = ".tiff"; break;
587                         case 8 : $ext = ".tiff"; break;
588                         case 9 : $ext = ".jpc"; break;
589                         case 10 : $ext = ".jp2"; break;
590                         case 11 : $ext = ".jpx"; break;
591                         case 12 : $ext = ".jb2"; break;
592                         case 13 : $ext = ".swf"; break;
593                         case 14 : $ext = ".aiff"; break;
594                         case 15 : $ext = ".wbmp"; break;
595                         case 16 : $ext = ".xbm"; break; // I add more media support (^^,)
596                         default : $ext = ".xxxx"; error(_T('regist_upload_notsupport'), $dest);
597                 }
598                 $allow_exts = explode('|', strtolower(ALLOW_UPLOAD_EXT)); // 接受之附加圖檔副檔名
599                 if(array_search(substr($ext, 1), $allow_exts)===false) error(_T('regist_upload_notsupport'), $dest); // 並無在接受副檔名之列
600                 // 封鎖設定:限制上傳附加圖檔之MD5檢查碼
601                 $md5chksum = md5_file($dest); // 檔案MD5
602                 if(array_search($md5chksum, $BAD_FILEMD5)!==FALSE) error(_T('regist_upload_blocked'), $dest); // 在封鎖設定內則阻擋
603
604                 // 四‧計算附加圖檔圖檔縮圖顯示尺寸 //++++---- <- the comment from pixmicat team is broken here 
605                 $W = $imgW = $size[0];
606                 $H = $imgH = $size[1];
607                 $MAXW = $resto ? MAX_RW : MAX_W;
608                 $MAXH = $resto ? MAX_RH : MAX_H;
609                 if($W > $MAXW || $H > $MAXH){
610                         $W2 = $MAXW / $W;
611                         $H2 = $MAXH / $H;
612                         $key = ($W2 < $H2) ? $W2 : $H2;
613                         $W = ceil($W * $key);
614                         $H = ceil($H * $key);
615                 }
616                 $mes = _T('regist_uploaded', CleanStr($upfile_name));
617         }
618
619         // 檢查表單欄位內容並修整
620         if(strlen($name) > 100) error(_T('regist_nametoolong'), $dest);
621         if(strlen($email) > 100) error(_T('regist_emailtoolong'), $dest);
622         if(strlen($sub) > 100) error(_T('regist_topictoolong'), $dest);
623         if(strlen($resto) > 10) error(_T('regist_longthreadnum'), $dest);
624
625         // E-mail / 標題修整
626         $email = str_replace("\r\n", '', $email); $sub = str_replace("\r\n", '', $sub);
627
628         // Tripcode area--------------------------------------------------------------------------------
629         if($name){
630                 // 名稱修整
631                 $name = str_replace(TRIP_KEY, TRIP_KEY_FAKE, $name); // 防止トリップ偽造
632                 $name = str_replace($config['CAP.SUFFIX'], $config['CAP.SUFFIX.FAKE'], $name); // 防止管理員キャップ偽造
633                 $name = str_replace("\r\n", '', $name);
634                 $nameOri = $name; // 名稱
635                 // トリップ
636                 //----if(preg_match('/(.*?)[##](.*)/u', $name, $regs)){ // トリップ(Trip)機能
637                         //----$name = $nameOri = $regs[1]; $cap = strtr($regs[2], array('&amp;'=>'&'));
638                         //----$salt = preg_replace('/[^\.-z]/', '.', substr($cap.'H.', 1, 2));
639                         //----$salt = strtr($salt, ':;<=>?@[\\]^_`', 'ABCDEFGabcdef');
640                         //----$name = $name.TRIP_KEY.substr(crypt($cap, $salt), -10);
641                 if(preg_match('/(.*?)[##](.*)/u', $name, $regs)){ // トリップ(Trip)機能
642                         $name = str_replace("&#", "&%%%%%%", $name); # otherwise HTML numeric entities screw up explode()!
643                         list($name, $trip, $sectrip) = str_replace("&&", "&%%%%%%", explode("#", $name));
644
645                         if($trip != ''){
646                                 if(function_exists("iconv")) $trip = iconv("UTF-8", "SHIFT_JIS//TRANSLIT", $trip); // convert to Windows Japanese #&#65355;&#65345;&#65357;&#65353;
647                                 $salt = strtr(preg_replace('/[^\.-z]/', '.', substr($trip.'H.', 1, 2)), ':;<=>?@[\\]^_`', 'ABCDEFGabcdef');
648                                 $metrip = TRIP_KEY.substr(crypt($trip, $salt), -10);
649                         }else $metrip = '';
650                         if($sectrip != ''){
651                                 if(function_exists("iconv")) $sectrip = iconv("UTF-8", "SHIFT_JIS//TRANSLIT", $sectrip); // convert to Windows Japanese #&#65355;&#65345;&#65357;&#65353;
652                                 $salt = "LOLLOLOLOLOLOLOLOLOLOLOLOLOLOLOLMEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE"; # this is ONLY used if the host doesn't have openssl # I don't know a better way to get random data
653                                 if(file_exists(SALTFILE)){ # already generated a key
654                                         $salt = file_get_contents(SALTFILE);
655                                 }else{
656                                         system("openssl rand 448 > '".SALTFILE, $err);
657                                         if($err === 0){
658                                                 if(chmod(SALTFILE,0400)){
659                                                         $salt = file_get_contents(SALTFILE);
660                                                 }else{
661                                                         $donk = IDSEED;
662                                                         $fp = fopen(SALTFILE, "w");
663                                                         fputs($fp, $donk);
664                                                         fclose($fp);
665                                                 }
666                                         }
667                                 }
668                                 $sha = base64_encode(pack("H*", sha1($sectrip.$salt)));
669                                 $sha = substr($sha, 0, 16);
670                                 $metrip .= TRIP_KEY.TRIP_KEY.$sha;
671                         }
672                         // Tripcode filter
673                         //++++if(file_exists(FILTER_DIR)){
674                                 //++++include(FILTER_DIR.'trip.php');
675                         //++++}
676                         //----"</b></font><font class=\"postertrip\">".
677                         $name .= $metrip;
678                 }
679                 if($config['CAP.ENABLE'] && preg_match('/(.*?)[##](.*)/u', $email, $aregs)){ // 管理員キャップ(Cap)機能
680                         $acap_name = $nameOri; $acap_pwd = strtr($aregs[2], array('&amp;'=>'&'));
681                         if($acap_name==$config['CAP.NAME'] && $acap_pwd==$config['CAP.PASSWORD']){
682                                 $name = '<span class="admin_cap">'.$name.$config['CAP.SUFFIX'].'</span>';
683                                 $is_admin = true;
684                                 $email = $aregs[1]; // 去除 #xx 密碼
685                         }
686                 }
687                 if(!$is_admin){ // 非管理員
688                         $name = str_replace(_T('admin'), '"'._T('admin').'"', $name);
689                         $name = str_replace(_T('deletor'), '"'._T('deletor').'"', $name);
690                 }
691                 $name = str_replace('&'.TRIP_KEY, '&amp;'.TRIP_KEY, $name); // 避免 &#xxxx; 後面被視為 Trip 留下 & 造成解析錯誤
692         }
693         // End of Tripcode area--------------------------------------------------------------------------
694
695         // 內文修整
696         if((strlen($com) > COMM_MAX) && !$is_admin) error(_T('regist_commenttoolong'), $dest);
697         $com = CleanStr($com, $is_admin); // 引入$is_admin參數是因為當管理員キャップ啟動時,允許管理員依config設定是否使用HTML
698         if(!$com && $upfile_status==4) error(_T('regist_withoutcomment'));
699         $com = str_replace(array("\r\n", "\r"), "\n", $com); $com = ereg_replace("\n(( | )*\n){4,}", "\n", $com);
700         if(!BR_CHECK || substr_count($com,"\n") < BR_CHECK) $com = nl2br($com); // 換行字元用<br />代替
701         $com = str_replace("\n", '', $com); // 若還有\n換行字元則取消換行
702         // 預設的內容
703         if(!$name || ereg("^[ | |]*$", $name)){
704                 if($config['ALLOW_NONAME']) $name = $config['DEFAULT_NONAME'];
705                 else error(_T('regist_withoutname'), $dest);
706         }
707         if(!$sub || ereg("^[ | |]*$", $sub)){
708                 if($config['ALLOW_NOSUB']) $sub = $config['DEFAULT_NOTITLE'];
709                 else error(_T('regist_withoutsubject'), $dest);
710         }
711         if(!$com || ereg("^[ | |\t]*$", $com)){
712                 if($config['ALLOW_NOCOM']) $com = $config['DEFAULT_NOCOMMENT'];
713                 else error(_T('regist_withoutcomment'), $dest);
714         }
715         // 修整標籤樣式
716         if($category && USE_CATEGORY){
717                 $category = explode(',', $category); // 把標籤拆成陣列
718                 $category = ','.implode(',', array_map('trim', $category)).','; // 去空白再合併為單一字串 (左右含,便可以直接以,XX,形式搜尋)
719         }else{ $category = ''; }
720         if($up_incomplete) $com .= '<br /><br /><span class="warn_txt">'._T('notice_incompletefile').'</span>'; // 上傳附加圖檔不完全的提示
721
722         // 密碼和時間的樣式 
723         if($pwd=='') if($config['ALLOW_NOPASS']) error(_T('regist_withoutpassword'), $dest); else $pwd = ($pwdc=='') ? substr(rand(),0,8) : $pwdc;
724         $pass = $pwd ? substr(md5($pwd), 2, 8) : '*'; // 生成真正儲存判斷用的密碼
725         $youbi = array(_T('sun'),_T('mon'),_T('tue'),_T('wed'),_T('thu'),_T('fri'),_T('sat'));
726 //----  $yd = $youbi[gmdate('w', $time+TIME_ZONE*60*60)];
727         $yd = $youbi[date('w', $tome)];
728 //----  $now = gmdate('y/m/d', $time+TIME_ZONE*60*60).'('.(string)$yd.')'.gmdate('H:i', $time+TIME_ZONE*60*60);
729         $now = date($config['DATE_FORMAT'], $tome).'('.(string)$yd.')'.date($config['TIME_FORMAT'], $tome);
730
731 //----  if(DISP_ID){ // 顯示ID
732 //----          if($email && DISP_ID==1) $now .= ' ID:????';
733 //----          else $now .= ' ID:'.substr(crypt(md5(getREMOTE_ADDR().IDSEED.gmdate('Ymd', $time+TIME_ZONE*60*60)),'id'), -8);
734 //----  }
735         if(DISP_ID){ // 顯示ID
736                 if($email&&DISP_ID==1) $now .= " ID:????";
737                 else $now .= " ID:".substr(crypt(md5(getREMOTE_ADDR().IDSEED.date($config['DATE_FORMAT'], $tome)),'id'), -8);
738         }
739
740         // 連續投稿 / 相同附加圖檔檢查
741         $checkcount = 50; // 預設檢查50筆資料
742         $pwdc = substr(md5($pwdc), 2, 8); // Cookies密碼
743         if($PIO->isSuccessivePost($checkcount, $com, $time, $pass, $pwdc, $host, $upfile_name)) error(_T('regist_successivepost'), $dest); // 連續投稿檢查
744         if($dest){ if($PIO->isDuplicateAttachment($checkcount, $md5chksum)) error(_T('regist_duplicatefile'), $dest); } // 相同附加圖檔檢查
745         if($resto) $ThreadExistsBefore = $PIO->isThread($resto);
746
747         // 舊文章刪除處理
748         if(PIOSensor::check('delete', $LIMIT_SENSOR)){
749                 $delarr = PIOSensor::listee('delete', $LIMIT_SENSOR);
750                 if(count($delarr)){
751                         deleteCache($delarr);
752                         $PMS->useModuleMethods('PostOnDeletion', array($delarr, 'recycle')); // "PostOnDeletion" Hook Point
753                         $files = $PIO->removePosts($delarr);
754                         if(count($files)) $FileIO->deleteImage($files);
755                 }
756         }
757
758         // 附加圖檔容量限制功能啟動:刪除過大檔
759         if(STORAGE_LIMIT && STORAGE_MAX > 0){
760                 $tmp_total_size = total_size(); // 取得目前附加圖檔使用量
761                 if($tmp_total_size > STORAGE_MAX){
762                         $files = $PIO->delOldAttachments($tmp_total_size, STORAGE_MAX, false);
763                         $FileIO->deleteImage($files);
764                 }
765         }
766
767         // 判斷欲回應的文章是不是剛剛被刪掉了
768         if($resto){
769                 if($ThreadExistsBefore){ // 欲回應的討論串是否存在
770                         if(!$PIO->isThread($resto)){ // 被回應的討論串存在但已被刪
771                                 // 提前更新資料來源,此筆新增亦不紀錄
772                                 $PIO->dbCommit();
773                                 updatelog();
774                                 error(_T('regist_threaddeleted'), $dest);
775                         }else{ // 檢查是否討論串被設為禁止回應 (順便取出原討論串的貼文時間)
776                                 $post = $PIO->fetchPosts($resto); // [特殊] 取單篇文章內容,但是回傳的$post同樣靠[$i]切換文章!
777                                 list($chkstatus, $chktime) = array($post[0]['status'], $post[0]['tim']);
778                                 $chktime = substr($chktime, 0, -3); // 拿掉微秒 (後面三個字元)
779                                 $flgh = $PIO->getPostStatus($chkstatus);
780                                 if($flgh->exists('TS')) error(_T('regist_threadlocked'), $dest);
781                         }
782                 }else error(_T('thread_not_found'), $dest); // 不存在
783         }
784
785         // 計算某些欄位值
786         $no = $PIO->getLastPostNo('beforeCommit') + 1;
787         isset($ext) ? 0 : $ext = '';
788         isset($imgW) ? 0 : $imgW = 0;
789         isset($imgH) ? 0 : $imgH = 0;
790         isset($imgsize) ? 0 : $imgsize = '';
791         isset($W) ? 0 : $W = 0;
792         isset($H) ? 0 : $H = 0;
793         isset($md5chksum) ? 0 : $md5chksum = '';
794         $age = false;
795         $status = '';
796         if(USE_UPSERIES && stristr($email, 'noko')){
797                 $email = false;
798                 $noko = true;
799         }else $noko = false;
800         if($resto){
801                 if(!stristr($email, 'sage') && ($PIO->postCount($resto) <= MAX_RES || MAX_RES==0)){
802                         if(!MAX_AGE_TIME || (($time - $chktime) < (MAX_AGE_TIME * 60 * 60))) $age = true; // 討論串並無過期,推文
803                 }
804         }
805         $PMS->useModuleMethods('RegistBeforeCommit', array(&$name, &$email, &$sub, &$com, &$category, &$age, $dest, $resto, array($W, $H, $imgW, $imgH), &$status)); // "RegistBeforeCommit" Hook Point
806
807         // 正式寫入儲存
808         $PIO->addPost($no,$resto,$md5chksum,$category,$tim,$ext,$imgW,$imgH,$imgsize,$filename,$W,$H,$pass,$now,$name,$email,$sub,$com,$host,$age,$status);
809 //----  $PIO->addPost($no,$now,$name,$email,$sub,$com,$age,$status,$host,$pwd,$ext,$W,$H,$tim,$md5chksum,$imgsize,$filename,$imgW,$imgH,$category,$resto);
810         $PIO->dbCommit();
811         $lastno = $PIO->getLastPostNo('afterCommit'); // 取得此新文章編號
812         $PMS->useModuleMethods('RegistAfterCommit', array($lastno, $resto, $name, $email, $sub, $com)); // "RegistAfterCommit" Hook Point
813
814         // noko in cookie
815         if($noko) $email = 'noko';
816
817         // Cookies儲存:密碼與E-mail部分,期限是一週
818         setcookie('pwdc', $pwd, time()+7*24*3600, '/');
819         setcookie('emailc', $email, time()+7*24*3600, '/');
820         total_size(true); // 刪除舊容量快取
821         if($dest && is_file($dest)){
822                 $destFile = $path.IMG_DIR.$tim.$ext; // 圖檔儲存位置
823                 $thumbFile = $path.THUMB_DIR.$tim.'s.jpg'; // 預覽圖儲存位置
824                 rename($dest, $destFile);
825                 if(USE_THUMB !== 0){ // 生成預覽圖
826                         $thumbType = USE_THUMB; if(USE_THUMB==1){ $thumbType = 'gd'; } // 與舊設定相容
827                         require(PHP_DIRECTORY.'lib/thumb/thumb.'.$thumbType.'.php');
828                         $thObj = new ThumbWrapper($destFile, $imgW, $imgH);
829                         $thObj->setThumbnailConfig($W, $H, THUMB_Q);
830                         $thObj->makeThumbnailtoFile($thumbFile);
831                         @chmod($thumbFile, 0666);
832                         unset($thObj);
833                 }
834                 if($FileIO->uploadImage()){ // 支援上傳圖片至其他伺服器
835                         if(file_exists($destFile)) $FileIO->uploadImage($tim.$ext, $destFile, filesize($destFile));
836                         if(file_exists($thumbFile)) $FileIO->uploadImage($tim.'s.jpg', $thumbFile, filesize($thumbFile));
837                 }
838         }
839         updatelog();
840
841         // 引導使用者至新頁面
842         $RedirURL = PHP_SELF2.'?'.$tim; // 定義儲存資料後轉址目標
843         if(isset($_POST['up_series']) || $noko){ // 勾選連貼機能
844                 if($resto) $RedirURL = PHP_SELF.'?res='.$resto.'&amp;upseries=1'; // 回應後繼續轉回此主題下
845                 else{
846                         $RedirURL = PHP_SELF.'?res='.$lastno.'&amp;upseries=1'; // 新增主題後繼續轉到此主題下
847                 }
848         }
849         $RedirforJS = strtr($RedirURL, array("&amp;"=>"&")); // JavaScript用轉址目標
850
851         echo '<?xml version="1.0" encoding="UTF-8"?>'."\n";
852         echo <<< _REDIR_
853 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
854 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="'.PIXMICAT_LANGUAGE.'">
855 <head>
856 <title></title>
857 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
858 <meta http-equiv="Refresh" content="1;URL=$RedirURL" />
859 <script type="text/javascript">
860 // Redirection (use JS)
861 // <![CDATA[
862 function redir(){
863         location.href = "$RedirforJS";
864 }
865 setTimeout("redir()", 1000);
866 // ]]>
867 </script>
868 </head>
869 <body>
870 <div>
871 _REDIR_;
872 echo _T('regist_redirect',$mes,$RedirURL).'</div>
873 </body>
874 </html>';
875 }
876
877 /* 使用者刪除 */
878 /* ユーザー削除 */
879 function usrdel(){
880         global $PIO, $FileIO, $PMS, $language;
881         // $pwd: 使用者輸入值, $pwdc: Cookie記錄密碼
882         $pwd = isset($_POST['pwd']) ? $_POST['pwd'] : '';
883         $pwdc = isset($_COOKIE['pwdc']) ? $_COOKIE['pwdc'] : '';
884         $onlyimgdel = isset($_POST['onlyimgdel']) ? $_POST['onlyimgdel'] : '';
885         $delno = array();
886         reset($_POST);
887         while($item = each($_POST)){ if($item[1]=='delete' && $item[0] != 'func') array_push($delno, $item[0]); }
888         $haveperm = ($pwd==ADMIN_PASS) || adminAuthenticate('check');
889         if($haveperm && isset($_POST['func'])){ // 前端管理功能
890                 $message = '';
891                 $PMS->useModuleMethods('AdminFunction', array('run', $delno, $_POST['func'], &$message)); // "AdminFunction" Hook Point
892                 if($_POST['func'] != 'delete'){
893                         if(isset($_SERVER['HTTP_REFERER'])){
894                                 header('HTTP/1.1 302 Moved Temporarily');
895                                 header('Location: '.$_SERVER['HTTP_REFERER']);
896                         }
897                         exit(); // 僅執行AdminFunction,終止刪除動作
898                 }
899         }
900         $PMS->useModuleMethods('Authenticate', array($pwd,'userdel',&$haveperm));
901
902         if($pwd=='' && $pwdc!='') $pwd = $pwdc;
903         $pwd_md5 = substr(md5($pwd),2,8);
904         $host = gethostbyaddr(getREMOTE_ADDR());
905         $search_flag = $delflag = false;
906
907         if(!count($delno)) error(_T('del_notchecked'));
908
909         $delposts = array(); // 真正符合刪除條件文章
910         $posts = $PIO->fetchPosts($delno);
911         foreach($posts as $post){
912                 if($pwd_md5==$post['pwd'] || $host==$post['host'] || $haveperm){
913                         $search_flag = true; // 有搜尋到
914                         array_push($delposts, $post['no']);
915                 }
916         }
917         if($search_flag){
918                 if(!$onlyimgdel) $PMS->useModuleMethods('PostOnDeletion', array($delposts, 'frontend')); // "PostOnDeletion" Hook Point
919                 $files = $onlyimgdel ? $PIO->removeAttachments($delposts) : $PIO->removePosts($delposts);
920                 $FileIO->deleteImage($files);
921                 deleteCache($delposts);
922                 total_size(true); // 刪除容量快取
923                 $PIO->dbCommit();
924         }else error(_T('del_wrongpwornotfound'));
925         if(isset($_POST['func']) && $_POST['func'] == 'delete'){ // 前端管理刪除文章返回管理頁面
926                 if(isset($_SERVER['HTTP_REFERER'])){
927                         header('HTTP/1.1 302 Moved Temporarily');
928                         header('Location: '.$_SERVER['HTTP_REFERER']);
929                 }
930                 exit();
931         }
932 }
933
934 /* 管理員密碼認證 */
935 /* パス認証 */
936 function valid(){
937         global $PMS, $language;
938         $pass = isset($_POST['pass']) ? $_POST['pass'] : ''; // 管理者密碼
939         $haveperm = false;
940         $isCheck = adminAuthenticate('check'); // 登入是否正確
941         if(!$isCheck && $pass){
942                 $haveperm = ($pass == ADMIN_PASS);
943                 $PMS->useModuleMethods('Authenticate', array($pass,'admin',&$haveperm));
944                 if($haveperm){ adminAuthenticate('login'); $isCheck = true; }
945                 else error(_T('admin_wrongpassword'));
946         }
947         $dat = '';
948         head($dat);
949         $links = '[<a href="'.PHP_SELF2.'?'.time().'">'._T('return').'</a>] [<a href="'.PHP_SELF.'?mode=remake">'._T('admin_remake').'</a>] [<a href="'.PHP_SELF.'?page_num=0">'._T('admin_frontendmanage').'</a>]';
950         $PMS->useModuleMethods('LinksAboveBar', array(&$links,'admin',$isCheck)); // LinksAboveBar hook point
951         $dat .= '<div id="bannerlink">'.$links.'</div><div id="banner"><div class="passvalid">'._T('admin_top').'</div>
952 </div>
953 <form action="'.PHP_SELF.'" method="post" id="adminform">
954 <div id="admin-check" style="text-align: center;">
955 ';//----class="bar_admin"
956         echo $dat;
957         if(!$isCheck){
958                 echo '<br />
959 <input type="radio" name="admin" value="del" checked="checked" />'._T('admin_manageposts').'
960 <input type="radio" name="admin" value="optimize" />'._T('admin_optimize').'
961 <input type="radio" name="admin" value="check" />'._T('admin_check').'
962 <input type="radio" name="admin" value="repair" />'._T('admin_repair').'
963 <input type="radio" name="admin" value="export" />'._T('admin_export').'
964 <input type="radio" name="admin" value="stylesheets" />'._T('admin_stylesheets').'<p />
965 <input type="hidden" name="mode" value="admin" />
966 <input class="inputtext" type="password" name="pass" size="8" />
967 <input type="submit" value="'._T('admin_verify_btn').'" />
968 </div>
969 </form>';
970                 die("\n</body>\n</html>");
971         }elseif(!isset($_REQUEST['admin'])){
972                 echo '<br />
973 <input type="radio" name="admin" value="del" checked="checked" />'._T('admin_manageposts').'
974 <input type="radio" name="admin" value="optimize" />'._T('admin_optimize').'
975 <input type="radio" name="admin" value="check" />'._T('admin_check').'
976 <input type="radio" name="admin" value="repair" />'._T('admin_repair').'
977 <input type="radio" name="admin" value="export" />'._T('admin_export').'
978 <input type="radio" name="admin" value="stylesheets" />'._T('admin_stylesheets').'
979 <input type="radio" name="admin" value="logout" />'._T('admin_logout').'<p />
980 <input type="hidden" name="mode" value="admin" />
981 <input type="submit" value="'._T('admin_submit_btn').'" />
982 </div>
983 </form>';
984                 die("\n</body>\n</html>");
985         }
986 }
987
988 /* 管理文章模式 */
989 /* 管理者削除 */
990 function admindel(){
991         global $PIO, $FileIO, $PMS, $language;
992
993         $pass = isset($_POST['pass']) ? $_POST['pass'] : ''; // 管理者密碼
994         $page = isset($_REQUEST['page']) ? $_REQUEST['page'] : 0; // 切換頁數
995         $onlyimgdel = isset($_POST['onlyimgdel']) ? $_POST['onlyimgdel'] : ''; // 只刪圖
996         $modFunc = '';
997         $delno = $thsno = array();
998         $delflag = isset($_POST['func']) && ($_POST['func'] == 'delete') && isset($_POST['clist']); // 是否有「刪除」勾選
999         $thsflag = isset($_POST['stop']); // 是否有「停止」勾選
1000         $is_modified = false; // 是否改寫檔案
1001         $message = ''; // 操作後顯示訊息
1002
1003         if(isset($_POST['func']) && isset($_POST['clist']))
1004                 $PMS->useModuleMethods('AdminFunction', array('run', $_POST['clist'], $_POST['func'], &$message)); // "AdminFunction" Hook Point
1005
1006         // 刪除文章區塊
1007         if($delflag){
1008                 //if(!adminAuthenticate('check')) error(_T('admin_wrongpassword'));
1009
1010                 $delno = array_merge($delno, $_POST['clist']);
1011                 if($onlyimgdel != 'on') $PMS->useModuleMethods('PostOnDeletion', array($delno, 'backend')); // "PostOnDeletion" Hook Point
1012                 $files = ($onlyimgdel != 'on') ? $PIO->removePosts($delno) : $PIO->removeAttachments($delno);
1013                 $FileIO->deleteImage($files);
1014                 deleteCache($delno);
1015                 total_size(true); // 刪除容量快取
1016                 $is_modified = true;
1017         }
1018         // 討論串停止區塊
1019         if($thsflag){
1020                 //if(!adminAuthenticate('check')) error(_T('admin_wrongpassword'));
1021
1022                 $thsno = array_merge($thsno, $_POST['stop']);
1023                 $threads = $PIO->fetchPosts($thsno); // 取得文章
1024                 foreach($threads as $th){
1025                         $flgh = $PIO->getPostStatus($th['status']);
1026                         $flgh->toggle('TS');
1027                         $PIO->setPostStatus($th['no'], $flgh->toString());
1028                 }
1029                 $is_modified = true;
1030         }
1031         if(($delflag || $thsflag) && $is_modified) $PIO->dbCommit(); // 無論如何都有檔案操作,回寫檔案
1032
1033         $line = $PIO->fetchPostList(0, $page * ADMIN_PAGE_DEF, ADMIN_PAGE_DEF); // 分頁過的文章列表
1034         $posts_count = count($line); // 迴圈次數
1035         $posts = $PIO->fetchPosts($line); // 文章內容陣列
1036
1037         echo '<input type="hidden" name="mode" value="admin" />
1038 <input type="hidden" name="admin" value="del" />
1039 <div style="text-align: left;">'._T('admin_notices').'</div>
1040 <div>'.$message.'</div>
1041 <table border="1" cellspacing="0" style="margin: 0px auto;">
1042 <tr class="managehead">'._T('admin_list_header').'</tr>
1043 ';
1044
1045         for($j = 0; $j < $posts_count; $j++){
1046                 $bg = ($j % 2) ? 'row1' : 'row2'; // 背景顏色
1047                 extract($posts[$j]);
1048
1049                 if($no == 0) break; // Do not display post 0
1050
1051                 // 修改欄位樣式
1052                 $now = preg_replace('/.{2}\/(.{5})\(.+?\)(.{5}).*/', '$1 $2', $now);
1053                 $name = htmlspecialchars(str_cut(html_entity_decode(strip_tags($name)), 8));
1054                 $sub = htmlspecialchars(str_cut(html_entity_decode($sub), 8));
1055                 if($email) $name = "<a href=\"mailto:$email\">$name</a>";
1056                 $com = str_replace('<br />',' ',$com);
1057                 $com = htmlspecialchars(str_cut(html_entity_decode($com), 20));
1058
1059                 // 討論串首篇停止勾選框 及 模組功能
1060                 $modFunc = $THstop = ' ';
1061                 $PMS->useModuleMethods('AdminList', array(&$modFunc, $posts[$j], $resto)); // "AdminList" Hook Point
1062                 if($resto==0){ // $resto = 0 (即討論串首篇)
1063                         $flgh = $PIO->getPostStatus($status);
1064                         $THstop = '<input type="checkbox" name="stop[]" value="'.$no.'" />'.($flgh->exists('TS') ? _T('admin_stop_btn') : '');
1065                 }
1066
1067                 // 從記錄抽出附加圖檔使用量並生成連結
1068                 if($ext && $FileIO->imageExists($tim.$ext)){
1069                         $clip = '<a href="'.$FileIO->getImageURL($tim.$ext).'" rel="_blank">'.$tim.$ext.'</a>';
1070                         $size = $FileIO->getImageFilesize($tim.$ext);
1071                         if($FileIO->imageExists($tim.'s.jpg')) $size += $FileIO->getImageFilesize($tim.'s.jpg');
1072                 }else{
1073                         $clip = $md5chksum = '--';
1074                         $size = 0;
1075                 }
1076
1077                 // 印出介面
1078                 echo <<< _ADMINEOF_
1079 <tr class="$bg" align="left">
1080 <th align="center">$modFunc</th><th align="center">$THstop</th><th><input type="checkbox" name="clist[]" value="$no" />$no</th><td><small>$now</small></td><td>$sub</td><td><b>$name</b></td><td><small>$com</small></td><td>$host</td><td align="center">$clip ($size)<br />$md5chksum</td>
1081 </tr>
1082
1083 _ADMINEOF_;
1084         }
1085         echo '</table>
1086 <p>
1087 <select name="func"><option value="delete">'._T('admin_delete').'</option>';
1088         $funclist = array();
1089         $PMS->useModuleMethods('AdminFunction', array('add', &$funclist, null, null)); // "AdminFunction" Hook Point
1090         foreach($funclist as $f) echo '<option value="'.$f[0].'">'.$f[1].'</option>';
1091         echo '</select>
1092 <input type="submit" value="'._T('admin_submit_btn').'" /> <input type="reset" value="'._T('admin_reset_btn').'" /> [<input type="checkbox" name="onlyimgdel" id="onlyimgdel" value="on" /><label for="onlyimgdel">'._T('del_img_only').'</label>]</p>
1093 <p>'._T('admin_totalsize',total_size()).'</p>
1094 </div>
1095 </form>
1096 <hr />
1097 ';
1098
1099         $countline = $PIO->postCount(); // 總文章數
1100         $page_max = ceil($countline / ADMIN_PAGE_DEF) - 1; // 總頁數
1101         echo '<table class="pages" border="1" style="float: left;"><tr>';
1102         if($page) echo '<td><a href="'.PHP_SELF.'?mode=admin&amp;admin=del&amp;page='.($page - 1).'">'._T('prev_page').'</a></td>';
1103         else echo '<td style="white-space: nowrap;">'._T('first_page').'</td>';
1104         echo '<td>';
1105         for($i = 0; $i <= $page_max; $i++){
1106                 if($i==$page) echo '[<b>'.$i.'</b>] ';
1107                 else echo '[<a href="'.PHP_SELF.'?mode=admin&amp;admin=del&amp;page='.$i.'">'.$i.'</a>] ';
1108         }
1109         echo '</td>';
1110         if($page < $page_max) echo '<td><a href="'.PHP_SELF.'?mode=admin&amp;admin=del&amp;page='.($page + 1).'">'._T('next_page').'</a></td>';
1111         else echo '<td style="white-space: nowrap;">'._T('last_page').'</td>';
1112         die('</tr></table><br/><br/>
1113 </body>
1114 </html>');
1115 }
1116
1117 /* manage_css */
1118 // http://www.magmagateau.com/fuukaba/ is the source of the code below
1119 function manage_css(){
1120         global $PMS, $language;
1121         $order = array(); $line = '';
1122
1123         // Handle submission
1124         if(isset($_POST['order']) || isset($_POST['new'])){
1125                 $default = $_POST['default'];
1126
1127                 if(isset($_POST['order'])){
1128                         $dupid = false;
1129                         $order = $_POST['order'];
1130                         $ids = array();
1131                         $id = 0;
1132                         $name = '';
1133                         if(count($order) > 1){
1134                                 foreach($order as $name => $id) $ids[$id]++;
1135                                 foreach($ids as $idu => $count){
1136                                         if($idu < 1 || $count == 1) continue;
1137                                         foreach($order as $name => $id) if($id == $idu) $dupid = true;
1138                                 }
1139                                 if($dupid){
1140                                         ksort($order); // Yes, we're going to wimp out and reset it alphabetically.
1141                                         $go = 0;
1142                                         foreach($order as $name => $id) $go++;
1143                                         $order[$name] = $go;
1144                                 }
1145                         }
1146                         $order = array_flip($order);
1147                 }
1148
1149                 // Find out if a new stylesheet entry has been added
1150                 if(is_array($_POST['new'])){
1151                         $new_path = $_POST['new']['path'];
1152                         $new_name = $_POST['new']['name'];
1153                         $new_order = $_POST['new']['order'];
1154                         if($new_path != '' && $new_name != '') $order[$new_order] = $new_name;
1155                         if($default == 'new') $default = $new_name;
1156                 }
1157
1158                 ksort($order);
1159
1160                 // Get existing stylesheet entries
1161                 foreach($order as $id => $name){
1162                         if(!$id) continue;
1163                         if(!$_POST['path'][$name]) continue;
1164                         $temp['path'][$name] = $_POST['path'][$name];
1165                         $temp['names'][$name] = $name;
1166                         $temp['short'][$name] = $_POST['short'][$name];
1167                         $temp['order'][$name] = $id;
1168                 }
1169
1170                 // Get newly added stylesheet entries
1171                 if(is_array($_POST['new'])){
1172                         $temp['path'][$new_name] = $_POST['new']['path'];
1173                         $temp['names'][$new_name] = $new_name;
1174                         $temp['short'][$new_name] = $_POST['new']['short'];
1175                         $temp['order'][$new_name] = $new_order;
1176                 }
1177
1178                 // Build CSV lines
1179                 foreach($order as $id => $name){
1180                         if(!$id) continue; // Ignore Display order 0
1181                         $line   .= $name.','.$temp['short'][$name].','.$temp['path'][$name].',';
1182                         $line   .= ($name == $default) ? 'default,' : ',';
1183                         $line   .= "\n";
1184                 }
1185
1186                 $style_dat = DATA_DIR.CSV_SS;
1187
1188                 // Success messages
1189                 $action = (file_exists($style_dat)) ? _t('admin_updated') : _t('admin_created');
1190                 //---- $delete = (@unlink(CSS_DIR.CSVSS)) ? ' - <span class="warning">'.str_replace('[file]', CSS_DIR.CSVSS, _t('admin_deleted')).'</span>' : false;
1191                 $fp = fopen($style_dat, 'w+');
1192                 set_file_buffer($fp, 0);
1193                 rewind($fp);
1194                 fputs($fp, $line);
1195                 fclose($fp);
1196                 @chmod($style_dat, 0666);
1197                 echo '<div class="bar_managecss">'.str_replace('[file]', $style_dat, _t('admin_updated'))./*----$delete.*/'</div>';
1198         }
1199
1200         // Editing messages
1201         if(file_exists(DATA_DIR.CSV_SS)){
1202                 $style_data = DATA_DIR.CSV_SS;
1203                 $style_mode = _t('admin_editing');
1204 //----  }else{
1205 //----          $style_data = CSS_DIR.CSVSS;
1206 //----          $style_mode = _t('admin_imported');
1207         }
1208         echo '<div class="banner"><table width="100%"><tr><th class="bar_managecss">
1209 '.str_replace('[file]', $style_data, $style_mode).'
1210 </th></tr></table></div>';
1211
1212         echo '<div class="postlists">
1213 <input type="hidden" name="mode" value="admin" />
1214 <input type="hidden" name="admin" value="stylesheets" />
1215 <table width="100%" border="1" cellspacing="0">';
1216
1217         // Read data from R4+(CSV)
1218         if(file_exists(DATA_DIR.CSV_SS)){
1219                 $style_data = DATA_DIR.CSV_SS;
1220                 $lines = explode("\n", file_get_contents($style_data));
1221                 $j = 0;
1222                 $lines = array_diff($lines, array(''));
1223                 if(count($lines)){
1224                         echo '<tr class="managehead"><th colspan="2">'._t('admin_is_default').'</th><th>'._t('admin_fullname').'</th><th>'._t('admin_shortname').'</th><th>'._t('admin_dispid').'</th></tr>';
1225                 }
1226                 foreach($lines as $null => $line){
1227                         if($line != ''){ // Line has data
1228                                 list($style_name, $style_short, $style_file, $style_rel) = explode(',', $line);
1229                                 $j++; // For alternating <tr> BG colour
1230
1231                                 $style_path = CSS_DIR.$style_file;
1232
1233                                 if(file_exists($style_path)){
1234                                         if($style_rel) $style_rel = ' checked="checked"';
1235                                         else $style_rel = false;
1236                                         $class = ($j % 2) ? 'row1' : 'row2'; // BG colour
1237                                         echo '<tr class="'.$class.'"><td align="left" colspan="2"><label><input name="default" type="radio"'.$style_rel.' value="'.$style_name.'" /> '.$style_path.'</label><input type="hidden" name="path['.$style_name.']" value="'.$style_file.'" /></td><td align="left">'.$style_name.'</td><td align="left"><input name="short['.$style_name.']" value="'.$style_short.'" size="5" /></td><td align="left"><label><input name="order['.$style_name.']" size="2" value="'.$j.'" /></label></td></tr>';
1238                                 }
1239                         }
1240                 }
1241         }
1242
1243         // Read data from R3 DAT
1244 //----  else if(file_exists(CSS_DIR.CSVSS)){
1245 //----          $style_data = CSS_DIR.CSVSS;
1246 //----          $lines = explode("\n", file_get_contents($style_data));
1247 //----          $j = 0;
1248 //----          foreach($lines as $null => $line){ // Line has data, or line is not commented out
1249 //----                  if(substr($line, 0, 2) != '//' && $line != ''){
1250 //----                          $bits = explode('[*]', $line);
1251 //----                          $j++;
1252 //----                          $style_name = $bits[0];
1253 //----                          $style_path = CSS_DIR.$bits[2];
1254 //----                          if(file_exists($style_path)){
1255 //----                                  $style_short = $bits[1];
1256 //----                                  if($bits[3]) $style_rel = ' checked="checked"';
1257 //----                                  else $style_rel = false;
1258 //----                                  $class = ($j % 2) ? 'row1' : 'row2'; // BG colour
1259 //----                                  echo '<tr class="'.$class.'"><td align="left" colspan="2"><label><input name="default" type="radio"'.$style_rel.' value="'.$style_name.'" /> '.$style_path.'</label><input type="hidden" name="path['.$style_name.']" value="'.$bits[2].'" /></td><td align="left"><input name="names['.$style_name.']" value="'.$style_name.'" size="25" /></td><td align="left"><input name="short['.$style_name.']" value="'.$style_short.'" size="5" /></td><td align="left"><input name="order['.$style_name.']" size="2" value="'.$j.'" /></td></tr>';
1260 //----                          }
1261 //----                  }
1262 //----          }
1263 //----  }
1264
1265         $j++; $class = ($j % 2) ? 'row1' : 'row2';
1266
1267         // Insert string for when there are stylesheet entries to modify
1268         $action = ($j > 1) ? _t('admin_modstyle') : false;
1269         // Check default radio button for new row when there are NO stylesheet entries
1270         $style_rel = (!$action) ? ' checked="checked"' : false;
1271
1272         echo '<tr class="managehead"><th>'.str_replace('[or modify]', $action, _t('admin_addstyle')).'</th><th>'._t('admin_new_file').'</th><th>'._t('admin_fullname').'</th><th>'._t('admin_shortname').'</th><th>'._t('admin_new_id').'</th></tr>';
1273
1274         echo '<tr class="'.$class.'"><td align="left"><label><input name="default" type="radio"'.$style_rel.' value="new" /> '._t('admin_style_default').'</label></td><td align="left"><nobr>'.CSS_DIR.'<input name="new[path]" /></nobr></td><td align="left"><input name="new[name]" size="25" /></td><td align="left"><input name="new[short]" size="5" /></td><td align="left"><input name="new[order]" size="2" value="'.$j.'" /></td></tr></table></div>
1275 <center><p><div class="passvalid"><input type="submit" value="'._T('admin_submit_btn').'" /> <input type="reset" value="'._T('admin_reset_btn').'" /></div></p>';
1276         die('</center></form></body></html>');
1277 }
1278
1279 /* 計算目前附加圖檔使用容量 (單位:KB) */
1280 function total_size($isupdate=false){
1281         global $config, $PIO, $FileIO;
1282
1283         $size = 0; $all = 0;
1284         $cache_file = "./".SIZE_CACHE; // 附加圖檔使用容量值快取檔案
1285
1286         if($isupdate){ // 刪除舊快取
1287                 if(is_file($cache_file)) unlink($cache_file);
1288                 return;
1289         }
1290         if(!is_file($cache_file)){ // 無快取,新增
1291                 $line = $PIO->fetchPostList(); // 取出所有文章編號
1292                 $posts = $PIO->fetchPosts($line);
1293                 $linecount = count($posts);
1294                 for($i = 0; $i < $linecount; $i++){
1295                         extract($posts[$i]);
1296                         // 從記錄檔抽出計算附加圖檔使用量
1297                         if($ext && $FileIO->imageExists($tim.$ext)) $all += $FileIO->getImageFilesize($tim.$ext); // 附加圖檔合計計算
1298                         if($FileIO->imageExists($tim.'s.jpg')) $all += $FileIO->getImageFilesize($tim.'s.jpg'); // 預覽圖合計計算
1299                 }
1300                 $sp = fopen($cache_file, 'w');
1301                 stream_set_write_buffer($sp, 0);
1302                 fwrite($sp, $all); // 寫入目前使用容量值
1303                 fclose($sp);
1304                 @chmod($cache_file, 0666);
1305         }else{ // 使用快取
1306                 $sp = file($cache_file);
1307                 $all = $sp[0];
1308                 unset($sp);
1309         }
1310 //----        return (int)($all / 1024);
1311         if(!$config['KB']) return (int)($all);
1312         else return (int)($all / 1024);
1313 }
1314
1315 /* 搜尋(全文檢索)功能 */
1316 function search(){
1317         global $PTE, $PIO, $FileIO, $PMS, $language;
1318
1319         if(!USE_SEARCH) error(_T('search_disabled'));
1320         $searchKeyword = isset($_POST['keyword']) ? trim($_POST['keyword']) : ''; // 欲搜尋的文字
1321         $dat = '';
1322         head($dat);
1323         $links = '[<a href="'.PHP_SELF2.'?'.time().'">'._T('return').'</a>]';
1324         $PMS->useModuleMethods('LinksAboveBar', array(&$links,'search'));
1325         $dat .= '<div id="bannerlink">'.$links.'</div><div id="banner"><div class="bar_search">'._T('search_top').'</div>
1326 </div>
1327 ';
1328         echo $dat;
1329         if($searchKeyword==''){
1330                 echo '<form action="'.PHP_SELF.'" method="post">
1331 <div id="search">
1332 <input type="hidden" name="mode" value="search" />
1333 ';
1334                 echo '<ul>'._T('search_notice').'<input class="inputtext" type="text" name="keyword" size="30" />
1335 '._T('search_target').'<select name="field"><option value="com" selected="selected">'._T('search_target_comment').'</option><option value="name">'._T('search_target_name').'</option><option value="sub">'._T('search_target_topic').'</option><option value="no">'._T('search_target_number').'</option></select>
1336 '._T('search_method').'<select name="method"><option value="AND" selected="selected">'._T('search_method_and').'</option><option value="OR">'._T('search_method_or').'</option></select>
1337 <input type="submit" value="'._T('search_submit_btn').'" />
1338 </li>
1339 </ul>
1340 </div>
1341 </form>';
1342         }else{
1343                 $searchField = $_POST['field']; // 搜尋目標 (no:編號, name:名稱, sub:標題, com:內文)
1344                 $searchMethod = $_POST['method']; // 搜尋方法
1345                 $searchKeyword = preg_split('/( | )+/', trim($searchKeyword)); // 搜尋文字用空格切割
1346                 $hitPosts = $PIO->searchPost($searchKeyword, $searchField, $searchMethod); // 直接傳回符合的文章內容陣列
1347
1348                 echo '<div id="search_result">
1349 ';
1350                 $resultlist = '';
1351                 foreach($hitPosts as $post){
1352                         extract($post);
1353                         if(USE_CATEGORY){
1354                                 $ary_category = explode(',', str_replace('&#44;', ',', $category)); $ary_category = array_map('trim', $ary_category);
1355                                 $ary_category_count = count($ary_category);
1356                                 $ary_category2 = array();
1357                                 for($p = 0; $p < $ary_category_count; $p++){
1358                                         if($c = $ary_category[$p]) $ary_category2[] = '<a href="'.PHP_SELF.'?mode=category&amp;c='.urlencode($c).'">'.$c.'</a>';
1359                                 }
1360                                 $category = implode(', ', $ary_category2);
1361                         }else $category = '';
1362                         $arrLabels = array('{$NO}'=>'<a href="'.PHP_SELF.'?res='.($resto?$resto.'#r'.$no:$no).'">'.$no.'</a>', '{$SUB}'=>$sub, '{$NAME}'=>$name, '{$NOW}'=>$now, '{$COM}'=>$com, '{$CATEGORY}'=>$category, '{$NAME_TEXT}'=>_T('post_name'), '{$CATEGORY_TEXT}'=>_T('post_category'));
1363                         $resultlist .= $PTE->ParseBlock('SEARCHRESULT',$arrLabels);
1364                 }
1365                 echo $resultlist ? $resultlist : '<div style="text-align: center">'._T('search_notfound').'<br/><a href="?mode=search">'._T('search_back').'</a></div>';
1366                 echo "</div>";
1367         }
1368         echo "</body>\n</html>";
1369 }
1370
1371 /* 利用類別標籤搜尋符合的文章 */
1372 function searchCategory(){
1373         global $PTE, $PIO, $PMS, $FileIO, $language;
1374         $category = isset($_GET['c']) ? strtolower(strip_tags(trim($_GET['c']))) : ''; // 搜尋之類別標籤
1375         if(!$category) error(_T('category_nokeyword'));
1376         $category_enc = urlencode($category); $category_md5 = md5($category);
1377         $page = isset($_GET['p']) ? @intval($_GET['p']) : 1; if($page < 1) $page = 1; // 目前瀏覽頁數
1378         $isrecache = isset($_GET['recache']); // 是否強制重新生成快取
1379
1380         // 利用Session快取類別標籤出現篇別以減少負擔
1381         session_start(); // 啟動Session
1382         if(!isset($_SESSION['loglist_'.$category_md5]) || $isrecache){
1383                 $loglist = $PIO->searchCategory($category);
1384                 $_SESSION['loglist_'.$category_md5] = serialize($loglist);
1385         }else $loglist = unserialize($_SESSION['loglist_'.$category_md5]);
1386
1387         $loglist_count = count($loglist);
1388         if(!$loglist_count) error(_T('category_notfound'));
1389         $page_max = ceil($loglist_count / PAGE_DEF); if($page > $page_max) $page = $page_max; // 總頁數
1390
1391         // 分割陣列取出適當範圍作分頁之用
1392         $loglist_cut = array_slice($loglist, PAGE_DEF * ($page - 1), PAGE_DEF); // 取出特定範圍文章
1393         $loglist_cut_count = count($loglist_cut);
1394
1395         $dat = '';
1396         head($dat);
1397         $links = '[<a href="'.PHP_SELF2.'?'.time().'">'._T('return').'</a>][<a href="'.PHP_SELF.'?mode=category&amp;c='.$category_enc.'&amp;recache=1">'._T('category_recache').'</a>]';
1398         $PMS->useModuleMethods('LinksAboveBar', array(&$links,'category'));
1399         $dat .= "<div>$links</div>\n";
1400         for($i = 0; $i < $loglist_cut_count; $i++){
1401                 $posts = $PIO->fetchPosts($loglist_cut[$i]); // 取得文章內容
1402                 $dat .= arrangeThread($PTE, ($posts[0]['resto'] ? $posts[0]['resto'] : $posts[0]['no']), null, $posts, 0, $loglist_cut[$i], array(), array(), false, false, false, 0, 0, 0, 0, 0); // 逐個輸出 (引用連結不顯示)
1403         }
1404
1405         $dat .= '<table border="1"><tr>';
1406         if($page > 1) $dat .= '<td><form action="'.PHP_SELF.'?mode=category&amp;c='.$category_enc.'&amp;p='.($page - 1).'" method="post"><div><input type="submit" value="'._T('prev_page').'" /></div></form></td>';
1407         else $dat .= '<td style="white-space: nowrap;">'._T('first_page').'</td>';
1408         $dat .= '<td>';
1409         for($i = 1; $i <= $page_max ; $i++){
1410                 if($i==$page) $dat .= "[<b>".$i."</b>] ";
1411                 else $dat .= '[<a href="'.PHP_SELF.'?mode=category&amp;c='.$category_enc.'&amp;p='.$i.'">'.$i.'</a>] ';
1412         }
1413         $dat .= '</td>';
1414         if($page < $page_max) $dat .= '<td><form action="'.PHP_SELF.'?mode=category&amp;c='.$category_enc.'&amp;p='.($page + 1).'" method="post"><div><input type="submit" value="'._T('next_page').'" /></div></form></td>';
1415         else $dat .= '<td style="white-space: nowrap;">'._T('last_page').'</td>';
1416         $dat .= '</tr></table>'."\n";
1417
1418         foot($dat);
1419         echo $dat;
1420 }
1421
1422 /* 顯示已載入模組資訊 */
1423 function listModules(){
1424         global $PMS, $language;
1425         $dat = '';
1426         head($dat);
1427         $links = '[<a href="'.PHP_SELF2.'?'.time().'">'._T('return').'</a>]';
1428         $PMS->useModuleMethods('LinksAboveBar', array(&$links,'modules'));
1429         $dat .= '<div id="bannerlink">'.$links.'</div><div id="banner"><div class="bar_info_mod">'._T('module_info_top').'</div>
1430 </div>
1431
1432 <div id="modules">
1433 ';
1434         /* Module Loaded */
1435         $dat .= _T('module_loaded').'<ul>'."\n";
1436         foreach($PMS->getLoadedModules() as $m) $dat .= '<li>'.$m."</li>\n";
1437         $dat .= "</ul><hr />\n";
1438
1439         /* Module Infomation */
1440         $dat .= _T('module_info').'<ul>'."\n";
1441         foreach($PMS->moduleInstance as $m) $dat .= '<li>'.$m->getModuleName().'<div style="padding-left:2em;">'.$m->getModuleVersionInfo()."</div></li>\n";
1442         $dat .= '</ul><hr />
1443 </div>
1444
1445 ';
1446         foot($dat);
1447         echo $dat;
1448 }
1449
1450 /* 刪除舊頁面快取檔 */
1451 function deleteCache($no){
1452         foreach($no as $n){
1453                 if($oldCaches = glob('./cache/'.$n.'-*')){
1454                         foreach($oldCaches as $o) @unlink($o);
1455                 }
1456         }
1457 }
1458
1459 /* 顯示系統各項資訊 */
1460 function showstatus(){
1461         global $config, $PTE, $PIO, $FileIO, $PMS, $language, $LIMIT_SENSOR;
1462         $countline = $PIO->postCount(); // 計算投稿文字記錄檔目前資料筆數
1463         $counttree = $PIO->threadCount(); // 計算樹狀結構記錄檔目前資料筆數
1464         $tmp_total_size = total_size(); // 附加圖檔使用量總大小
1465         $tmp_ts_ratio = STORAGE_MAX > 0 ? $tmp_total_size / STORAGE_MAX : 0; // 附加圖檔使用量
1466         if(!$config['KB']) $kbb = ' B';
1467         else $kbb = ' KB';
1468
1469         // 決定「附加圖檔使用量」提示文字顏色
1470         if($tmp_ts_ratio < 0.3 ) $clrflag_sl = '235CFF';
1471         elseif($tmp_ts_ratio < 0.5 ) $clrflag_sl = '0CCE0C';
1472         elseif($tmp_ts_ratio < 0.7 ) $clrflag_sl = 'F28612';
1473         elseif($tmp_ts_ratio < 0.9 ) $clrflag_sl = 'F200D3';
1474         else $clrflag_sl = 'F2004A';
1475
1476         // 生成預覽圖物件資訊及功能是否正常
1477         $func_thumbWork = '<span style="color: red;">'._T('info_nonfunctional').'</span>';
1478         $func_thumbInfo = '(No thumbnail)';
1479         if(USE_THUMB !== 0){
1480                 $thumbType = USE_THUMB; if(USE_THUMB==1){ $thumbType = 'gd'; }
1481                 require(PHP_DIRECTORY.'lib/thumb/thumb.'.$thumbType.'.php');
1482                 $thObj = new ThumbWrapper();
1483                 if($thObj->isWorking()) $func_thumbWork = '<span style="color: blue;">'._T('info_functional').'</span>';
1484                 $func_thumbInfo = $thObj->getClass();
1485                 unset($thObj);
1486         }
1487
1488         // PIOSensor
1489         if(count($LIMIT_SENSOR))
1490                 $piosensorInfo=nl2br(PIOSensor::info($LIMIT_SENSOR));
1491
1492         $dat = '';
1493         head($dat);
1494         $links = '[<a href="'.PHP_SELF2.'?'.time().'">'._T('return').'</a>] [<a href="'.PHP_SELF.'?mode=moduleloaded">'._T('module_info_top').'</a>]';
1495         $PMS->useModuleMethods('LinksAboveBar', array(&$links,'status'));
1496         $dat .= '<div id="bannerlink">'.$links.'</div><div id="banner"><div class="bar_info">'._T('info_top').'</div>
1497 </div>
1498 ';
1499
1500         $dat .= '
1501 <div id="status-table" style="text-align: center;">
1502 <table border="1" style="margin: 0px auto; text-align: left;">
1503 <tr><td align="center" colspan="4">'._T('info_basic').'</td></tr>
1504 <tr><td style="width: 240px;">'._T('info_basic_ver').'</td><td colspan="3"> '.PIXMICAT_VER.' </td></tr>
1505 <tr><td>'._T('info_basic_pio').'</td><td colspan="3"> '.PIXMICAT_BACKEND.' : '.$PIO->pioVersion().'</td></tr>
1506 <tr><td>'._T('info_basic_threadsperpage').'</td><td colspan="3"> '.PAGE_DEF.' '._T('info_basic_threads').'</td></tr>
1507 <tr><td>'._T('info_basic_postsperpage').'</td><td colspan="3"> '.RE_DEF.' '._T('info_basic_posts').'</td></tr>
1508 <tr><td>'._T('info_basic_postsinthread').'</td><td colspan="3"> '.RE_PAGE_DEF.' '._T('info_basic_posts').' '._T('info_basic_posts_showall').'</td></tr>
1509 <tr><td>'._T('info_basic_bumpposts').'</td><td colspan="3"> '.MAX_RES.' '._T('info_basic_posts').' '._T('info_basic_0disable').'</td></tr>
1510 <tr><td>'._T('info_basic_bumphours').'</td><td colspan="3"> '.MAX_AGE_TIME.' '._T('info_basic_hours').' '._T('info_basic_0disable').'</td></tr>
1511 <tr><td>'._T('info_basic_urllinking').'</td><td colspan="3"> '.AUTO_LINK.' '._T('info_0no1yes').'</td></tr>
1512 <tr><td>'._T('info_basic_com_limit').'</td><td colspan="3"> '.COMM_MAX._T('info_basic_com_after').'</td></tr>
1513 <tr><td>'._T('info_basic_anonpost').'</td><td colspan="3"> '.$config['ALLOW_NONAME'].' '._T('info_basic_anonpost_opt').'</td></tr>
1514 <tr><td>'._T('info_basic_del_incomplete').'</td><td colspan="3"> '.KILL_INCOMPLETE_UPLOAD.' '._T('info_0no1yes').'</td></tr>
1515 <tr><td>'._T('info_basic_use_sample',THUMB_Q).'</td><td colspan="3"> '.USE_THUMB.' '._T('info_0notuse1use').'</td></tr>
1516 <tr><td>'._T('info_basic_useblock').'</td><td colspan="3"> '.BAN_CHECK.' '._T('info_0disable1enable').'</td></tr>
1517 <tr><td>'._T('info_basic_showid').'</td><td colspan="3"> '.DISP_ID.' '._T('info_basic_showid_after').'</td></tr>
1518 <tr><td>'._T('info_basic_cr_limit').'</td><td colspan="3"> '.BR_CHECK._T('info_basic_cr_after').'</td></tr>
1519 <!--<tr><td>'._T('info_basic_timezone').'</td><td colspan="3"> GMT </td></tr>-->
1520 <tr><td>'._T('info_basic_line_number_limit').'</td><td colspan="3"> '.$config['LINE_NUMBER']._T('info_basic_line_number_after').'</td></tr>
1521 <tr><td>'._T('info_basic_theme').'</td><td colspan="3"> '.$PTE->BlockValue('THEMENAME').' '.$PTE->BlockValue('THEMEVER').'<br/>by '.$PTE->BlockValue('THEMEAUTHOR').'</td></tr>
1522 <tr><td align="center" colspan="4">'._T('info_dsusage_top').'</td></tr>
1523 <tr align="center"><td>'._T('info_basic_threadcount').'</td><td colspan="'.(isset($piosensorInfo)?'2':'3').'"> '.$counttree.' '._T('info_basic_threads').'</td>'.(isset($piosensorInfo)?'<td rowspan="2">'.$piosensorInfo.'</td>':'').'</tr>
1524 <tr align="center"><td>'._T('info_dsusage_count').'</td><td colspan="'.(isset($piosensorInfo)?'2':'3').'">'.$countline.'</td></tr>
1525 <tr><td align="center" colspan="4">'._T('info_fileusage_top').STORAGE_LIMIT.' '._T('info_0disable1enable').'</td></tr>';
1526
1527         if(STORAGE_LIMIT){
1528                 $dat .= '
1529 <tr align="center"><td>'._T('info_fileusage_limit').'</td><td colspan="2">'.STORAGE_MAX.$kbb.'</td><td rowspan="2">'._T('info_dsusage_usage').'<br /><span style="color: #'.$clrflag_sl.'">'.substr(($tmp_ts_ratio * 100), 0, 6).'</span> %</td></tr>
1530 <tr align="center"><td>'._T('info_fileusage_count').'</td><td colspan="2"><span style="color: #'.$clrflag_sl.'">'.$tmp_total_size.$kbb.'</span></td></tr>';
1531         }else{
1532                 $dat .= '
1533 <tr align="center"><td>'._T('info_fileusage_count').'</td><td>'.$tmp_total_size.$kbb.'</td><td colspan="2">'._T('info_dsusage_usage').'<br /><span style="color: green;">'._T('info_fileusage_unlimited').'</span></td></tr>';
1534         }
1535
1536         $dat .= '
1537 <tr><td align="center" colspan="4">'._T('info_server_top').'</td></tr>
1538 <tr align="center"><td colspan="3">PHP version</td><td>'.phpversion().'</td></tr>
1539 <tr align="center"><td colspan="3">'.$func_thumbInfo.'</td><td>'.$func_thumbWork.'</td></tr>
1540 </table>
1541 <hr />
1542 </div>'."\n";
1543
1544         foot($dat);
1545         echo $dat;
1546 }
1547
1548 /* 程式首次執行之初始化 */
1549 /* 初期設定 */
1550 function init(){
1551         global $PIO, $FileIO, $language;
1552         if(!is_writable(realpath('./'))) error(_T('init_permerror'));
1553
1554         $chkfolder = array(IMG_DIR, THUMB_DIR, 'cache/', TEMP_DIR);
1555         // 逐一自動建置資料夾
1556         foreach($chkfolder as $value) if(!is_dir($value)){ mkdir($value); @chmod($value, 0777); }  // 沒有就建立
1557
1558         $PIO->dbInit(); // PIO Init
1559         $FileIO->init(); // FileIO Init
1560
1561         error(_T('init_inited'));
1562 }
1563
1564 /*-----------程式各項功能主要判斷-------------*/
1565 /*-----------Main-------------*/
1566 if(GZIP_COMPRESS_LEVEL && ($Encoding = CheckSupportGZip())){ ob_start(); ob_implicit_flush(0); } // 支援且開啟Gzip壓縮就設緩衝區
1567 $mode = isset($_GET['mode']) ? $_GET['mode'] : (isset($_POST['mode']) ? $_POST['mode'] : ''); // 目前執行模式 (GET, POST)
1568
1569 //init(); // ←■■!程式環境初始化,跑過一次後請刪除此行!■■
1570 switch($mode){
1571         case 'regist':
1572                 regist();
1573                 break;
1574         case 'admin':
1575                 $admin = isset($_REQUEST['admin']) ? $_REQUEST['admin'] : ''; // 管理者執行模式
1576                 valid();
1577                 switch($admin){
1578                         case 'del': admindel(); break;
1579                         case 'logout':
1580                                 adminAuthenticate('logout');
1581                                 header('HTTP/1.1 302 Moved Temporarily');
1582                                 header('Location: '.fullURL().PHP_SELF2.'?'.time());
1583                                 break;
1584                         case 'optimize':
1585                         case 'check':
1586                         case 'repair':
1587                         case 'export':
1588                                 if(!$PIO->dbMaintanence($admin)) echo _T('action_main_notsupport');
1589                                 else echo _T('action_main_'.$admin).(($mret = $PIO->dbMaintanence($admin,true))?_T('action_main_success'):_T('action_main_failed')).(is_bool($mret)?'':'<br/>'.$mret);
1590                                 die("</div></form></body>\n</html>");
1591                                 break;
1592                         case 'stylesheets': manage_css(); break;
1593                         default:
1594                 }
1595                 break;
1596         case 'search':
1597                 search();
1598                 break;
1599         case 'status':
1600                 showstatus();
1601                 break;
1602         case 'category':
1603                 searchCategory();
1604                 break;
1605         case 'module':
1606                 $loadModule = isset($_GET['load']) ? $_GET['load'] : '';
1607                 if($PMS->onlyLoad($loadModule)) $PMS->moduleInstance[$loadModule]->ModulePage();
1608                 else echo '404 Not Found';
1609                 break;
1610         case 'moduleloaded':
1611                 listModules();
1612                 break;
1613         case 'init':
1614                 init(); // ←■■!程式環境初始化,跑過一次後請刪除此行!■■
1615                 break;
1616         case 'usrdel':
1617                 usrdel();
1618         case 'remake':
1619                 updatelog();
1620                 header('HTTP/1.1 302 Moved Temporarily');
1621                 header('Location: '.fullURL().PHP_SELF2.'?'.time());
1622                 break;
1623         default:
1624                 // 如果瀏覽器支援XHTML標準MIME就輸出
1625                 header('Content-Type: '.((USE_XHTML && strpos($_SERVER['HTTP_ACCEPT'],'application/xhtml+xml')!==FALSE) ? 'application/xhtml+xml' : 'text/html').'; charset=utf-8');
1626                 $res = isset($_GET['res']) ? $_GET['res'] : 0; // 欲回應編號
1627                 if($res){ // 回應模式輸出
1628                         $page = isset($_GET['page_num']) ? $_GET['page_num'] : 'RE_PAGE_MAX';
1629                         if(!($page=='all' || $page=='RE_PAGE_MAX')) $page = intval($_GET['page_num']);
1630                         updatelog($res, $page); // 實行分頁
1631                 }elseif(isset($_GET['page_num']) && intval($_GET['page_num']) > -1){ // PHP動態輸出一頁
1632                         updatelog(0, intval($_GET['page_num']));
1633                 }else{ // 導至靜態庫存頁
1634                         if(!is_file(PHP_SELF2)) updatelog();
1635                         header('HTTP/1.1 302 Moved Temporarily');
1636                         header('Location: '.fullURL().PHP_SELF2.'?'.time());
1637                 }
1638 }
1639 if(GZIP_COMPRESS_LEVEL && $Encoding){ // 有啟動Gzip
1640         if(!ob_get_length()) exit; // 沒內容不必壓縮
1641         header('Content-Encoding: '.$Encoding);
1642         header('X-Content-Encoding-Level: '.GZIP_COMPRESS_LEVEL);
1643         header('Vary: Accept-Encoding');
1644         print gzencode(ob_get_clean(), GZIP_COMPRESS_LEVEL); // 壓縮內容
1645 }
1646 ?>