diff --git a/Models/UserFingerprint.php b/Models/UserFingerprint.php index 7870fce..de080aa 100644 --- a/Models/UserFingerprint.php +++ b/Models/UserFingerprint.php @@ -253,4 +253,59 @@ public function deleteRotated($max_log_count = 100000, $delete_ratio = 0.01) $delete_id_quoted = DB::quote($delete_id); return DB::delete($this->_table, "`id` <= $delete_id_quoted"); } + + public function findUserByFingerprintOrSid($fingerprint_array, $sid_array) + { + if (!$fingerprint_array || !$fingerprint_array) { + return []; + } + $fingerprint_in = implode(', ', DB::quote($fingerprint_array)); + $sid_in = implode(', ', DB::quote($sid_array)); + return DB::fetch_all("SELECT DISTINCT(`uid`), `username` FROM `{$this->prefixed_table}` WHERE `fingerprint` IN ({$fingerprint_in}) OR `sid` IN ({$sid_in})"); + } + + public function findRelatedUser($uid) + { + $records = DB::fetch_all("SELECT `fingerprint`, `sid` FROM `{$this->prefixed_table}` WHERE `uid` = {$uid}"); + $fingerprint_array = []; + $sid_array = []; + foreach ($records as $row) { + $fingerprint_array[] = $row['fingerprint']; + $sid_array[] = $row['sid']; + } + $related_users = $this->findUserByFingerprintOrSid($fingerprint_array, $sid_array); + return [ + 'fingerprint_array' => $fingerprint_array, + 'sid_array' => $sid_array, + 'related_users' => $related_users, + ]; + } + + public function findMultiAccountUidArray($start = 0, $limit = 20) + { + $fingerprint_array = []; + $sid_array = []; + $records = DB::fetch_all("SELECT `fingerprint`, COUNT(DISTINCT(`uid`)) AS `count` FROM `pre_user_fingerprint_log` GROUP BY `fingerprint` ORDER BY `count` DESC LIMIT {$start}, {$limit}");; + foreach ($records as $row) { + if ((int)$row['count'] > 1) { + $fingerprint_array[] = $row['fingerprint']; + } + } + $records = DB::fetch_all("SELECT `sid`, COUNT(DISTINCT(`uid`)) AS `count` FROM `pre_user_fingerprint_log` GROUP BY `sid` ORDER BY `count` DESC LIMIT {$start}, {$limit}"); + foreach ($records as $row) { + if ((int)$row['count'] > 1) { + $sid_array[] = $row['sid']; + } + } + return $this->findUserByFingerprintOrSid($fingerprint_array, $sid_array); + } + + public function findUserByUid($uid_array) + { + if (!$uid_array) { + return []; + } + $in = implode(', ', DB::quote($uid_array)); + return DB::fetch_all("SELECT DISTINCT(`uid`), `username` FROM `{$this->prefixed_table}` WHERE `uid` IN ({$in})"); + } } diff --git a/admin_chart.inc.php b/admin_chart.inc.php new file mode 100644 index 0000000..d03efa8 --- /dev/null +++ b/admin_chart.inc.php @@ -0,0 +1,131 @@ + ['name' => '1' . _(' Relation Account')], + 1 => ['name' => '2' . _(' Relation Account')], + 2 => ['name' => '3' . _(' Relation Account')], + 3 => ['name' => _('Fingerprint')], + 4 => ['name' => _('Session')], +]; +$nodes = []; +$links = []; +$index = 0; +$all_uid_index = []; +$all_fingerprint_index = []; +$all_sid_index = []; + + +$uid = (int)$_GET['uid']; +if ($uid) { + $uid_to_search = [$uid]; +} else { + $records = $table->findMultiAccountUidArray(); + foreach ($records as $row) { + $uid_to_search[] = (int)$row['uid']; + } +} + +$records = $table->findUserByUid($uid_to_search); +$uid_to_search_2 = []; +foreach ($records as $row) { + $row_uid = (int)$row['uid']; + if (!isset($all_uid_index[$row_uid])) { + $nodes[$index] = [ + 'name' => $row['username'], + 'category' => 0, + 'symbolSize' => 40, + ]; + $all_uid_index[$row_uid] = $index; + ++$index; + $uid_to_search_2[] = $row_uid; + } +} +$uid_to_search = $uid_to_search_2; + +for ($level = 1; $level <= 2; ++$level) { + $uid_to_search_2 = []; + foreach ($uid_to_search as $uid) { + $records = $table->findRelatedUser($uid); + + foreach ($records['fingerprint_array'] as $fingerprint) { + if (!isset($all_fingerprint_index[$fingerprint])) { + $nodes[$index] = [ + 'name' => $fingerprint, + 'category' => 3, + 'symbolSize' => 10, + ]; + $all_fingerprint_index[$fingerprint] = $index; + ++$index; + } + $links[] = [ + 'source' => $all_uid_index[$uid], + 'target' => $all_fingerprint_index[$fingerprint], + ]; + } + + foreach ($records['sid_array'] as $sid) { + if (!isset($all_sid_index[$sid])) { + $nodes[$index] = [ + 'name' => $sid, + 'category' => 4, + 'symbolSize' => 10, + ]; + $all_sid_index[$sid] = $index; + ++$index; + } + $links[] = [ + 'source' => $all_uid_index[$uid], + 'target' => $all_sid_index[$sid], + ]; + } + + foreach ($records['related_users'] as $row) { + $row_uid = (int)$row['uid']; + if (!isset($all_uid_index[$row_uid])) { + $nodes[$index] = [ + 'name' => $row['username'], + 'category' => $level, + 'symbolSize' => (4 - $level) * 10, + ]; + $all_uid_index[$row_uid] = $index; + ++$index; + $uid_to_search_2[] = $row_uid; + } + $links[] = [ + 'source' => $all_uid_index[$uid], + 'target' => $all_uid_index[$row_uid], + ]; + } + } + $uid_to_search = $uid_to_search_2; +} + +$data = [ + 'title' => [ + 'text' => _('User Account Relation Visualization') + ], + 'categories' => $categories, + 'nodes' => $nodes, + 'links' => $links, +]; + + +echo ''; + +echo <<<'EOD' +