<?php  // mod/assignment/submissions.phpを参考にして

    require_once("../../config.php");

    $id   = optional_param('id', 0, PARAM_INT);          // Course module ID
    $a    = optional_param('a', 0, PARAM_INT);           // Assignment ID
    $mode = optional_param('mode', 'all', PARAM_ALPHA);  // What mode are we in?

    if ($id) {
        if (! $cm = get_coursemodule_from_id('assignment', $id)) {
            error("Course Module ID was incorrect");
        }

        if (! $assignment = fs_get_record("assignment", "id", $cm->instance)) {
            error("assignment ID was incorrect");
        }

        if (! $course = fs_get_record("course", "id", $assignment->course)) {
            error("Course is misconfigured");
        }
    } else {
        if (!$assignment = fs_get_record("assignment", "id", $a)) {
            error("Course module is incorrect");
        }
        if (! $course = fs_get_record("course", "id", $assignment->course)) {
            error("Course is misconfigured");
        }
        if (! $cm = get_coursemodule_from_instance("assignment", $assignment->id, $course->id)) {
            error("Course Module ID was incorrect");
        }
    }

    require_login($course->id, false, $cm);

    require_capability('mod/assignment:grade', get_context_instance(CONTEXT_MODULE, $cm->id));

// (Shirai098): 提出された課題の明白な手抜きを見抜く機能 (2008/10/28)
// レベル１：内容が完全に一致する提出物が複数存在する 
// レベル２：内容が酷似した提出物が複数存在する 
// レベル３：内容の一部が類似した提出物が複数存在する 
// レベル４：内容が外部情報からのコピー＆ペーストである可能性のある提出物が存在する 
// 課題の提出物の情報を取得する
require_once($CFG->libdir.'/filelib.php');

// 二つのファイルをバイナリモードで比較する
function file_compare($source, $target)
{
    if (($fp1 = fs_fopen($source, 'rb')) == false) return false;
    if (($fp2 = fs_fopen($target, 'rb')) == false) return false;
    $flag = true;
    while (!feof($fp1) && !feof($fp2)) {
        $data1 = fread($fp1, 1024);
        $data2 = fread($fp2, 1024);
        if ($data1 !== $data2) {
            fclose($fp1);
            fclose($fp2);
            return false;
        }
    }
    if ((!feof($fp1)) || (!feof($fp2))) return false;
    return true;
}

// デバッグ用出力を有効にする場合はコメント記号を外す
// define('bhc_debug', true);

function get_uploaded_assignment_for_boneheadcheck($courseid, $id)
{
    global $CFG;

    // ファイルリストの取得
    $uploadeddata = array();
    $uploaded_cnt = 0;
    $filearea = $CFG->dataroot.'/'.$courseid.'/moddata/assignment/'.$id;
    $cdir = opendir($filearea);
    while (($uid = fs_readdir($cdir)) !== false) {
        if (($uid == '.') || ($uid == '..')) continue;
        $udir = opendir($filearea.'/'.$uid);
        $list = array();
        while (($ufile = fs_readdir($udir)) !== false) {
            if (($ufile == '.') || ($ufile == '..')) continue;
            $uploaded_cnt++;
            $info['uid']      = $uid;
            if ($user = fs_get_record('user', 'id', $info['uid'])) {
                $info['fullname'] = fullname($user);
            } else {
                $info['fullname'] = $info['uid'];
            }
            $info['filename'] = $ufile;
            $info['fullpath'] = $filearea.'/'.$uid.'/'.$ufile;
            $info['filesize'] = fs_filesize($info['fullpath']);
            $info['ffurl']    = get_file_url($courseid.'/moddata/assignment/'.$id.'/'.$uid.'/'.$ufile, null, 'coursefile');
            $info['ctime']    = fs_filectime($info['fullpath']);
            $info['mtime']    = fs_filemtime($info['fullpath']);
            $list[] = $info;
        }
        closedir($udir);
        if (!empty($list)) $uploadeddata[$uid] = $list;
    }
    closedir($cdir);

    // 確認用出力
    if (defined('bhc_debug')) {
        $cnt = 0;
        foreach ($uploadeddata as $uid => $list) {
            echo 'User: '.$uid.'<br />';
            foreach ($list as $info) {
                $cnt++;
                echo '--> '.$info['filename'].'<br />';
                echo ' '.$info['fullpath'].'<br />';
                echo ' '.$info['filesize'].'<br />';
                echo ' '.$info['ffurl'].'<br />';
            }
        }
        echo '合計:'.$cnt.'ファイル<br />';
    }
    return $uploadeddata;
}

function bonehead_check_level1($uploadeddata)
{
    // チェック開始
    // １次チェック（ファイルサイズで抽出）
    $uploaded_cnt = 0;
    $suspects1 = array();
    foreach ($uploadeddata as $uid => $list) {
        foreach ($list as $info) {
            $uploaded_cnt++;
            $suspects1[$info['filesize']][] = $info;
        }
    }
    foreach ($suspects1 as $fsize => $suspects) {
        if (count($suspects) <= 1) unset($suspects1[$fsize]);
    }

    // 確認用出力
    if (defined('bhc_debug')) {
        $cnt = 0;
        foreach ($suspects1 as $fsize => $suspects) {
           echo '<br />ファイルサイズ: '.$fsize.'<br />';
            foreach ($suspects as $info) {
                $cnt++;
                echo $info['uid'].'の'.$info['filename'].'<br />';
                echo '-->'.$info['fullpath'].'<br />';
                echo '-->'.$info['filesize'].'<br />';
                echo '-->'.$info['ffurl'].'<br />';
            }
        }
        echo '合計:'.$cnt.'ファイル<br /><br />';
    }

    // ２次チェック（SHA1ハッシュ値を調べて抽出）
    $suspects2 = array();
    foreach ($suspects1 as $fsize => $suspects) {
        foreach ($suspects as $info) {
            if (($sha1 = fs_sha1_file($info['fullpath'])) == false) {
                error('ファイルが見付かりませんでした');
                die;
            }
            $info['sha1'] = $sha1;
            $suspects2[$fsize][$sha1][] = $info;
        }
        foreach ($suspects2[$fsize] as $sha1 => $list) {
            if (count($list) <= 1) unset($suspects2[$fsize][$sha1]);
        }
    }

    // ３次チェック（厳密なチェック）：(1)とその他の比較
    $suspects3 = array();
    foreach ($suspects2 as $fsize => $suspects) {
        foreach ($suspects as $sha1 => $list) {
            $source = '';
            foreach ($list as $info) {
                if ($source === '') {
                    $source = $info['fullpath'];
                    $info['compare'] = '-';
                } else {
                    if (file_compare($source, $info['fullpath'])) {
                        $info['compare'] = 'Yes';
                    } else {
                        $info['compare'] = 'No';
                    }
                }
                $suspects3[$fsize][$sha1][] = $info;
            }
        }
    }

    $total_cnt = 0;
    echo '<b>検査結果表示</b><br />（完全に一致するファイル）<br />';
    foreach ($suspects3 as $fsize => $suspects) {
        foreach ($suspects as $sha1 => $list) {
            $cnt = 0;
            echo '<br />';
            echo '<table border="2" cellpadding="4">';
            echo '<caption>ファイルサイズ: '.$fsize.'byte</caption>';
            echo '<tr bgcolor="ffcc00"><th>No.</th><th>ユーザ名</th><th>ファイル名</th><th>作成日時</th><th>更新日時</th>';
            echo '<th>(1)と厳密に等しいか？</th>';
            echo '</tr>';
            foreach ($list as $info) {
                $cnt++;
                $total_cnt++;
                echo '<tr align="center">';
                echo "<td>($cnt)</td><td>".$info['fullname'].'</td><td>';
                echo '<a href="'.$info['ffurl'].'" target="_blank">'.$info['filename'].'</a>';
                echo '</td>';
                echo '<td>'.date('Y/m/d H:i:s', $info['ctime']).'</td>';
                echo '<td>'.date('Y/m/d H:i:s', $info['mtime']).'</td>';
                echo '<td>'.$info['compare'].'</td>';
                echo '</tr>';
            }
            echo '</table>';
            echo '(SHA1ハッシュ値：'.$info['sha1'].')<br />';
        }
    }
    echo "<br /><b>合計 $uploaded_cnt ファイル中の $total_cnt ファイル</b><br />";
    output_CloseWindowButton(true);
    echo '<hr />';

    // 仲良しの傾向が強いと思われるグループを調べる
    $friend = array();
    foreach ($suspects2 as $fsize => $suspects) {
        foreach ($suspects as $sha1 => $list) {
            $buddy = array();
            foreach ($list as $info) {
                $buddy[$info['uid']] = $info['fullname'];
            }
            $friend[] = $buddy;
        }
    }

    echo '<br /><b>仲良しグループ候補</b><br />';
    $cnt = 1;
    foreach ($friend as $buddy) {
        echo "グループ$cnt<br />";
        foreach ($buddy as $uid => $member) {
            echo "$uid,$member<br />";
        }
        echo '<br />';
        $cnt++;
    }
    output_CloseWindowButton(true);
    return $friend;
}

    $uploadeddata = get_uploaded_assignment_for_boneheadcheck($course->id, $assignment->id);
    bonehead_check_level1($uploadeddata);

?>
