= "4.1.0") {
extract($_GET);
extract($_POST);
extract($_SERVER);
extract($_COOKIE);
}
$PHP_SELF = $SCRIPT_NAME;
/*************************************
* Tree BBS by ToR
*
* http://php.s3.to/
*
*************************************
* ツリー掲示板です。
* ・いろんな表示モードが選べます
* ・クッキーによりデフォルトの表示モードと件数が設定できます
* ・検索機能があります
* ・二重投稿・連続投稿防止機能があります
* ・禁止語句を**に変換します
* ・許可タグを指定できます
* ・新着記事にはNew等の文字を表示できます
* ・ツリーの深さを制限できます
* ・好きなデザインにしやすいです
*
* 準備
* ・空のログファイルを用意して書き込み属性を与えて下さい
* ・過去ログを使う場合は過去ログディレクトリを書き込み可にして、
* past.txtを用意して中に1とだけ書いて保存し、書き込み可にして下さい。
*
* 6/17 過去ログ修正、検索可
* 04/2/22 レス数制限、script除去追加
* 04/08/14 Line943: /<($tags)(.*?)>/si → /<($tags)\b(.*?)>/si
* 09/06/22 XSS脆弱性修正
*/
class tree{
var $logarr = array();
var $id = array();
var $thread = array();
var $root = array();
var $tree_arr = array();
var $error = "";
/* 設定ここから */
// ツリー記号
var $i_gif = "│";
var $t_gif = "├";
var $l_gif = "└";
var $nogif = " ";
// ログファイル名
var $logfile = "log.log";
// ログ最大行
var $max_log = 100;
// 過去ログ機能を使う?YES=1,No=0
var $past = 0;
// 過去ログNoファイル(初期値は1)(1.log 2.logを作成
var $pastno = "past.txt";
// 過去ログ保存ディレクトリ(書き込み可能にする。707等
var $pastdir = "./dat/";
// コメント最大行
var $max_line = 25;
// 投稿フォーム表示から投稿までの制限秒
var $posttime = 3;
// 連続投稿制限秒
var $renzoku = 10;
// 最新?時間内の投稿にNew記号
var $expire = 24;
// ツリーの深さ制限
var $max_depth = 20;
// ツリーのレス数制限
var $max_res = 50;
// ツリー時の一行表示文字数(記号+題名+文字を半角で)
var $cut_size = 60;
// 許可するタグ(本文のみ)
var $allow_tag = "
";
// 禁止する文字(**に変換)
var $bad_word = "href=|url=|バカ|死ね|氏ね|架空口座|販売|精力|媚薬|中絶|http://";
// >引用がついた時の色
var $quote = "#aaaacc";
// 投稿があると管理人にメールで通知する場合のアドレス(不要なら空)
var $adm_mail = "";
// 管理人に来るメールのsubject({id},{subj}使用可)
var $adm_subj = "[BBS-{id} {subj} ]";
// 管理人パスワード。単独記事表示の削除フォームから
var $adm_pass = "pass1212";
// 初期表示モード(tree=ツリー,expn=スレッド,root=タイトル,dump=一覧
var $mode = "root";
// 表示件数の初期状態
var $page_tree = 10;
var $page_expn = 5;
var $page_root = 15;
var $page_dump = 20;
// クッキー保存名
var $cookie_n = "treebbs_cookie";
var $cookie_s = "treebbs_setting";
// ヘッダ部分
var $head = '
サポート掲示板
サポート掲示板
今日:{today} 昨日:{yesterday} 合計:{total}';
/** 変数説明
* {id}-記事No {subj}-題名 {name}-投稿者 {date}-投稿日 {com}-本文 {host}-ホスト {time}-投稿time
* {n}-単独記事表示リンク {all}-ツリー一覧表示リンク {reply}-返信リンク {nl}で\n(''で囲った時用)
* {new}で新着$new_msg表示 {email}で以下の$if_email文字にリンク {url}で以下の$if_url文字にリンク
*/
// タイトル表示ヘッダ
var $root_head = "
No. | タイトル | 投稿者 | レス | 最終更新 |
\n";
// タイトル表示本文 {lname}最新投稿者 {ldate}最新投稿日 {lcom} 最新本文
var $root_msg = "{num} | {subj} | {name} | {res} | {ldate} by {lname} {host} |
\n";
// タイトル表示フッタ
var $root_foot = "
\n";
// ツリー表示ヘッダ
var $tree_head = "";
// ツリー表示親記事
var $tree_oya = " ▼-{subj} [{name}] ({date}) ";
// ツリー表示子記事
var $tree_res = "{subj} [{name}] ({date}) {new} ";
// ツリー表示フッタ
var $tree_foot = " |
\n";
// 展開表示親記事
var $expn_oya = " {num}: {subj} |
Name: {name} {url} {email} Date: {date}{com}
\n";
// 展開表示子記事
var $expn_res = " [{id}] {subj} Name: {name} {url} {email} Date: {date}{com}
\n";
// 展開表示テーブル閉じ
var $expn_bott = " |
\n";
// 一覧・単独表示
var $dump_msg = "
[{id}] {subj} |
Name: {name} {url} {email} Date: {date}{com}
返信する |
\n";
//単独表示時関連ツリー開始・終了タグ
var $n_tree_st = " 関連ツリー\n";
var $n_tree_to = " |
\n";
//ツリー一括時ツリー開始・終了タグ
var $all_tree_st = "No.{id}に関するツリー";
var $all_tree_to = " |
\n";
// フッタ部分
var $foot = "\n
";
// 新着記事記号
var $new_msg = "New!";
// E-Mailがあるとき{email}のリンク文字(空なら名前にリンク)
var $if_email = "E-MAIL";
// URLがあるとき{url}のリンク文字
var $if_url = "(HOME)";
/***
* コンストラクタ
*
*/
function tree($mode, $log){
global ${$this->cookie_s};
// $this->mode = "tree";
if(${$this->cookie_s}){
list($view,$pagetree,$pageexpn,$pageroot,$pagedump)=explode(",",${$this->cookie_s});
$this->mode = $view;
$this->page_tree = $pagetree;
$this->page_expn = $pageexpn;
$this->page_root = $pageroot;
$this->page_dump = $pagedump;
}
if($mode) $this->mode = $mode;
if($log && file_exists($this->pastdir.$log.".log")) {
$this->logfile = $this->pastdir.$log.".log";
}
$this->logarr = file($this->logfile);
}
/***
* なびめにゅう表示
*
*/
function show_navi(){
global $PHP_SELF,$all,$n,$log;
if($log) $kako = "&log=$log";
$form = ($this->mode == "form" && !$all && !$n) ? "新規投稿" : "新規投稿";
$tree = ($this->mode == "tree" && !$all && !$n) ? "ツリー" : "ツリー";
$expn = ($this->mode == "expn" && !$all && !$n) ? "スレッド" : "スレッド";
$root = ($this->mode == "root" && !$all && !$n) ? "タイトル" : "タイトル";
$dump = ($this->mode == "dump" && !$all && !$n) ? "一覧" : "一覧";
$search = ($this->mode == "search") ? "検索" : "検索";
if ($this->past) $past_m = "ログ | ";
$setup = ($this->mode == "setup") ? "設定" : "設定";
$html = "
{$form} | {$tree} | {$expn} | {$root} | {$dump} | {$search} | {$past_m}{$setup} |
\n";
return $html;
}
/***
* 改ページ表示
*
*/
function show_jump($offset, $limit, $total){
global $PHP_SELF,$log;
if($log) $kako = "&log=$log";
$num_page = ceil($total/$limit);
$prev = $offset - 1;
$next = $offset + 1;
if($prev >= 1){
$prev_st = "";
$prev_to = "";
}
if($next <= $num_page){
$next_st = "";
$next_to ="";
}
$html.= "[ {$prev_st}前の {$limit} 件{$prev_to} | {$offset} /{$num_page}ページ | {$next_st}次の {$limit} 件{$next_to} ]\n";
return $html;
}
/***
* ヘッドライン表示
*
*/
function show_headline($offset,$limit){
global $PHP_SELF,$log;
if($log) $kako = "&log=$log";
$st = ($offset-1) * $limit;
if($st < 0) $st = 0;
$html = "
\n";
return $html;
}
/***
* 投稿フォーム表示
*
*/
function show_form($root=0, $oya=0, $subj='', $com='', $mode='quote', $name='', $email='', $url='', $no='', $pass=''){
global $PHP_SELF,$n,${$this->cookie_n},$log;
$sid = session_id();
$_SESSION['time'] = time();
if ($mode == "quote") {
if(get_magic_quotes_gpc()) ${$this->cookie_n} = stripslashes(${$this->cookie_n});
if(ereg("Re\[([0-9]+)\]:", $subj, $reg)){
$reg[1]++;
$r_sub=ereg_replace("Re\[([0-9]+)\]:", "Re[$reg[1]]:", $subj);
}elseif(ereg("^Re:", $subj)){
$r_sub=ereg_replace("^Re:", "Re[2]:", $subj);
}elseif($subj){
$r_sub = "Re:$subj";
}
if($com){
$i_com = ">$com";
$i_com = str_replace("'", "\'", $i_com);
$i_com = str_replace(">", ">", $i_com);
$i_com = str_replace("<", "<", $i_com);
$i_com = eregi_replace("
", "
", $i_com);
}
list($c_name,$c_email,$c_url,$c_pass) = explode(",", ${$this->cookie_n});
$hidden = "";
}
if ($mode == "edit") {
$r_sub = $subj;
$r_com = $com;
$c_name = $name;
$c_email = $email;
$c_url = $url;
$c_pass = $pass;
$hidden = "";
}
if(isset($log)) $kako = "";
if($this->allow_tag) $tag = "タグ使用可 ".htmlspecialchars($this->allow_tag);
$html.= '
';
$html.= "
";
return $html;
}
/***
* 検索フォーム表示
*
*/
function show_search($word){
global $PHP_SELF,$log;
if(get_magic_quotes_gpc()) $word = stripslashes($word);
$word = htmlspecialchars($word);
if (is_numeric($log)) {
$num = sprintf("%03d",$log);
$kako = "過去ログ $num から";
$hide = "";
}
$html = "
";
return $html;
}
/***
* 設定フォーム表示
*
*/
function show_setup(){
global $PHP_SELF,${$this->cookie_s};
list($view,) = explode(",", ${$this->cookie_s});
$$view = " selected";
if(!$view) $tree = " selected";
$html = "
";
return $html;
}
/***
* 過去ログフォーム
*
*/
function show_past(){
global $PHP_SELF;
$html = "
[ ログ選択 ] |
古い順に並んでいます
";
$no = file($this->pastno);
for($i=1; $i<=$no[0]; $i++){
$num = sprintf("%03d",$i);
if(file_exists($this->pastdir.$i.".log")){
$html.="過去ログ $num ";
}
}
$html.="現在のログ
|
";
return $html;
}
/***
* 削除フォーム
*
*/
function show_del($n){
global $PHP_SELF,${$this->cookie_n};
list(,,,$pass) = explode(",", ${$this->cookie_n});
$html = "
";
return $html;
}
/***
* ログを配列に
*
*/
function get_arr(){
for($i = 0; $i < count($this->logarr); $i++){
//記事番号\t親記事番号\t根記事番号
list($id, $oya, $root,) = explode("\t", $this->logarr[$i]);
//$this->id : 記事番号をキーにしたログデータ配列
$this->id[$id] = $this->logarr[$i];
//$this->thread : スレッド構造の配列。値は記事番号
$this->thread[$root][$oya][] = $id;
//$this->root : 根記事のみの配列。ログ順
if($oya==0) $this->root[] = $id;
}
//print_r($this->thread);
}
/***
* メインHTML生成処理
*
*/
function show_main($page){
if(intval($page) == 0) $page = 1;//最初はページ1
//ヘッダ部分
switch($this->mode){
//タイトルモード
case 'root':
//ページング生成
$jump = tree::show_jump($page, $this->page_root, count($this->root));
//ヘッダHTML
$html = $jump . $this->root_head;
//1ページ表示数決定
$page_def = $this->page_root;
break;
//展開モード
case 'expn':
$jump = tree::show_jump($page, $this->page_expn, count($this->root));
//ヘッドライン
$html = $jump . tree::show_headline($page, $this->page_expn);
$page_def = $this->page_expn;
break;
//ツリーモード
case 'tree':
$jump = tree::show_jump($page, $this->page_tree, count($this->root));
$html = $jump . $this->tree_head;
$page_def = $this->page_tree;
break;
//一覧モード
case 'dump':
$jump = tree::show_jump($page, $this->page_dump, count($this->id));
$html = $jump;
//最新番号取得
list($st,) = explode("\t", $this->logarr[0]);
//データ開始位置
$st = ($page) ? $st - ($page-1) * $this->page_dump : $st;
//最新記事順に表示
for($i = $st; $i > $st-$this->page_dump; $i--){
$html.= tree::show_msg($i, $this->mode);
}
//フッタ表示で終了
$html.= "
" . $jump;
return $html;
break;
}
//データ開始位置
$st = ($page) ? ($page-1) * $page_def : 0;
//親記事番号でループ
for($i = $st; $i < $st+$page_def; $i++){
if($this->root[$i]=="") continue;
switch($this->mode){
//タイトルモード
case 'root':
$html.= tree::show_msg($this->root[$i], 'root');
$html = str_replace('{num}', $i+1, $html);
break;
//展開モード
case 'expn':
//ツリー構造を初期化
$this->tree_arr = array();
//ツリー生成
tree::make_tree($this->root[$i]);
//ツリー順に表示
foreach($this->tree_arr as $val){
$html.= tree::show_msg($val[0], 'expn');
$html = str_replace('{num}', $i+1, $html);
}
//テーブル閉じ
$html.= $this->expn_bott;
break;
//ツリーモード
case 'tree':
$this->tree_arr = array();
tree::make_tree($this->root[$i]);
foreach($this->tree_arr as $val){
$html.= tree::show_msg($val[0], 'tree', $val[1]);
}
break;
}
}
//フッタ部分
switch($this->mode){
case 'root':
$html.= $this->root_foot;
break;
case 'tree':
$html.= $this->tree_foot;
break;
}
//ページング表示
$html.= $jump;
return $html;
}
/***
* ツリーの生成、並び替え
*
*/
function make_tree($id, $oya=0, $pre="", $img=""){
//前ツリーがLならその下は空
if($img == $this->l_gif) $pre.= $this->nogif;
//前ツリーがTならその下はI
if($img == $this->t_gif) $pre.= $this->i_gif;
//ツリー構造なら
if(is_array($this->thread[$id][$oya])){
foreach($this->thread[$id][$oya] as $no){
//下ツリーがあればT記号終わってればL記号
$img = (count($this->thread[$id][$oya])>1) ? $this->t_gif : $this->l_gif;
//子記事は後ろに送る
$no = ($oya==0) ? array_shift($this->thread[$id][$oya]) : array_pop($this->thread[$id][$oya]);
//ツリー構造と記号を配列に
$this->tree_arr[] = array($no,"$pre$img");
//再帰
tree::make_tree($id,$no,$pre,$img);
}
return true;
}else{
return false;
}
}
/***
* HTML生成・テンプレ置換
*
*/
function show_msg($no, $act="", $mark=""){
global $PHP_SELF,$all,$n,$log;
if($log) $kako = "&log=$log";
if(!$this->id[$no]) return false;
list($id,$oya,$root,$subj,$name,$email,$date,$com,$url,$tim,$host,) = explode("\t", $this->id[$no]);
switch($act){
case 'root':
//if($oya == 0) $html = $this->root_msg;
foreach($this->thread[$no] as $kidno){
rsort($kidno);
$tmp = $kidno[0];
$max = ($tmp > $max) ? $tmp : $max;
$resc += count($kidno);
}
$resc = $resc - 1;
list($lno,$oya,$root,,$lname,$lemail,$ldate,$lcom,$lurl,$ltim,$lhost,) = explode("\t", $this->id[$max]);
$html = $this->root_msg;
$lcom = substr($lcom, 0, 30)."..";
$html = str_replace('{res}', "$resc", $html);
$html = str_replace('{lname}', "$lname", $html);
$html = str_replace('{ldate}', "$ldate", $html);
$html = str_replace('{lcom}', "$lcom", $html);
break;
case 'expn':
$html = ($oya == 0) ? $this->expn_oya : $this->expn_res;
if($email && $this->if_email=="") $html = str_replace('{name}', "{name}", $html);
elseif($email) $html = str_replace('{email}', "$this->if_email", $html);
else $html = str_replace('{email}', "", $html);
break;
case 'tree':
if($oya == 0){
$html = $this->tree_oya;
}else{
$html = $mark . $this->tree_res;
}
if($id == $n) $html = ereg_replace("(]+)>)([^<]+)()","\\3", $html);
if($all) $html = str_replace('{n}', "#$id", $html);
if(!$all && !$n && (strlen($name)+strlen($subj)+strlen($mark) > $this->cut_size)){
if(strlen($name) > strlen($subj)){
$name = substr($name, 0, $this->cut_size-strlen($mark)+strlen($subj)) . "..";
}else{
$subj = substr($subj, 0, $this->cut_size-strlen($mark)+strlen($name)) . "..";
}
}
break;
case 'dump':
$html = $this->dump_msg;
if($email && $this->if_email=="") $html = str_replace('{name}', "{name}", $html);
elseif($email) $html = str_replace('{email}', "$this->if_email", $html);
else $html = str_replace('{email}', "", $html);
if($id == $n) $html = str_replace(''."([^<]+)", "", $html);
}
if($url) $html = str_replace('{url}',"$this->if_url", $html);
else $html = str_replace('{url}', "", $html);
// 自動リンク
$com = tree::auto_link($com);
// >がある時は色変更
$com = ereg_replace("(^|>)(>[^<]*)", "\\1quote>\\2", $com);
$html = str_replace('{id}', $id, $html);
$html = str_replace('{subj}', $subj, $html);
$html = str_replace('{name}', $name, $html);
$html = str_replace('{date}', $date, $html);
$html = str_replace('{com}', $com, $html);
$html = str_replace('{host}', $host, $html);
$html = str_replace('{time}', $tim, $html);
$html = str_replace('{n}', $PHP_SELF."?n=".$id.$kako, $html);
$html = str_replace('{all}', $PHP_SELF."?all=".$root.$kako, $html);
$html = str_replace('{reply}', $PHP_SELF."?n=".$id.$kako."#frm", $html);
$html = str_replace('{nl}', "\n", $html);
if(time() - $tim < $this->expire*3600) $html = str_replace('{new}', $this->new_msg, $html);
else $html = str_replace('{new}', "", $html);
return $html;
}
/***
* 書き込み前チェック
*
*/
function add_chk($root=0, $oya=0, $name, $email, $subj, $com, $url, $pass, $email_reply, $no=''){
global $REQUEST_METHOD,$PHP_SELF;
if ($_SESSION['time'] == "") {
$this->error = "不正な投稿をしないで下さい";
return false;
}
if (time() - $_SESSION['time'] < $this->posttime) {
$this->error = "投稿はもうしばらく時間を置いてからお願い致します";
return false;
}
// 数字化
if (!is_numeric($root) || !is_numeric($oya)) {
$this->error = "不正な投稿をしないで下さい";
return false;
}
if ($no != "") $no = intval($no);
if (preg_match("/(]*?>|\[url(?:\s?=|\]))|href=/i", $com)) {
$this->error = "禁止ワードエラー!!";
return false;
}
if($REQUEST_METHOD != "POST") {
$this->error = "不正な投稿をしないで下さい";
return false;
}
if($url && !ereg("^http://", $url)){
$this->error = "URLはhttp://から記入してください";
return false;
}
if($email && !ereg(".+@.+\\..+", $email)){
$this->error = "メールアドレスは正しく記入してください";
return false;
}
if($name=="" || ereg("^( | )*$",$name)){
$this->error = "名前が書き込まれていません";
return false;
}
if($subj=="" || ereg("^( | )*$",$subj)){
$this->error = "題名が書き込まれていません";
return false;
}
if($com=="" || ereg("^( | |[\r\n])*$",$com)){
$this->error = "本文が書き込まれていません";
return false;
}
// 親チェック、深さチェック、レス数チェック
if($root != 0 && $no == ''){
if(!is_array($this->thread[$root])){
$this->error = "返信先の記事が見つかりませんでした";
return false;
}
if(count($this->thread[$root]) > $this->max_depth){
$this->error = "ツリー階層が深くなりすぎたので
これ以上返信できません";
return false;
}
foreach($this->thread[$root] as $kidno){
$resc += count($kidno);
}
if($resc > $this->max_res){
$this->error = "レス数制限に達したので
これ以上返信できません";
return false;
}
}
if($no == "kako"){
$this->error = "過去ログには投稿できません";
return false;
}
//現在時刻
$tim = time();
// ホスト名を取得
$ip = (getenv("HTTP_X_FORWARDED_FOR") != "") ? getenv("HTTP_X_FORWARDED_FOR") : getenv("REMOTE_ADDR");
$host = gethostbyaddr($ip);
//同一ホストからの連続投稿禁止
list($lno,,,,$lname,,,$lcom,,$ltime,$lhost,) = explode("\t", $this->logarr[0]);
if($this->renzoku && $host==$lhost && $tim - $ltime < $this->renzoku){
$this->error = "連続投稿はもうしばらく時間を置いてからお願い致します";
return false;
}
//時間のフォーマット
$date = gmdate("m/d H:i",$tim+9*60*60);
//url整形
$url = trim($url);
$url = ereg_replace("^http://", "", $url);
$url = str_replace(" ", "%20", $url);
//PW暗号化
if(trim($pass)!="") $pwd = substr(md5($pass),2,8);
//テキスト整形
$subj = tree::CleanStr($subj);
$name = tree::CleanStr($name);
$email= tree::CleanStr($email);
$url = tree::CleanStr($url);
$com = tree::CleanStr($com,1);
// 改行文字の統一。
$com = str_replace("\r\n", "\n", $com);
$com = str_replace("\r", "\n", $com);
if(substr_count($com, "\n") > $this->max_line){
$this->error = "コメント行数が長すぎます";
return false;
}
// 連続する空行を一行・\n→
\n→\n除去
$com = ereg_replace("\n(( | )*\n){3,}","\n",$com);
$com = nl2br($com);
$com = str_replace("\n", "", $com);
// 二重投稿チェック
if($no == '' && $name == $lname && $com == $lcom){
$this->error = "二重投稿は禁止です";
return false;
}
// 新NO、親は自分がroot
if($no == ''){
$no = $lno + 1;
if($root == 0) $root = $no;
} elseif(!$this->id[$no]){
$this->error = "該当記事がみつかりません";
return false;
}
$no = intval($no);
$oya = intval($oya);
$root = intval($root);
$dat = array($no,$oya,$root,$subj,$name,$email,$date,$com,$url,$tim,$host,$pwd,$email_reply);
// クッキー保存
$cookvalue = implode(",", array($name,$email,$url,$pass));
setcookie ($this->cookie_n, $cookvalue,time()+14*24*3600);
return $dat;
}
/***
* 新規書き込み
*
*/
function add_post($dat){
list($no,$oya,$root,$subj,$name,$email,$date,$com,$url,$tim,$host,$pwd,$email_reply) = $dat;
// データフォーマット
$new_msg = implode("\t", $dat)."\n";
// $new_msg = "$no\t$oya\t$root\t$subj\t$name\t$email\t$date\t$com\t$url\t$tim\t$host\t$pwd\t$email_reply\n";
$mailbody = str_replace(">", ">", $com);
$mailbody = str_replace("<", "<", $mailbody);
$mailbody = str_replace(""e;", '"', $mailbody);
$mailbody = str_replace("&", "&", $mailbody);
$mailbody = eregi_replace("
", "\n", $mailbody);
// 管理人にメール通知
if($this->adm_mail && ereg(".+@.+\\..+", $this->adm_mail)){
$subject = str_replace("{id}", "$no", $this->adm_subj);
$subject = str_replace("{subj}", $subj, $subject);
$body = "Date: $date\nHost: $host\n";
$body.= "---------------------------------------------\n";
$body.= $mailbody;
tree::send_mail($name, $email, $this->adm_mail, $subject, $body);
}
// 新ログ配列生成
if($oya != 0){
// レスがあったらメール
list(,,,,,$o_email,,,,,,,$reply) = explode("\t", $this->id[$oya]);
if(rtrim($reply) == "y" && ereg(".+@.+\\..+", $o_email)){
$subject = $no."-".$subj;
$body = "$name さんからのレス\n";
$body.= "Date: $date\nHost: $host\n";
$body.= "---------------------------------------------\n";
$body.= $mailbody;
tree::send_mail($name, $email, $o_email, $subject, $body);
}
for ($i = 0; $i < count($this->logarr); $i++) {
list($id, $oy, $rt) = explode("\t", $this->logarr[$i]);
if($root == $rt) $age[] = $this->logarr[$i];
else $buf[] = $this->logarr[$i];
}
$this->logarr = array_merge($age, $buf);
}
array_unshift($this->logarr, $new_msg);
// 過去ログ
if($this->past){
// ログ数オーバーは過去ログに書き出す
if(count($this->logarr) > $this->max_log){
$back = array_pop($this->logarr);
$backline[] = $back;
list($bid, $boya, $broot) = explode("\t", $back);
for ($j = count($this->logarr); $j >= 0; $j--){
list($id, $oy, $root) = explode("\t", $this->logarr[$j]);
if($bid == $root){
array_unshift($backline, $this->logarr[$j]);
array_pop($this->logarr);
}
}
// 現No取得
$no = file($this->pastno);
// 現過去ログ読み込み
if(file_exists($this->pastdir.$no[0].".log")) {
$pastline = file($this->pastdir.$no[0].".log");
}
// 現過去ログ行数オーバーならNOアップ
if(count($pastline) > $this->max_log){
$no[0]++;
$fp = fopen($this->pastno, "w");
fputs($fp, $no[0]);
fclose($fp);
}else{
$backline = array_merge($backline, $pastline);
}
// 過去ログ更新
$fp = fopen($this->pastdir.$no[0].".log", "w");
flock($fp, LOCK_EX);
fputs($fp, implode('', $backline));
fclose($fp);
}
}
// ログ書き込み
$fp = fopen($this->logfile, "w");
flock($fp, LOCK_EX);
fputs($fp, implode('', $this->logarr));
fclose($fp);
return true;
}
/***
* 編集書き込み
*
*/
function edit_post($dat){
list($no,$oya,$root,$subj,$name,$email,$date,$com,$url,$tim,$host,$pwd,$email_reply) = $dat;
// データフォーマット
$new_msg = implode("\t", $dat)."\n";
for($i = 0; $i < count($this->logarr); $i++){
list($id,) = explode("\t", $this->logarr[$i]);
if($id == $no){
$this->logarr[$i] = $new_msg;
break;
}
}
// ログ書き込み
$fp = fopen($this->logfile, "w");
flock($fp, LOCK_EX);
fputs($fp, implode('', $this->logarr));
fclose($fp);
return true;
}
/***
* タグ・¥除去
*
*/
function CleanStr($str,$com=0){
//先頭と末尾の空白除去
$str = trim($str);
//区切り文字\t変換
$str = str_replace("\t", " ", $str);
//¥を削除
if(get_magic_quotes_gpc()){
$str = stripslashes($str);
}
if(isset($this->bad_word)) $str = ereg_replace($this->bad_word, "**", $str);
if($this->allow_tag && $com == 1){
//許可タグ以外除去
// $str = strip_tags($str, $this->allow_tag);
$str = htmlspecialchars($str);
$tags = str_replace("><", "|", $this->allow_tag);
$tags = ereg_replace("[<>]", "", $tags);
$str = preg_replace("/<($tags)\b(.*?)>/si", "<\\1\\2>", $str);
$str = eregi_replace("<\/($tags)>", "\\1>", $str);
$str = eregi_replace("<(.*)(style|onmouse|onclick|script)[^=]*=", "<\\1", $str);
}else{
//タグ変換
$str = htmlspecialchars($str);
}
if ($com == 0) {
$str = eregi_replace("[\r\n]", "", $str);
}
//特殊文字
$str = str_replace("&#", "", $str);
$str = str_replace(""", '"', $str);
return $str;
}
/***
* 削除
*
*/
function del_msg($id, $pwd){
if(!isset($this->id[$id])){
$this->error = "該当記事が見つかりません";
return false;
}
if(trim($pwd)==""){
$this->error = "パスワードを入力してください";
return false;
}
list($no,$oya,$root,,,,,,,,,$pass,) = explode("\t", $this->id[$id]);
if($this->adm_pass == $pwd || substr(md5($pwd),2,8) == $pass){
$this->id[$id] = "$no\t$oya\t$root\t削除\t\t\t\tこの記事は削除されました\t\t\t\t\t\n";
$fp = fopen($this->logfile, "w");
flock($fp, LOCK_EX);
fputs($fp, implode('', $this->id));
fclose($fp);
} else {
$this->error = "パスワードが違います";
return false;
}
return true;
}
/***
* 編集
*
*/
function edit_msg($id, $pwd){
if(!isset($this->id[$id])){
$this->error = "該当記事が見つかりません";
return false;
}
if(trim($pwd)==""){
$this->error = "パスワードを入力してください";
return false;
}
list($no,$oya,$root,$subj,$name,$email,,$com,$url,,,$pass,) = explode("\t", $this->id[$id]);
if($this->adm_pass == $pwd || substr(md5($pwd),2,8) == $pass){
$com = eregi_replace("
", "\r", $com);
$html = tree::show_form($root, $oya, $subj, $com, "edit", $name, $email, $url, $no, $pwd);
} else {
$this->error = "パスワードが違います";
return false;
}
return $html;
}
/***
* 検索
*
*/
function search($word, $andor){
global $log;
if(!isset($word)) return false;
if(get_magic_quotes_gpc()) $word = stripslashes($word);
$keys = preg_split("/( | )+/", trim($word));
foreach($this->logarr as $line){
$find = FALSE;
for($i = 0; $i < count($keys); $i++){
if($keys[$i]=="") continue;
if(stristr($line,$keys[$i])){
$find = TRUE;
list($id,) = explode("\t", $line);
}elseif($andor == "and"){
$find = FALSE;
break;
}
}
if($find) $result[] = $id;
}
if(is_array($result)){
$word = htmlspecialchars($word);
$html.= "$word の検索結果 ".count($result)."件\n";
foreach($result as $no){
$html.= tree::show_msg($no, 'dump');
}
}
return $html;
}
/***
* メール送信
*
*/
function send_mail($name, $from, $to, $subject, $body){
if($subject!="") $subject = tree::mime_enc($subject);
$body = str_replace("\r\n", "\n", $body);
$body = str_replace("\r", "\n", $body);
//$str = mb_convert_encoding($str, "JIS", "SJIS");
$name = tree::mime_enc($name);
$froma = ($from) ? "$name<$from>" : "$name";
$head = "From: $froma\n";
$head.= "X-REF: ".getenv("HTTP_REFERER");
@mail($to, $subject, $body, $head);
}
/***
* MIMEエンコ
*
*/
function mime_enc($str){
//$str = mb_convert_encoding($str, "JIS", "SJIS");
$encode = "=?iso-2022-jp?B?" . base64_encode($str) . "?="; //Bヘッダ+エンコード
return $encode;
}
/***
* ヘッダ取得
*
*/
function show_head(){
if(file_exists("dcount.php")) include("dcount.php");
$this->head = str_replace("{today}", $today, $this->head);
$this->head = str_replace("{yesterday}", $yesterday, $this->head);
$this->head = str_replace("{total}", $total, $this->head);
return $this->head;
}
/***
* フッタ取得
*
*/
function show_foot(){
$foot = str_replace("