OSDN Git Service

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