oekaki-test.php
1 <?php 2 3 // $file: $_FILES array entry for the .tgkr file 4 // returns true if the replay file is valid, 5 // false if the replay should be ignored, and errors out in all other cases. 6 function oekaki_validate_replay($file) { 7 $max_size = 6 * 1024 * 1024; 8 $max_data_size = 15 * 1024 * 1024; // uncompresed size 9 10 if ($file['error'] > 0) { 11 error(S_FAILEDUPLOAD); 12 } 13 14 if ($file['size'] === 0) { 15 error(S_NOREC); 16 } 17 18 if ($file['size'] > $max_size) { 19 error(S_TOOLARGE); 20 } 21 22 $tmp_file = $file['tmp_name']; 23 24 if (is_uploaded_file($tmp_file) !== true) { 25 error(S_FAILEDUPLOAD); 26 } 27 28 // Check the actual data now 29 30 $f = fopen($tmp_file, 'rb'); 31 32 $magic = fread($f, 4); 33 34 $decompressed_size = fread($f, 4); 35 36 fread($f, 4); // version numbers 37 38 $compressed_data = fread($f, $file['size'] - 12); 39 40 fclose($f); 41 42 if ($magic !== "\x54\x47\x4B\x01") { // TGK 0x01 43 error(S_NOREC); 44 } 45 46 $decompressed_size = (int)unpack('N', $decompressed_size)[1]; 47 48 if (!$decompressed_size || $decompressed_size <= 0) { 49 error(S_NOREC); 50 } 51 52 if ($decompressed_size > $max_data_size) { 53 return false; 54 } 55 56 if (!$compressed_data) { 57 error(S_NOREC); 58 } 59 60 $data = gzinflate($compressed_data, $decompressed_size); 61 62 if ($data === false) { 63 error(S_NOREC); 64 } 65 66 $meta_size = (int)unpack('n', $data)[1]; 67 68 if (!$meta_size) { 69 return false; 70 } 71 72 // tool count (byte), tool entry size (byte) 73 $tool_meta = unpack('C2', substr($data, $meta_size, 2)); 74 75 if (!$tool_meta || !(int)$tool_meta[1] || !(int)$tool_meta[2]) { 76 return false; 77 } 78 79 $events_pos = $meta_size + ((int)$tool_meta[1]) * ((int)$tool_meta[2]) + 2; 80 81 $event_count = (int)unpack('N', substr($data, $events_pos, 4))[1]; 82 83 if (!$event_count || $event_count > 8640000) { 84 return false; 85 } 86 87 $prelude_type = unpack('C', substr($data, $events_pos + 4, 1)); 88 89 if ($prelude_type === false || (int)$prelude_type[1] !== 0) { 90 return false; 91 } 92 93 $conclusion_type = unpack('C', substr($data, -5, 1)); 94 95 if ($conclusion_type === false || (int)$conclusion_type[1] !== 255) { 96 return false; 97 } 98 99 return true; 100 } 101 102 function oekaki_get_valid_src_pid($src_pid, $board, $thread_id) { 103 $src_pid = (int)$src_pid; 104 105 if ($src_pid < 1) { 106 return null; 107 } 108 109 $thread_id = (int)$thread_id; 110 111 if ($thread_id < 1) { 112 return null; 113 } 114 115 $sql = "SELECT no FROM `%s` WHERE no = $src_pid AND (resto = $thread_id OR resto = 0) AND tim != 0 LIMIT 1"; 116 117 $res = mysql_board_call($sql, $board); 118 119 if (!$res || mysql_num_rows($res) !== 1) { 120 return null; 121 } 122 123 return $src_pid; 124 } 125 126 function oekaki_format_info($time, $replay_tim, $src_pid) { 127 $time = (int)$time; 128 129 if ($time < 1 || $time > 5184000) { // 60 days 130 return ''; 131 } 132 133 if ($time < 60) { 134 $time_str = $time . 's'; 135 } 136 else if ($time < 3600) { 137 $time_str = round($time / 60) . 'm'; 138 } 139 else { 140 $time_str = (int)($time / 3600) . 'h ' . round(($time % 3600) / 60) . 'm'; 141 } 142 143 if ($replay_tim && !$src_pid) { 144 $replay_tim = (int)$replay_tim; 145 $replay_link = ", Replay: <a href=\"javascript:oeReplay($replay_tim);\">View</a>"; 146 } 147 else { 148 $replay_link = ''; 149 } 150 151 if ($src_pid) { 152 $src_pid = (int)$src_pid; 153 $src_link = ", Source: >>$src_pid"; 154 } 155 else { 156 $src_link = ''; 157 } 158 159 return "<br><br><small><b>Oekaki Post</b> (Time: $time_str" . $replay_link . $src_link . ")</small>"; 160 }