OSDN Git Service

[modify]includeをrequire_onceに変更
[hengband/web.git] / register_score.php
1 <?php
2 //ini_set('display_errors', 'On');
3
4 ini_set('log_errors', 'On');
5 ini_set('error_log', 'errors/'.pathinfo(__FILE__, PATHINFO_FILENAME).'.log');
6
7 require_once "db_common.inc";
8 require_once "dump_file.inc";
9
10 // 登録が成功しない場合、HTTPレスポンスコード 400 Bad Request を返す
11 http_response_code(400);
12
13 /**
14  * 送信されてきたスコアのマルチバイト文字エンコーディングを取得する
15  *
16  * Content-Typeヘッダからエンコーディングを取得する。
17  * 同時に変愚蛮怒が送ってきているはずのContent-Typeヘッダと一致しているかチェックする。
18  *
19  * @return string|false 送られてきたスコアの、PHPのマルチバイト文字処理における文字エンコーディングを表す文字列
20  *                      取得できなかった場合はFALSE
21  */
22 function get_mb_encoding(){
23     $content_type = filter_input(INPUT_SERVER, 'CONTENT_TYPE');
24     if ($content_type == NULL) return FALSE;
25
26     $s = explode(';', $content_type);
27
28     if (count($s) != 2 ||
29         $s[0] !== "text/plain" ||
30         strpos(trim($s[1]), "charset=") !== 0) return FALSE;
31
32     $c = explode('=', $s[1]);
33
34     switch (strtolower(trim($c[1]))) {
35     case "euc-jp":
36         return "EUC-JP";
37     case "shift_jis":
38         return "SJIS";
39     case "utf-8":
40         return "UTF-8";
41     default:
42         return FALSE;
43     }
44 }
45
46
47 /**
48  * 受信したスコアデータを分割する
49  *
50  * 受信したスコアデータを、キャラクタ情報部分・キャラクタダンプ部分・スクリーンショット部分の3つに分割する
51  * それぞれの部分は1行毎の文字列の配列とする
52  *
53  * @param string $recv_contents 受信したスコアデータ
54  * @return array|false キャラクタ情報・キャラクタダンプ・スクリーンショットのそれぞれの部分のデータの配列
55  *                     分割できなかった場合はFALSE
56  */
57 function split_recv_contents($recv_contents)
58 {
59     $recv_lines = explode("\n", $recv_contents);
60
61     $dump_info_end_line = array_search('-----charcter dump-----', $recv_lines);
62     $dump_txt_end_line = array_search('-----screen shot-----', $recv_lines);
63
64     if ($dump_info_end_line === FALSE) return FALSE;
65
66     $info_lines = array_slice($recv_lines, 0, $dump_info_end_line);
67     $dump_lines = array_slice(
68         $recv_lines,
69         $dump_info_end_line + 1,
70         $dump_txt_end_line ? $dump_txt_end_line - $dump_info_end_line - 1: NULL
71     );
72     $screen_lines = $dump_txt_end_line ?
73                   array_slice(
74                       $recv_lines,
75                       $dump_txt_end_line + 1,
76                       NULL
77                   ) : FALSE;
78
79     return [$info_lines, $dump_lines, $screen_lines];
80 }
81
82
83 /**
84  * キャラクタ情報をパースする
85  *
86  * スコアデータのキャラクタ情報をパースし、情報名=>値の連想配列を得る
87  * ex) name: Hoge を ['name' => 'Hoge'] のようにする
88  *
89  * @param string $info_liens 受信したスコアデータのキャラクタ情報(1要素1行の配列)
90  * @return array|false キャラクタ情報・キャラクタダンプ・スクリーンショットのそれぞれの部分のデータの配列
91  *                     分割できなかった場合はFALSE
92  */
93 function parse_character_info($info_lines)
94 {
95     $info = [];
96     foreach ($info_lines as $l) {
97         $splitpos = strpos($l, ':');
98         if ($splitpos !== FALSE) {
99             $key = substr($l, 0, $splitpos);
100             $val = substr($l, $splitpos + 1);
101             $info[$key] = trim($val);
102         }
103     }
104
105     return $info;
106 }
107
108
109 /**
110  * キャラクタ情報からDBへのスコア登録用パラメータを生成する
111  *
112  * @param array $info キャラクタ情報の連想配列
113  * @return array DBへのスコア登録用パラメータ('character_info'と'realm_info'の連想配列)
114  */
115 function create_db_insert_score_data($info)
116 {
117     $character_info_array = [
118         'version' => $info['version'],
119         'score' => $info['score'],
120         'name' => $info['name'],
121         'race' => $info['race'],
122         'class' => $info['class'],
123         'personality' => $info['seikaku'],
124         'sex' => $info['sex'],
125         'level' => $info['level'],
126         'depth' => $info['depth'],
127         'maxlv' => $info['maxlv'],
128         'maxdp' => $info['maxdp'],
129         'au' => $info['au'],
130         'turns' => $info['turns'],
131         'winner' => $info['killer'] == 'ripe' || $info['killer'] == 'Seppuku',
132         'killer' => $info['killer'],
133     ];
134
135     $realm_info_array = array_values(
136         array_filter(
137             [$info['realm1'], $info['realm2']],
138             function($v) {return $v !== '魔法なし';})
139     );
140
141     return [
142         'character_info' => $character_info_array,
143         'realm_info' => $realm_info_array,
144     ];
145 }
146
147
148 $recv_encoding = get_mb_encoding();
149 if ($recv_encoding === FALSE) {
150     exit;
151 }
152
153 $recv_contents = file_get_contents('php://input');
154 if (strlen($recv_contents) !== filter_input(INPUT_SERVER, 'CONTENT_LENGTH', FILTER_VALIDATE_INT)) {
155     exit;
156 }
157
158 $recv_contents = mb_convert_encoding($recv_contents, "UTF-8", $recv_encoding);
159
160 $split_contents = split_recv_contents($recv_contents);
161 if ($split_contents === FALSE) {
162     exit;
163 }
164
165 $char_info = parse_character_info($split_contents[0]);
166
167 $db = new ScoreDB();
168 $score_id = $db->register_new_score(create_db_insert_score_data($char_info));
169
170 if ($score_id === FALSE) {
171     exit;
172 }
173
174 $dumpfile = new DumpFile($score_id);
175 $dumpfile->save('dumps', 'txt', $split_contents[1]);
176 $dumpfile->save('screens', 'html', $split_contents[2]);
177
178 // 登録成功、HTTPレスポンスコード 200 OK を返す
179 http_response_code(200);