sync.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. <?php
  2. // Gasteizko Margolariak API v1 //
  3. //List of available data formatting
  4. define('FOR_JSON', 'json');
  5. //Default info format
  6. define('DEF_FORMAT', FOR_JSON);
  7. //Database section identifiers
  8. define('SEC_ALL', 'all');
  9. define('SEC_BLOG', 'blog');
  10. define('SEC_ACTIVITIES', 'activities');
  11. define('SEC_GALLERY', 'gallery');
  12. define('SEC_LABLANCA', 'lablanca');
  13. //Posible actions
  14. define('ACTION_SYNC', 'sync');
  15. define('ACTION_VERSION', 'version');
  16. //$_GET valid parameters
  17. define('GET_CLIENT', 'client');
  18. define('GET_USER', 'user');
  19. define('GET_ACTION', 'action');
  20. define('GET_SECTION', 'section');
  21. define('GET_VERSION', 'version');
  22. define('GET_FOREGROUND', 'foreground');
  23. define('GET_FORMAT', 'json');
  24. //Error messages
  25. define('ERR_ACTION', '-ACTION:');
  26. define('ERR_SECTION', '-SECTION:');
  27. define('ERR_VERSION', '-VERSION:');
  28. define('ERR_FOREGROUND', '-FOREGROUND:');
  29. define('ERR_FORMAT', '-FORMAT:');
  30. /****************************************************
  31. * This function is called from almost everywhere at *
  32. * the beggining of the page. It initializes the *
  33. * session variables, connect to the db, enabling *
  34. * the variable $con for futher use everywhere in *
  35. * the php code, and populates the arrays $user *
  36. * and $permission, with info about the user. *
  37. * *
  38. * @return: (db connection): The connection handler. *
  39. ****************************************************/
  40. function startdb(){
  41. //Include the db configuration file. It's somehow like this
  42. /*
  43. <?php
  44. $host = 'XXXX';
  45. $db_name = 'XXXX';
  46. $username_ro = 'XXXX';
  47. $username_rw = 'XXXX';
  48. $pass_ro = 'XXXX';
  49. $pass_rw = 'XXXX';
  50. ?>
  51. */
  52. include('../../.htpasswd');
  53. //Connect to to database
  54. $con = mysqli_connect($host, $username_rw, $pass_rw, $db_name);
  55. //Set encoding options
  56. mysqli_set_charset($con, 'utf-8');
  57. header('Content-Type: text/html; charset=utf8');
  58. mysqli_query($con, 'SET NAMES utf8;');
  59. //Return the db connection
  60. return $con;
  61. }
  62. /****************************************************
  63. * Echoes the version of one or more of the sections *
  64. * of the database, or the global section. *
  65. * *
  66. * @params: *
  67. * con: (MySQL server connection) RO mode enough. *
  68. * section: (string): 'blog', 'activities', *
  69. * 'gallery', 'lablanca', 'global'. None *
  70. * to get them all. *
  71. ****************************************************/
  72. function get_version($con, $section = SEC_ALL){
  73. if ($section == SEC_ALL){
  74. $q = mysqli_query($con, "SELECT SUM(version) AS version FROM version;");
  75. }
  76. else{
  77. $q = mysqli_query($con, "SELECT version FROM version WHERE section = '$section';");
  78. }
  79. if (mysqli_num_rows == 0){
  80. //'Bad request' status code
  81. http_response_code(400);
  82. return 0;
  83. }
  84. else{
  85. $r = mysqli_fetch_array($q);
  86. return($r['version']);
  87. }
  88. }
  89. /****************************************************
  90. * Prepares the info of the database or a portion of *
  91. * it in the selected format. *
  92. * *
  93. * @params: *
  94. * con: (MySQL server connection) RO mode enough. *
  95. * section: (string): 'blog', 'activities', *
  96. * 'gallery', 'lablanca', 'global'. None *
  97. * to get them all. *
  98. * format: (int): 1: json (default). *
  99. ****************************************************/
  100. function sync($con, $section = SEC_ALL, $format = DEF_FORMAT){
  101. switch ($section){
  102. case SEC_BLOG:
  103. $tables = [ 'post', 'post_comment', 'post_image', 'post_tag' ];
  104. break;
  105. case SEC_ACTIVITIES:
  106. $tables = [ 'activity', 'activity_comment', 'activity_image', 'activity_tag', 'activity_itinerary', 'location', 'album', 'photo', 'photo_album', 'photo_comment', 'place' ];
  107. break;
  108. case SEC_GALLERY:
  109. $tables = [ 'album', 'photo', 'photo_album', 'photo_comment', 'place' ];
  110. break;
  111. case SEC_LABLANCA:
  112. $tables = [ 'festival', 'festival_day', 'festival_event', 'festival_event_image', 'festival_offer', 'place', 'people' ];
  113. break;
  114. case SEC_ALL:
  115. $tables = [ 'activity', 'activity_comment', 'activity_image', 'activity_tag', 'album', 'photo', 'festival', 'festival_day', 'festival_event', 'festival_event_image', 'festival_offer', 'place', 'post', 'post_comment', 'post_image', 'post_tag', 'settings', 'sponsor' ];
  116. break;
  117. default:
  118. //'Bad request' staus code
  119. http_response_code(400);
  120. return;
  121. }
  122. switch ($format){
  123. case FOR_JSON:
  124. $db = array();
  125. foreach($tables as $table){
  126. $db[] = [ $table => get_table($con, $table, $format) ];
  127. }
  128. return(json_encode($db));
  129. break;
  130. }
  131. }
  132. /****************************************************
  133. * Echoes the contents of a table from the database. *
  134. * Inaccessible or sensitive tables or fields are *
  135. * not printed. *
  136. * *
  137. * @params: *
  138. * con: (MySQL server connection) RO mode enough. *
  139. * table (string): The name of the table. *
  140. ****************************************************/
  141. function get_table($con, $table){
  142. $table = strtolower($table);
  143. switch ($table){
  144. case "activity":
  145. $q = mysqli_query($con, "SELECT id, permalink, date, city, title_es, title_en, title_eu, text_es, text_eu, text_en, after_es, after_en, after_eu, price, inscription, max_people, album FROM activity WHERE visible = 1;");
  146. break;
  147. case "activity_comment":
  148. $q = mysqli_query($con, "SELECT activity_comment.id AS id, activity, text, dtime, CONCAT(user.username, user) AS user, lang FROM activity_comment, user WHERE activity_comment.user = user.id AND approved = 1;");
  149. break;
  150. case "album":
  151. $q = mysqli_query($con, "SELECT id, permalink, title_es, title_en, title_eu, description_es, description_en, description_eu, open FROM album;");
  152. break;
  153. case "photo":
  154. $q = mysqli_query($con, "SELECT photo.id AS id, file, permalink, text_es, text_en, text_eu, description_es, description_en, description_eu, uploaded, place, width, height, size, CONCAT(username, user) AS user FROM photo, user WHERE user.id = photo.user AND approved = 1;");
  155. break;
  156. case "post":
  157. $q = mysqli_query($con, "SELECT post.id AS id, permalink, title_es, title_en, title_eu, text_es, text_en, text_eu, username, dtime FROM post, user WHERE user.id = user AND visible = 1;");
  158. break;
  159. case "post_comment":
  160. $q = mysqli_query($con, "SELECT post_comment.id AS id, post, text, dtime, CONCAT(user.username, user) AS user, lang FROM post_comment, user WHERE post_comment.user = user.id AND approved = 1;");
  161. break;
  162. //Other cases:
  163. default:
  164. //If the table is a public one and has not been listed above, all of its fields are public.
  165. if (in_array($table, ['activity_image', 'activity_tag', 'festival', 'festival_day', 'festival_event', 'festival_event_image', 'festival_offer', 'place', 'post_image', 'post_tag', 'settings', 'sponsor'])){
  166. $q = mysqli_query($con, "SELECT * FROM $table;");
  167. }
  168. //If forbidden table
  169. else{
  170. //'Forbidden' status code
  171. http_response_code(403);
  172. return;
  173. }
  174. }
  175. //Create result array
  176. $rows = array();
  177. while($r = mysqli_fetch_assoc($q)) {
  178. $rows[] = $r;
  179. }
  180. return $rows;
  181. }
  182. function get_user_ip(){
  183. $client = @$_SERVER['HTTP_CLIENT_IP'];
  184. $forward = @$_SERVER['HTTP_X_FORWARDED_FOR'];
  185. $remote = $_SERVER['REMOTE_ADDR'];
  186. if(filter_var($client, FILTER_VALIDATE_IP)){
  187. $ip = $client;
  188. }
  189. elseif(filter_var($forward, FILTER_VALIDATE_IP)){
  190. $ip = $forward;
  191. }
  192. else{
  193. $ip = $remote;
  194. }
  195. return $ip;
  196. }
  197. function log_sync($con, $client, $user, $action, $section, $version, $new_version, $foreground, $format, $error){
  198. $ip = get_user_ip();
  199. $browser_data = get_browser(null, true);
  200. $os = $browser_data['platform'];
  201. $browser = $browser_data['browser'];
  202. $uagent = $browser_data['browser_name_pattern'];
  203. mysqli_query($con, "INSERT INTO sync (client, user, action, section, version_from, version_to, fg, format, error, ip, os, uagent) VALUES ('$client', '$user', '$action', '$section', $version, $new_version, $foreground, '$format', '$error', '$ip', '$os', '$uagent');");
  204. error_log("INSERT INTO sync (client, user, action, section, version_from, version_to, fg, format, error, ip, os, uagent) VALUES ('$client', '$user', '$action', '$section', $version, $new_version, $foreground, '$format', '$error', '$ip', '$os', '$uagent');");
  205. }
  206. //Connect to the database
  207. $con = startdb('rw');
  208. //Get data from URL
  209. $client = mysqli_real_escape_string($con, $_GET[GET_CLIENT]);
  210. $user = mysqli_real_escape_string($con, $_GET[GET_USER]);
  211. $action = strtolower(mysqli_real_escape_string($con, $_GET[GET_ACTION]));
  212. $section = strtolower(mysqli_real_escape_string($con, $_GET[GET_SECTION]));
  213. $version = mysqli_real_escape_string($con, $_GET[GET_VERSION]);
  214. $foregroud = mysqli_real_escape_string($con, $_GET[GET_FOREGROUND]);
  215. $format = strtolower(mysqli_real_escape_string($con, $_GET[GET_FORMAT]));
  216. //Initialize some variables
  217. $error = '';
  218. $new_version = -1;
  219. //Validate data
  220. if (strlen($client) < 1){
  221. $client = '';
  222. }
  223. if (strlen($user) < 1){
  224. $user = '';
  225. }
  226. if ($action != ACTION_SYNC && $action != ACTION_VERSION){
  227. //Bad request
  228. http_response_code(400);
  229. $error = $error . ERR_ACTION . mysqli_real_escape_string($con, $_GET[GET_ACTION]);
  230. }
  231. if (strlen($section) > 0 && $section != SEC_ALL && $section != SEC_BLOG && $section != SEC_ACTIVITIES && $section != SEC_GALLERY && $section != SEC_LABLANCA ){
  232. //Bad request
  233. http_response_code(400);
  234. $error = $error . ERR_SECTION . mysqli_real_escape_string($con, $_GET[GET_SECTION]);
  235. }
  236. if (strlen($section) == 0){
  237. $section = SEC_ALL;
  238. }
  239. if (strlen($version) == 0){
  240. $version = -1;
  241. }
  242. if (is_int($version) == false){
  243. //Bad request
  244. http_response_code(400);
  245. $error = $error . ERR_VERSION . mysqli_real_escape_string($con, $_GET[GET_VERSION]);
  246. $version = -1;
  247. }
  248. if (strlen($foregroud) < 1){
  249. $foreground = 1;
  250. }
  251. if ($foreground != 0 && $foregroud != 0){
  252. //Bad request
  253. http_response_code(400);
  254. $error = $error . ERR_FOREGROUND . mysqli_real_escape_string($con, $_GET[GET_BACKGROUND]);
  255. }
  256. if (strlen($format) < 1){
  257. $format = DEF_FORMAT;
  258. }
  259. if ($format != FOR_JSON){
  260. //Bad request
  261. http_response_code(400);
  262. $error = $error . ERR_FORMAT . mysqli_real_escape_string($con, $_GET[GET_FORMAT]);
  263. }
  264. //If there has not been an error, procede
  265. if (strlen($error) == 0){
  266. //If the client just needs to know the version number
  267. if ($action == ACTION_VERSION){
  268. $new_version = get_version($con, $section);
  269. echo ($new_version);
  270. }
  271. //If the clients wants to actually perform a sync
  272. else{
  273. //If the client version is up to date, send a no content status
  274. $new_version = get_version($con, $section);
  275. if ($version >= $new_version){
  276. //No content
  277. http_response_code(204);
  278. }
  279. //If the client needs an update
  280. else{
  281. echo(sync($con, $section));
  282. }
  283. }
  284. }
  285. //Log the sync in the database
  286. log_sync($con, $client, $user, $action, $section, $version, $new_version, $foreground, $format, $error);
  287. ?>