IPv6 support #2
[stouyapi.git] / www / push-to-my-ouya.php
1 <?php
2 /**
3  * Click "push to my OUYA" in the browser, and the OUYA will install
4  * the game a few minutes later.
5  *
6  * Works without registration.
7  * We simply use the IP address as user identification.
8  * Pushed games are deleted after 24 hours.
9  * Maximal 30 games per IP to prevent flooding.
10  *
11  * @author Christian Weiske <cweiske@cweiske.de>
12  */
13 $dbFile     = __DIR__ . '/../data/push-to-my-ouya.sqlite3';
14 $apiGameDir = __DIR__ . '/api/v1/details-data/';
15
16 require_once __DIR__ . '/../src/push-to-my-ouya-helpers.php';
17
18 //support different ipv4-only domain
19 header('Access-Control-Allow-Origin: *');
20
21 if ($_SERVER['REQUEST_METHOD'] != 'POST') {
22     header('HTTP/1.0 400 Bad Request');
23     header('Content-type: text/plain');
24     echo 'POST only, please' . "\n";
25     exit(1);
26 }
27
28 if (!isset($_GET['game'])) {
29     header('HTTP/1.0 400 Bad Request');
30     header('Content-type: text/plain');
31     echo '"game" parameter missing' . "\n";
32     exit(1);
33 }
34
35 $game = $_GET['game'];
36 $cleanGame = preg_replace('#[^a-zA-Z0-9.]#', '', $game);
37 if ($game != $cleanGame) {
38     header('HTTP/1.0 400 Bad Request');
39     header('Content-type: text/plain');
40     echo 'Invalid game' . "\n";
41     exit(1);
42 }
43
44 $apiGameFile = $apiGameDir . $game . '.json';
45 if (!file_exists($apiGameFile)) {
46     header('HTTP/1.0 404 Not Found');
47     header('Content-type: text/plain');
48     echo 'Game does not exist' . "\n";
49     exit(1);
50 }
51
52 $ip = $_SERVER['REMOTE_ADDR'];
53 if ($ip == '') {
54     header('HTTP/1.0 400 Bad Request');
55     header('Content-type: text/plain');
56     echo 'Cannot detect your IP address' . "\n";
57     exit(1);
58 }
59 $ip = mapIp($ip);
60
61 try {
62     $db = new SQLite3($dbFile, SQLITE3_OPEN_READWRITE | SQLITE3_OPEN_CREATE);
63 } catch (Exception $e) {
64     header('HTTP/1.0 500 Internal server error');
65     header('Content-type: text/plain');
66     echo 'Cannot open database' . "\n";
67     echo $e->getMessage() . "\n";
68     exit(2);
69 }
70
71 $res = $db->querySingle(
72     'SELECT name FROM sqlite_master WHERE type = "table" AND name = "pushes"'
73 );
74 if ($res === null) {
75     //table does not exist yet
76     $db->exec(
77         <<<SQL
78         CREATE TABLE pushes (
79             id INTEGER PRIMARY KEY AUTOINCREMENT,
80             game TEXT NOT NULL,
81             ip TEXT NOT NULL,
82             created_at TEXT DEFAULT CURRENT_TIMESTAMP
83         )
84 SQL
85     );
86 }
87
88 //clean up old pushes
89 $db->exec(
90     'DELETE FROM pushes'
91     . ' WHERE created_at < \'' . gmdate('Y-m-d H:i:s', time() - 86400) . '\''
92 );
93
94 //check if this IP already pushed this game
95 $numThisGame = $db->querySingle(
96     'SELECT COUNT(*) FROM pushes'
97     . ' WHERE ip = \'' . SQLite3::escapeString($ip) . '\''
98     . ' AND game = \'' . SQLite3::escapeString($game) . '\''
99 );
100 if ($numThisGame >= 1) {
101     header('HTTP/1.0 400 Bad Request');
102     header('Content-type: text/plain');
103     echo 'Already pushed.' . "\n";
104     exit(1);
105 }
106
107 //check number of pushes for this IP
108 $numPushes = $db->querySingle(
109     'SELECT COUNT(*) FROM pushes'
110     . ' WHERE ip = \'' . SQLite3::escapeString($ip) . '\''
111 );
112 if ($numPushes >= 30) {
113     header('HTTP/1.0 400 Bad Request');
114     header('Content-type: text/plain');
115     echo 'Too many pushes. Come back tomorrow.' . "\n";
116     exit(1);
117 }
118
119 //store the push
120 $stmt = $db->prepare('INSERT INTO pushes (game, ip) VALUES(:game, :ip)');
121 $stmt->bindValue(':game', $game);
122 $stmt->bindValue(':ip', $ip);
123 $res = $stmt->execute();
124 if ($res === false) {
125     header('HTTP/1.0 500 Internal server error');
126     header('Content-type: text/plain');
127     echo 'Cannot store push' . "\n";
128     exit(3);
129 }
130 $res->finalize();
131
132 header('HTTP/1.0 200 OK');
133 header('Content-type: text/plain');
134 echo 'Push accepted' . "\n";
135 exit(3);
136 ?>