#!/usr/bin/perl use strict; use Date::Calc qw(Today); use Boofy::Main; use Boofy::Login; use Boofy::HTML qw(make_comm_table make_friend_table make_path); use Boofy::String qw(get_time tune_html tune_form make_clickable get_age short_japanese_date fold_line %cf_blood %cf_sex make_photo_dir); use Boofy::Config qw(PIC_DIR ADMIN_EMAIL ADMIN_NAME DB_DIARY_RSS DB_ADMIN); use Boofy::Cache; use Boofy::Log; use Boofy::Session; use constant LIMIT_TIME => 6 * 3600; ## 6時間 use constant LIMIT_COUNT => 500; #------------------------------------------------------------------------------ # FUNCTIONS #------------------------------------------------------------------------------ sub get_data { my ($dbh2, $member_id) = @_; my $sth = $dbh2->prepare(qq{ SELECT member.first_name, member.last_name, member.nickname, member.sex, member.birthday, member.blood_type, h_pref.name AS hometown_pref, h_area.name AS hometown_area, l_pref.name AS location_pref, l_area.name AS location_area, member.introduction, member.default_photo, job.name AS job_name, member.job_details, member.location_level, member.age_level, member.birthday_level, member.hometown_level, member.job_level, member.job_details_level, member.diary_level, member.diary_host_id, member.diary_url FROM member LEFT JOIN job ON job.id=member.job_id LEFT JOIN prefecture h_pref ON h_pref.id=member.hometown_pref_id LEFT JOIN prefecture l_pref ON l_pref.id=member.location_pref_id LEFT JOIN area h_area ON h_area.id=member.hometown_area_id LEFT JOIN area l_area ON l_area.id=member.location_area_id WHERE member.id=? }); $sth->execute($member_id); my $row = $sth->fetchrow_hashref(); return $row; } sub show_main { my ($tpl, $friend_id, $level, $row, $level_2, $cache, $cache_friend, $last_access, $mn) = @_; our %cf_sex; our %cf_blood; my $key; ## Hobby if ($cache_friend->{"hobby:$friend_id"}) { $tpl->param("hobby", join(", ", @{ $cache_friend->{"hobby:$friend_id"} })); } ## Favorite if ($cache_friend->{"favorite:$friend_id"}) { my @favorite = ref($cache_friend->{"favorite:$friend_id"}) ? @{ $cache_friend->{"favorite:$friend_id"} } : (); my @loop; foreach (@favorite) { $_->{value} = make_clickable(tune_html($_->{value})); push @loop, $_; } $tpl->param("favorite_loop", \@loop); } my $name = "$row->{last_name} $row->{first_name}"; $tpl->param("full_name", tune_html($name)); $tpl->param("name", tune_html($row->{nickname})); $tpl->param("sex", $cf_sex{$row->{sex}}); $tpl->param("blood_type", $row->{blood_type} ? $cf_blood{$row->{blood_type}} : undef()); $tpl->param("level_2", $level_2); ## Photo level my $photo = PIC_DIR; $photo .= $row->{default_photo} ? make_photo_dir($friend_id) . $friend_id . "_" . $row->{default_photo} . ".jpg" : "/no_photo.gif"; if ($row->{default_photo}) { $tpl->param("show_photo_link", "show_photo.pl?id=$friend_id"); } $tpl->param("photo", $photo); ## Last login $tpl->param("last_login", get_time($last_access)); ## Age level if ($level <= $row->{age_level} && $row->{birthday}) { $tpl->param("age", get_age($row->{birthday})); } ## Birthday level if ($level <= $row->{birthday_level} && $row->{birthday}) { $tpl->param("birthday", short_japanese_date($row->{birthday})); ## Check if today is birthday my @birthday = split("-", $row->{birthday}); my @today = Today(); if (int($today[1]) == int($birthday[1]) && int($today[2]) == int($birthday[2])) { $tpl->param("birthday_link", "send_message.pl?id=$friend_id"); } } ## Job level if ($level <= $row->{job_level}) { $tpl->param("job", $row->{job_name}); } ## Job details level if ($level <= $row->{job_details_level}) { $tpl->param("job_details", make_clickable(tune_html($row->{job_details}))); } ## Location level if ($level <= $row->{location_level}) { $tpl->param("location", $row->{location_pref} . $row->{location_area}); } ## Hometown level if ($level <= $row->{hometown_level}) { $tpl->param("hometown", $row->{hometown_pref} . $row->{hometown_area}); } $tpl->param("introduction", make_clickable(tune_html($row->{introduction}))); ## Diary if ($level <= $row->{diary_level}) { ## Mixi diary if ($row->{diary_host_id} == 1) { ## mixi diary ## Get from memcached $key = "own_diary:" . $friend_id; if (ref($cache->{$key}) && @{ $cache->{$key} }) { $tpl->param("diary_new_loop", $cache->{$key}); } $tpl->param("list_diary_link", "list_diary.pl?id=$friend_id"); } else { ## Other diary my $dbh_rss = $mn->load_dbh(db_name => DB_DIARY_RSS); if ($dbh_rss) { my $sth2 = $dbh_rss->prepare(qq{ SELECT link, date, title FROM rss WHERE member_id=? ORDER BY date DESC, time DESC LIMIT 7 }); $sth2->execute($friend_id); my @loop = (); while (my $row2 = $sth2->fetchrow_hashref()) { my %loop; $loop{date} = short_japanese_date($row2->{date}); $loop{title} = tune_html(fold_line($row2->{title}, 24)); $loop{view_link} = $row2->{link}; $loop{new_window} = "target=diary"; push(@loop, \%loop); } $tpl->param("diary_new_loop", \@loop); $tpl->param("list_diary_link", tune_form($row->{diary_url})); $tpl->param("new_window", "target=diary"); } } } ## Album $key = "own_album:" . $friend_id; if (ref($cache->{$key}) && @{ $cache->{$key} }) { $tpl->param("album_new_loop", $cache->{$key}); } $tpl->param("list_album_link", "list_album.pl?id=$friend_id"); ## Review $key = "own_review:" . $friend_id; if (ref($cache->{$key}) && @{ $cache->{$key} }) { $tpl->param("review_new_loop", $cache->{$key}); } $tpl->param("list_review_link", "list_review.pl?id=$friend_id"); } sub show_intro { my ($cc, $tpl, $cache, $member_id) = @_; my $key = "intro:" . $member_id; if (!ref($cache->{$key}) || scalar(@{ $cache->{$key} }) < 1) { return undef(); } my @writer_id; foreach (@{ $cache->{$key} }) { ## Skip 'show_friend.pl?id=', and get only id ## this is 18 bytes my $writer_id = unpack("x18 A*", $_->{show_friend_link}); push(@writer_id, $writer_id); } my $value = $cc->get_photo(\@writer_id); ## Unpack photo:$member_id to $member_id my %photo = map { unpack("x6 A*", $_) => $value->{$_} } keys(%{ $value }); foreach (@{ $cache->{$key} }) { my $writer_id = unpack("x18 A*", $_->{show_friend_link}); if ($photo{$writer_id}) { $_->{photo} = PIC_DIR . make_photo_dir($writer_id). $writer_id . "_" . $photo{$writer_id} . "s.jpg"; } else { $_->{photo} = PIC_DIR . "/no_photo_small.gif"; } } $tpl->param("intro_loop", $cache->{$key}); $tpl->param("show_intro_link", "show_intro.pl?id=$member_id"); } sub log_spam { my ($dbh_admin, $member_id, $target_id, $count) = @_; if (!$dbh_admin) { return; } my $ip_address = $ENV{HTTP_X_FORWARDED_FOR} || $ENV{REMOTE_ADDR}; eval { $dbh_admin->do(q{ INSERT INTO show_friend_spam SET member_id=?, target_id=?, count=?, ip_address=? }, undef, ($member_id, $target_id, $count, $ip_address)); } } #------------------------------------------------------------------------------ # MAIN #------------------------------------------------------------------------------ my $mn = Boofy::Main::->new(); my $cgi = $mn->load_cgi(); my $dbh2 = $mn->load_dbh2(); my $lg = Boofy::Login::->new($cgi); ## Login $lg->set_block_reload(1); my $member_id = $lg->get_member_id(); if (!$member_id) { $lg->show_login($mn); exit; } my %v = $cgi->Vars(); $v{id} ||= $cgi->url_param("id"); ## Block if (!$v{id} || $v{id} =~ /\D/) { my $tpl = $mn->load_tpl("header.tmpl"); $mn->show_header(); $mn->show_alert(); print $tpl->output(); exit; } ## Cache my $cc = Boofy::Cache::->new(); my $friend_type = $cc->get_member($v{id}); my $is_premium = ($friend_type == 2) ? 1 : undef(); ## Block if no data if (!$friend_type) { my $tpl = $mn->load_tpl("header.tmpl"); $mn->show_header(); $mn->show_alert("ユーザは既に退会したか、存在しないユーザIDです。"); print $tpl->output(); exit; } ## Redirect if ourself if ($v{id} == $member_id) { print $cgi->redirect("home.pl"); exit; } ## Block from friend if ($cc->is_block($member_id, $v{id})){ print $cgi->redirect("access_error.pl"); exit; } my $count = $cc->add_limit($member_id, "show_friend", LIMIT_TIME); ## 最初の時と100番ずつ if ( $count == LIMIT_COUNT || ($count > LIMIT_COUNT && ($count % 100 == 0)) ) { my $dbh_admin = $mn->load_dbh(db_name => DB_ADMIN); log_spam($dbh_admin, $member_id, $v{id}, $count); } my $log = Boofy::Log::->new(member_id => $member_id); $log->log_access($v{id}); my $stamp = $cc->get_stamp($v{id}, 1); ## skip update my $last_access; if ($stamp) { my @stamp = split '_', $stamp; $stamp[1] ||= 0; $last_access = time - $stamp[1]; } my $cache = $cc->get_home_wrap($v{id}, premium => $is_premium); my $cache_link = $cc->get_link($member_id, $v{id}); my $cache_friend = $cc->get_multi_show_friend( $v{id}, last_access => $last_access ); my ($level, $middle) = split(":", $cache_link); my $key_link_count = "link_count:" . $v{id}; my $level_2 = $cache->{$key_link_count}; my @path; if ($level == 3) { push(@path, $middle, $v{id}); } elsif ($level == 2) { push(@path, $v{id}); } ## Display my $tpl = $mn->load_tpl("show_friend_main.tmpl"); $mn->show_header(cache => 1); $mn->show_banner($member_id); $mn->show_premium($friend_type); my $friend = get_data($dbh2, $v{id}); show_main($tpl, $v{id}, $level, $friend, $level_2, $cache, $cache_friend, $last_access, $mn); ## 友人でない場合、マイミクシィリンクを出す if ($level > 2) { $tpl->param("add_friend_link", "add_friend.pl?id=$v{id}"); } ## 友人かつ紹介文まだない場合、紹介文書くリンク出す else { my $mm = Boofy::Member->new(); if (!$mm->multi_has_intro($member_id, $v{id})) { $tpl->param("edit_intro_link", "edit_intro.pl?id=$v{id}&type=edit"); } } my $key_member_friend = "member_friend:" . $v{id}; my $member_friend = $cache->{$key_member_friend}; $tpl->param("friend_id", $v{id}); $tpl->param("friend_table", make_friend_table($cc, $v{id}, $member_friend, $level_2, $friend->{sex})); my $key_member_comm_count = "member_comm_count:" . $v{id}; my $member_comm_count = $cache->{$key_member_comm_count}; my $key_member_comm = "member_comm:" . $v{id}; my $member_comm = $cache->{$key_member_comm}; $tpl->param("comm_table", make_comm_table($cc, $v{id}, $member_comm, $member_comm_count)); $tpl->param("path", make_path($cc, $member_id, \@path)); show_intro($cc, $tpl, $cache, $v{id}); print $tpl->output();