#!/usr/bin/perl
# ------------------------------------------------------------------------------
# CDB Viewer
# ------------------------------------------------------------------------------
my $document_root = '..';
# Modules
use strict;
use Time::Local;
# Common Lib
use lib "../system/lib";
use common;
# Debug
use Data::Dumper;
use CGI::Carp qw(fatalsToBrowser);
# ドキュメント名
my $document_name = 'topics';
# DB設定ディレクトリ
our $config_dir = 'conf';
#my $php_path = 'C:\php\php';
my $php_path = '/usr/bin/php';
# ===============================================================================
# フレームワークの設定変更
# ===============================================================================
$common::conf->{'sys_root'} = "$document_root/system";
$config_dir = "$document_root/system/$config_dir";
#================================================================================
# 設定読み込み
#================================================================================
# ---- 表示設定 ----------------------------------------------------------------
require qq|${document_name}_config.pl|;
my $view;
{
$view = $viewconf::view;
}
# ツール名
my $tool_name = 'contents';
# ---- DB全体設定 --------------------------------------------------------------
require qq|$config_dir/${tool_name}_conf.pl|;
my $cnf;
{
my $config_package_name;
## 標準設定で取得
$config_package_name = '$'.qq|config::cnf|;
$cnf = eval $config_package_name;
## 見つからない場合はツール名付きでトライ
if(!$cnf){
$config_package_name = '$'.$tool_name.qq|::config::cnf|;
$cnf = eval $config_package_name;
}
if(!$cnf){
error('設定ファイルが見つかりません。')
}
# スクリプト名補完
$cnf->{'script_name'} = $ENV{'SCRIPT_NAME'};
if(!$view->{'detail_script_name'}){
$cnf->{'detail_script_name'} = qq|${document_name}_detail.cgi|;
}else{
$cnf->{'detail_script_name'} = $view->{'detail_script_name'};
}
# ファイル名補完
$cnf->{'data_filename'} = qq|${tool_name}.dat| if($cnf->{'data_filename'} eq '');
$cnf->{'data_file'} = qq|$common::conf->{'sys_root'}/$cnf->{'data_dir'}/$cnf->{'data_filename'}|;
$cnf->{'preview_data_file'} = qq|$common::conf->{'sys_root'}/$cnf->{'preview_root_dir'}/$cnf->{'data_filename'}|;
$cnf->{'preview_root_dir'} = qq|$common::conf->{'sys_root'}/$cnf->{'preview_root_dir'}|;
# ディレクトリ名補完
$cnf->{'img_path'} = qq|$cnf->{'img_dir'}/$tool_name|;
$cnf->{'thumb_path'} = qq|$cnf->{'thumb_dir'}/$tool_name|;
$cnf->{'file_path'} = qq|$cnf->{'file_dir'}/$tool_name|;
}
# ---- DBテーブル設定 ----------------------------------------------------------
require qq|$config_dir/${tool_name}_table.pl|;
my $table;
{
my $table_package_name;
## 標準設定で取得
$table_package_name = '$'.qq|table::layout|;
$table = eval $table_package_name;
## 見つからない場合はツール名付きでトライ
if(!$table){
$table_package_name = '$'.$tool_name.qq|::table::layout|;
$table = eval $table_package_name;
}
if(!$table){
error('テーブル設定ファイルが見つかりません。');
}
}
#================================================================================
# メインルーチン
#================================================================================
# ----- データ収集 -------------------------------------------------------------
my %form = read_form();
my %cookie = get_cookie();
# ----- DB読み込み -------------------------------------------------------------
my @data;
if($form{'preview'} eq 'on'){
@data = read_db($cnf->{'preview_data_file'});
}else{
# 該当するコーナーIDを抽出
if($form{'corner'} ne ''){
my $corner;
$form{'corner'} = int($form{'corner'});
foreach my $target (@{$view->{'corner'}}){
if($form{'corner'} == $target){
$view->{'corner'} = [$target];
$corner = $target;
last;
}
}
if($corner eq ''){
$form{'corner'} = '';
}
}
@data = grep {
{ map { $_, 1 } (@{$view->{'corner'}}) }->{$_->{'corner'}}
} read_db($cnf->{'data_file'});
# @data = read_db($cnf->{'data_file'});
# 公開期間設定がある場合
if($table->{'open'}->{'type'} != 0){
# 公開設定が非公開のものをマスク
@data = grep { $_->{'hidden'} ne 'on' } @data;
# 公開期間外をマスク
my $nowtime = time();
if($table->{'open'}->{'type'} == 1 && $table->{'open'}->{'future_handling'} != 1){
@data = grep { (split(/,/,$_->{'dateset'}))[0] < $nowtime } @data;
}elsif($table->{'open'}->{'type'} == 2 || $table->{'open'}->{'type'} == 3 ){
@data = grep { (split(/,/,$_->{'dateset'}))[1] > $nowtime } grep { (split(/,/,$_->{'dateset'}))[0] < $nowtime } @data;
}
# 並び順をソート
@data = sort { (split(",",$b->{'dateset'}))[0] <=> (split(",",$a->{'dateset'}))[0] } reverse @data;
}
}
# ----- テンプレート設定 -------------------------------------------------------
my $template;
# ----- モード分岐 -------------------------------------------------------------
if($cnf->{'script_name'} =~ /top\.cgi$/){
top_list();
}elsif($cnf->{'script_name'} =~ /json\.cgi$/){
json_list();
}elsif($cnf->{'script_name'} =~ /detail\.cgi$/){
detail();
}else{
list();
}
#
#
exit;
#================================================================================
# list
# 記事の一覧表示
# パラメタ : なし
# 返り値 : なし
# 出力 : 記事一覧ページ
#================================================================================
sub list {
my $html;
my $array = @data;
### 表示記事決定 ###########################################################
my $page = ''; # 表示ページ
my $from = ''; # 表示開始位置
my $to = ''; # 表示終了位置
$form{'page'} =~ s/\W//g;
$page = int($form{'page'});
$page = 1 if($page < 1);
my $max_page = int(($array - 1) / $view->{"items_per_page"}) + 1;
$page = $max_page if($page > $max_page);
$from = ($page - 1) * $view->{"items_per_page"};
$to = $from + $view->{"items_per_page"} - 1;
$to = $array - 1 if($to >= $array);
### 表示記事決定 ###########################################################
my $navi;
my $corner_param;
if($form{'corner'} ne ''){
$corner_param = qq|&corner=$form{'corner'}|;
}
# 前後ボタン生成
my $prev = '';
my $next = '';
# 前ボタン
if($page < 2){
$prev = $view->{'btn_prev'};
}else{
my $prev_page = $page - 1;
$prev = qq|$view->{'btn_prev'}|;
}
# 後ボタン
if($page >= $max_page ){
$next .= $view->{'btn_next'};
}else{
my $next_page = $page + 1;
$next .= qq|$view->{'btn_next'}|;
}
# ダイレクトジャンプ生成
my $direct = '';
my $page_from = '';
my $page_to = '';
$page_from = int($page - ($view->{'direct_jump'} / 2));
$page_to = int($page + ($view->{'direct_jump'} / 2));
$page_from = 1 if($page_from < 1);
$page_to = $max_page if($page_to > $max_page);
for(my $i=$page_from;$i<=$page_to;$i++){
my $now = '';
if($i == $page){
$now =qq|class="now"|;
}
$direct .= qq||;
$direct .= sprintf ($view->{'direct_jump_format'},$i);
$direct .= qq| |;
}
# ナビ生成
$navi = $view->{'navi_style'};
$navi =~ s/\[PREV\]/$prev/ig;
$navi =~ s/\[NEXT\]/$next/ig;
$navi =~ s/\[DIRECT\]/$direct/ig;
## 記事一覧生成 ############################################################
$html .= $view->{'list_head'};
for(my $i=$from; $i<=$to; $i++){
my $item = $data[$i];
my $id = $item->{'id'};
my $date = get_date( $item );
my $icon = get_corner_icon( $item );
my $corner = get_item_format( $item, 'corner' )->{'html'};
my $title = get_item_format( $item, 'title' )->{'html'};
my $comment = get_item_format( $item, 'comment' )->{'html'};
my $link = get_item_format( $item, 'link' )->{'html'};
## アイコンHTMLタグ
my $corner_html;
if($view->{'corner_icon'} == 1){
$corner_html = qq||;
}else{
$corner_html = $corner;
}
## リンク先調整
if($link ne ''){
$title = qq|$title|;
}elsif($comment ne ''){
$title = qq|$title|;
}
## HTML生成
my $tmphtml = $view->{'list_body'};
$tmphtml =~ s/\[CORNER\]/$corner_html/ig;
$tmphtml =~ s/\[DATE\]/$date/ig;
$tmphtml =~ s/\[TITLE\]/$title/ig;
$html .= $tmphtml;
}
$html .= $view->{'list_foot'};
$html =~ s/\[NAVI\]/$navi/ig;
$template->{'contents'} = $html;
print_html_et($template, $view->{'list_template'});
}
#================================================================================
# json_list
# 記事の一覧表示
# パラメタ : なし
# 返り値 : なし
# 出力 : 記事一覧ページ
#================================================================================
sub json_list {
my $json;
my $callback = $view->{'json_callback'};
my @json_list;
my $array = @data;
### 表示記事決定 ###########################################################
my $from = 0; # 表示開始位置
my $to = $view->{"top_items_per_page"} - 1; # 表示終了位置
if($to >= $array){
$to = $array - 1;
}
## 記事一覧生成 ############################################################
for(my $i=$from; $i<=$to; $i++){
my $item = $data[$i];
my $id = $item->{'id'};
my $date = get_date( $item );
my $title = get_item_format( $item, 'title' )->{'html'};
my $comment = get_item_format( $item, 'comment' )->{'html'};
my $link = get_item_format( $item, 'link' )->{'html'};
my $corner = get_item_format( $item, 'corner' )->{'html'};
my $icon = get_corner_icon( $item );
## リンク先調整
my $internal = 0;
if($comment ne ''){
$internal = 1;
$link = qq|$cnf->{'detail_script_name'}?id=$id|;
}
my $json_item =<<"__END__";
{
id: "$id",
date: "$date",
title: "$title",
link: "$link",
internal: "$internal",
corner: "$corner",
icon: "$icon"
}
__END__
push @json_list, $json_item;
}
# JSONP
$json .= qq|$callback ([|;
$json .= join ',',@json_list;
$json .= qq|]);|;
print qq|Content-type: text/javascript; charset=utf-8\n\n|;
print $json;
}
#================================================================================
# top_list
# 記事の一覧表示
# パラメタ : なし
# 返り値 : なし
# 出力 : 記事一覧ページ
#================================================================================
sub top_list {
my $html;
my $array = @data;
### 表示記事決定 ###########################################################
my $from = 0; # 表示開始位置
my $to = $view->{"top_items_per_page"} - 1; # 表示終了位置
if($to >= $array){
$to = $array - 1;
}
## 記事一覧生成 ############################################################
$html .= $view->{'top_list_head'};
for(my $i=$from; $i<=$to; $i++){
my $item = $data[$i];
my $id = $item->{'id'};
my $date = get_date( $item );
my $icon = get_corner_icon( $item );
my $corner = get_item_format( $item, 'corner' )->{'html'};
my $title = get_item_format( $item, 'title' )->{'html'};
my $comment = get_item_format( $item, 'comment' )->{'html'};
my $link = get_item_format( $item, 'link' )->{'html'};
## アイコンHTMLタグ
my $corner_html;
if($view->{'corner_icon'} == 1){
$corner_html = qq||;
}else{
$corner_html = $corner;
}
## リンク先調整
if($link ne ''){
$title = qq|$title|;
}elsif($comment ne ''){
$title = qq|$title|;
}
## コメント装飾
$comment = alink ($comment,'_blank');
$comment = decoration ($comment);
## HTML生成
my $tmphtml = $view->{'top_list_body'};
$tmphtml =~ s/\[CORNER\]/$corner_html/ig;
$tmphtml =~ s/\[COMMENT\]/$comment/ig;
$tmphtml =~ s/\[DATE\]/$date/ig;
$tmphtml =~ s/\[TITLE\]/$title/ig;
$html .= $tmphtml;
}
$html .= $view->{'top_list_foot'};
$template->{'contents'} = $html;
print_html_et($template, $view->{'top_list_template'});
}
#================================================================================
# detail
# 記事の一覧表示
# パラメタ : なし
# 返り値 : なし
# 出力 : 記事一覧ページ
#================================================================================
sub detail {
my $html;
my $item;
if($form{'preview'} ne 'on'){
my @entry = search_data('id',$form{'id'},@data);
if(@entry != 1){
$item->{'empty'} = 1;
}else{
$item = shift @entry;
}
}else{
$item = shift @data;
}
## 詳細記事生成 ############################################################
my $format;
foreach my $label (@{$table->{'table'}}){
$format->{$label->{'name'}} = get_item_format( $item, $label->{'name'} );
}
## 日付
$format->{'pubdate'} = get_date( $item );
## アイコンHTMLタグ
my $corner_html;
{
my $icon = get_corner_icon( $item );
my $corner = $format->{'corner'}->{'html'};
if($view->{'corner_icon'} == 1){
$corner_html = qq||;
}else{
$corner_html = $corner;
}
$format->{'corner_html'} = $corner_html;
}
## コメント装飾
$format->{'comment'}->{'html'} = alink ($format->{'comment'}->{'html'},'_blank');
$format->{'comment'}->{'html'} = decoration ($format->{'comment'}->{'html'});
## 記事出力
$template->{'title'} = $format->{'title'}->{'html'};
$template->{'contents'} = viewconf::detail($format);;
print_html_et($template, $view->{'detail_template'});
}
#================================================================================
# get_item_format
# パラメタ : 記事データ, 項目名
# 返り値 : HTML
# 出力 : なし
#================================================================================
sub get_item_format {
my ($item, $name) = @_;
my $output;
my $label = (search_data('name',$name,@{$table->{'table'}}))[0];
#$output->{'label'} = $label;
# 1: 文字型の場合
if($label->{'type'} == 1){
$output->{'html'} = $item->{$name};
}
# 2/3: 選択肢の場合
elsif($label->{'type'} == 2 || $label->{'type'} == 3){
$output->{'html'} = (split ",",$label->{'options'})[$item->{$name}];
}
# 4: 選択肢の場合
elsif($label->{'type'} == 4){
my @array;
foreach my $tmp ( split /,/,$item->{$name} ){
@array = (split ",",$label->{'options'}) [$tmp];
}
$output->{'html_array'} = \@array;
}
# 11: 画像の場合
elsif($label->{'type'} == 11){
$label->{'imagetype'} = $cnf->{'imagetype'} if($label->{'imagetype'} eq '');
my @imagetype = split ",",$label->{'imagetype'};
# 画像のパス取得
my $filename = '';
foreach my $ext (@imagetype){
my $tmp_fname = sprintf "%s/%s/%s_%s.%s",$document_root,$cnf->{'img_path'},$label->{'prefix'},$item->{'id'},$ext;
if(-e $tmp_fname) {
$filename = $tmp_fname;
last;
}
}
# サムネールのパス取得
my $thumb = '';
{
my $tmp_fname = sprintf "%s/%s/%s_%s_thumb.jpg",$document_root,$cnf->{'thumb_path'},$label->{'prefix'},$item->{'id'};
if(-e $tmp_fname) {
$thumb = $tmp_fname;
last;
}
}
# プレビューモードの場合
if($form{'preview'} eq 'on'){
# プレビュー画像のパス取得
foreach my $ext (@imagetype){
my $tmp_fname = sprintf "%s/%s/%s_%s.%s",$cnf->{'preview_root_dir'},$cnf->{'img_path'},$label->{'prefix'},$item->{'id'},$ext;
if(-e $tmp_fname) {
$filename = $tmp_fname;
last;
}
}
# プレビューサムネールのパス取得
{
my $tmp_fname = sprintf "%s/%s/%s_%s_thumb.jpg",$cnf->{'preview_root_dir'},$cnf->{'thumb_path'},$label->{'prefix'},$item->{'id'};
if(-e $tmp_fname) {
$thumb = $tmp_fname;
last;
}
}
}
if($filename && $thumb){
$output->{'exist'} = 2;
}elsif($filename){
$output->{'exist'} = 1;
}else{
$output->{'exist'} = 0;
}
$output->{'filename'} = $filename;
$output->{'thumb'} = $thumb;
}
# 12:添付ファイルの場合
elsif($label->{'type'} == 12){
$label->{'filetype'} = $cnf->{'filetype'} if($label->{'filetype'} eq '');
my @filetype = split ",",$label->{'filetype'};
my $filename = '';
$output->{'exist'} = 0;
foreach my $ext (@filetype){
my $tmp_fname;
if($form{'preview'} eq 'on'){
$tmp_fname = sprintf "%s/%s/%s_%s.%s",$cnf->{'preview_root_dir'},$cnf->{'file_path'},$label->{'prefix'},$item->{'id'},$ext;
if(! -e $tmp_fname){
$tmp_fname = sprintf "%s/%s/%s_%s.%s",$document_root,$cnf->{'file_path'},$label->{'prefix'},$item->{'id'},$ext;
}
}else{
$tmp_fname = sprintf "%s/%s/%s_%s.%s",$document_root,$cnf->{'file_path'},$label->{'prefix'},$item->{'id'},$ext;
}
if(-e $tmp_fname) {
$filename = $tmp_fname;
$output->{'exist'} = 1;
$output->{'ext'} = $ext;
$output->{'size'} = -s $filename;
last;
}
}
$output->{'filename'} = $filename;
}
# 21:日付入力
elsif($label->{'type'} == 21){
$output->{'html'} = date_conv(10,$item->{$name});
}
# 22:日付入力
elsif($label->{'type'} == 22){
my ($systime1,$systime2,$switch) = split /,/,$item->{$name};
$output->{'html'} = date_conv(10,$systime1).'~'.date_conv(10,$systime2);
}
return $output;
}
#================================================================================
# decoration
# 文字装飾
# パラメタ : 記事データ
# 返り値 : HTML
# 出力 : なし
#================================================================================
sub decoration{
my $html = shift;
$html =~ s/\[RED\](.+?)\[\/RED\]/$1<\/strong>/ig;
$html =~ s/\[GREEN\](.+?)\[\/GREEN\]/$1<\/strong>/ig;
$html =~ s/\[BLUE\](.+?)\[\/BLUE\]/$1<\/strong>/ig;
$html =~ s/\[B\](.+?)\[\/B\]/$1<\/strong>/ig;
return $html;
}
#================================================================================
# get_corner_icon
# リストアップモード:記事の一覧表示
# パラメタ : 記事データ
# 返り値 : HTML
# 出力 : なし
#================================================================================
sub get_corner_icon {
my $item = shift;
my $iconfile = qq|$view->{'corner_icon_dir'}/$view->{'corner_iconfile'}->{$item->{'corner'}}|;
return $iconfile
}
#================================================================================
# get_date
# リストアップモード:記事の一覧表示
# パラメタ : 記事データ
# 返り値 : HTML
# 出力 : なし
#================================================================================
sub get_date {
my $item = shift;
my $epoc = (split ',',$item->{'dateset'})[0];
return date_conv(2,$epoc);
}
#================================================================================
# get_date
# リストアップモード:記事の一覧表示
# パラメタ : 記事データ
# 返り値 : HTML
# 出力 : なし
#================================================================================
sub get_date {
my $item = shift;
my $epoc = (split ',',$item->{'dateset'})[0];
return date_conv(2,$epoc);
}
#================================================================================
# date_conv
# 日付形式の生成
# パラメタ : $date_type(日付型の番号)
# $era_mode = 0 (西暦表示)の場合
# [1]0000/ 0/ 0 [2]0000/00/00 [3]00/ 0/ 0 [4]00/00/00
# [5]0000. 0. 0 [6]0000.00.00 [7]00. 0. 0 [8]00.00.00
# [9]0000年0月0日 [10]0000年0月0日(曜)
# $era_mode = 1 (年号表示)の場合
# [1]年号00年00月00日 [2]年号00年00月00日(曜)
# 返り値 : $date_style(日付形式)
# 出力 : なし
#================================================================================
sub date_conv {
my ($date_type, $time_value) = @_;
my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = gmtime ($time_value + 32400);
my @wdays = ("日","月","火","水","木","金","土");
$year += 1900;
$mon += 1;
my $syear = ($year + 1900) % 100;
my $date_style = '';
# 西暦表示の場合
if($cnf->{'era_mode'} == 0){
if($date_type == 1) {
$date_style = sprintf("%4d/%2d/%2d", $year, $mon, $mday);
}
elsif($date_type == 2) {
$date_style = sprintf("%04d/%02d/%02d", $year, $mon, $mday);
}
elsif($date_type == 3) {
$date_style = sprintf("%2d/%2d/%2d", $syear, $mon, $mday);
}
elsif($date_type == 4) {
$date_style = sprintf("%02d/%02d/%02d", $syear, $mon, $mday);
}
elsif($date_type == 5) {
$date_style = sprintf("%4d.%2d.%2d", $year, $mon, $mday);
}
elsif($date_type == 6) {
$date_style = sprintf("%04d.%02d.%02d", $year, $mon, $mday);
}
elsif($date_type == 7) {
$date_style = sprintf("%2d.%2d.%2d", $syear, $mon, $mday);
}
elsif($date_type == 8) {
$date_style = sprintf("%02d.%02d.%02d", $syear, $mon, $mday);
}
elsif($date_type == 9) {
$date_style = sprintf("%d年%d月%d日", $year, $mon, $mday);
}
elsif($date_type == 10) {
$date_style = sprintf("%d年%d月%d日(%s)", $year, $mon, $mday, $wdays[$wday]);
}
else {
$date_style = sprintf("%4d/%2d/%2d", $year, $mon, $mday);
}
}
# 年号表示の場合
elsif($cnf->{'era_mode'} == 1){
my $year_count = $year + $cnf->{'era_offset'};
my $year_label = "$cnf->{'era_name'}${year_count}";
if($date_type == 1) {
$date_style = sprintf("%s年%2d月%2d日",$year_label, $mon, $mday);
}
elsif($date_type == 2) {
$date_style = sprintf("%s年%2d月%2d日(%s)",$year_label, $mon, $mday, $wdays[$wday]);
}
else {
$date_style = sprintf("%s年%2d月%2d日",$year_label, $mon, $mday);
}
}
return $date_style;
}
#================================================================================
# read_db
# データベース読み込み
# パラメタ : ファイルパス
# 返り値 : 記事データ
# 出力 : なし
#================================================================================
sub read_db {
my $filepath = shift;
# 通常読込
if(-e "${filepath}.fmt" && -e $filepath){
return read_data($filepath);
}else{
return -1;
}
}
#================================================================================
# print_html_php (\%html, $template_file);
# HTML出力 (簡易テンプレート)
#================================================================================
sub print_html_php {
my @gzip_str = ('[GZIP OFF]','[GZIP ON]');
my $html = shift;
my $template_html_file = shift;
$html->{'gzip_mode'} = $gzip_str[ http_header ];
map { $html->{$_} = outcode($html->{$_}) } keys(%{$html});
my $template_html = `$php_path $template_html_file`;
my $template = join '',$template_html;
foreach my $key (keys (%{$html})){
my $target = qq||;
$template =~ s/($target)/$html->{$key}/igs;
}
print $template;
}