instance)) { error("assignment ID was incorrect"); } if (! $course = get_record("course", "id", $assignment->course)) { error("Course is misconfigured"); } } else { if (!$assignment = get_record("assignment", "id", $a)) { error("Course module is incorrect"); } if (! $course = 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) // レベル1:内容が完全に一致する提出物が複数存在する // レベル2:内容が酷似した提出物が複数存在する // レベル3:内容の一部が類似した提出物が複数存在する // レベル4:内容が外部情報からのコピー&ペーストである可能性のある提出物が存在する // 課題の提出物の情報を取得する require_once($CFG->libdir.'/filelib.php'); // 二つのファイルをバイナリモードで比較する function file_compare($source, $target) { if (($fp1 = fopen($source, 'rb')) == false) return false; if (($fp2 = 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, $level) { global $CFG; // ファイルリストの取得 $uploadeddata = array(); $uploaded_cnt = 0; $filearea = $CFG->dataroot.'/'.$courseid.'/moddata/assignment/'.$id; $cdir = opendir($filearea); while (($uid = readdir($cdir)) !== false) { if (($uid == '.') || ($uid == '..')) continue; $udir = opendir($filearea.'/'.$uid); $list = array(); while (($ufile = readdir($udir)) !== false) { if (($ufile == '.') || ($ufile == '..')) continue; $uploaded_cnt++; $info['uid'] = $uid; if ($user = 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'] = filesize($info['fullpath']); $info['ffurl'] = get_file_url($courseid.'/moddata/assignment/'.$id.'/'.$uid.'/'.$ufile, null, 'coursefile'); $info['ctime'] = filectime($info['fullpath']); $info['mtime'] = filemtime($info['fullpath']); $list[] = $info; } if (!empty($list)) $uploadeddata[$uid] = $list; } // 確認用出力 if (defined('bhc_debug')) { $cnt = 0; foreach ($uploadeddata as $uid => $list) { echo 'User: '.$uid.'
'; foreach ($list as $info) { $cnt++; echo '--> '.$info['filename'].'
'; echo ' '.$info['fullpath'].'
'; echo ' '.$info['filesize'].'
'; echo ' '.$info['ffurl'].'
'; } } echo '合計:'.$cnt.'ファイル
'; } // チェック開始 // 1次チェック(ファイルサイズで抽出) $suspects1 = array(); foreach ($uploadeddata as $uid => $list) { foreach ($list as $info) { $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 '
ファイルサイズ: '.$fsize.'
'; foreach ($suspects as $info) { $cnt++; echo $info['uid'].'の'.$info['filename'].'
'; echo '-->'.$info['fullpath'].'
'; echo '-->'.$info['filesize'].'
'; echo '-->'.$info['ffurl'].'
'; } } echo '合計:'.$cnt.'ファイル

'; } // 2次チェック(SHA1ハッシュ値を調べて抽出) $suspects2 = array(); foreach ($suspects1 as $fsize => $suspects) { foreach ($suspects as $info) { if (($sha1 = 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]); } } // 3次チェック(厳密なチェック):(1)とその他の比較 $suspects3 = array(); foreach ($suspects2 as $fsize => $suspects) { $source = ''; foreach ($suspects as $sha1 => $list) { 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 '検査結果表示
完全に一致するファイル)
'; foreach ($suspects3 as $fsize => $suspects) { echo '
'; echo ''; echo ''; echo ''; echo ''; echo ''; foreach ($suspects as $sha1 => $list) { $cnt = 0; foreach ($list as $info) { $cnt++; $total_cnt++; echo ''; echo "'; echo ''; echo ''; echo ''; echo ''; } echo '
ファイルサイズ: '.$fsize.'byte
No.ユーザ名ファイル名作成日時更新日時(1)と厳密に等しいか?
($cnt)".$info['fullname'].''; echo ''.$info['filename'].''; echo ''.date('Y/m/d H:i:s', $info['ctime']).''.date('Y/m/d H:i:s', $info['mtime']).''.$info['compare'].'
'; echo '(SHA1ハッシュ値:'.$info['sha1'].')
'; } } echo "
合計 $uploaded_cnt ファイル中の $total_cnt ファイル
"; echo '
'; // 仲良しの傾向が強いと思われるグループを調べる $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 '
仲良しグループ候補
'; $cnt = 1; foreach ($friend as $buddy) { echo "グループ$cnt
"; foreach ($buddy as $uid => $member) { echo "$uid,$member
"; } echo '
'; $cnt++; } return $friend; } get_uploaded_assignment_for_boneheadcheck($course->id, $assignment->id, 1); ?>