fd39043234ac4f37d876b86a0f854eeb87215c3c
[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 if (strpos($ip, ':') !== false) {
60     header('HTTP/1.0 400 Bad Request');
61     header('Content-type: text/plain');
62     echo 'Sorry, IPv6 is not supported' . "\n";
63     echo 'This here only works if the OUYA and your PC have the same IP address,'
64         . "\n";
65     echo 'and this is definitely not the case when using IPv6' . "\n";
66     exit(1);
67 }
68 $ip = mapIp($ip);
69
70 try {
71     $db = new SQLite3($dbFile, SQLITE3_OPEN_READWRITE | SQLITE3_OPEN_CREATE);
72 } catch (Exception $e) {
73     header('HTTP/1.0 500 Internal server error');
74     header('Content-type: text/plain');
75     echo 'Cannot open database' . "\n";
76     echo $e->getMessage() . "\n";
77     exit(2);
78 }
79
80 $res = $db->querySingle(
81     'SELECT name FROM sqlite_master WHERE type = "table" AND name = "pushes"'
82 );
83 if ($res === null) {
84     //table does not exist yet
85     $db->exec(
86         <<<SQL
87         CREATE TABLE pushes (
88             id INTEGER PRIMARY KEY AUTOINCREMENT,
89             game TEXT NOT NULL,
90             ip TEXT NOT NULL,
91             created_at TEXT DEFAULT CURRENT_TIMESTAMP
92         )
93 SQL
94     );
95 }
96
97 //clean up old pushes
98 $db->exec(
99     'DELETE FROM pushes'
100     . ' WHERE created_at < \'' . gmdate('Y-m-d H:i:s', time() - 86400) . '\''
101 );
102
103 //check if this IP already pushed this game
104 $numThisGame = $db->querySingle(
105     'SELECT COUNT(*) FROM pushes'
106     . ' WHERE ip = \'' . SQLite3::escapeString($ip) . '\''
107     . ' AND game = \'' . SQLite3::escapeString($game) . '\''
108 );
109 if ($numThisGame >= 1) {
110     header('HTTP/1.0 400 Bad Request');
111     header('Content-type: text/plain');
112     echo 'Already pushed.' . "\n";
113     exit(1);
114 }
115
116 //check number of pushes for this IP
117 $numPushes = $db->querySingle(
118     'SELECT COUNT(*) FROM pushes'
119     . ' WHERE ip = \'' . SQLite3::escapeString($ip) . '\''
120 );
121 if ($numPushes >= 30) {
122     header('HTTP/1.0 400 Bad Request');
123     header('Content-type: text/plain');
124     echo 'Too many pushes. Come back tomorrow.' . "\n";
125     exit(1);
126 }
127
128 //store the push
129 $stmt = $db->prepare('INSERT INTO pushes (game, ip) VALUES(:game, :ip)');
130 $stmt->bindValue(':game', $game);
131 $stmt->bindValue(':ip', $ip);
132 $res = $stmt->execute();
133 if ($res === false) {
134     header('HTTP/1.0 500 Internal server error');
135     header('Content-type: text/plain');
136     echo 'Cannot store push' . "\n";
137     exit(3);
138 }
139 $res->finalize();
140
141 header('HTTP/1.0 200 OK');
142 header('Content-type: text/plain');
143 echo 'Push accepted' . "\n";
144 exit(3);
145 ?>