sync.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. <?php
  2. // Gasteizko Margolariak API v1 //
  3. //Database section identifiers
  4. define('SEC_ALL', 'all');
  5. define('SEC_BLOG', 'blog');
  6. define('SEC_ACTIVITIES', 'activities');
  7. define('SEC_GALLERY', 'gallery');
  8. define('SEC_LABLANCA', 'lablanca');
  9. define('TAB_ACTIVITY', 'activity');
  10. define('TAB_ACTIVITY_COMMENT', 'activity_comment');
  11. define('TAB_ACTIVITY_IMAGE', 'activity_image');
  12. define('TAB_ACTIVITY_ITINERARY', 'activity_itinerary');
  13. define('TAB_ACTIVITY_TAG', 'activity_tag');
  14. define('TAB_ALBUM', 'album');
  15. define('TAB_FESTIVAL', 'festival');
  16. define('TAB_FESTIVAL_DAY', 'festival_day');
  17. define('TAB_FESTIVAL_EVENT_CITY', 'festival_event_city');
  18. define('TAB_FESTIVAL_EVENT_GM', 'festival_event_gm');
  19. define('TAB_FESTIVAL_OFFER', 'festival_offer');
  20. define('TAB_PEOPLE', 'people');
  21. define('TAB_PHOTO', 'photo');
  22. define('TAB_PHOTO_ALBUM', 'photo_album');
  23. define('TAB_PHOTO_COMMENT', 'photo_comment');
  24. define('TAB_PLACE', 'place');
  25. define('TAB_POST', 'post');
  26. define('TAB_POST_COMMENT', 'post_comment');
  27. define('TAB_POST_IMAGE', 'post_image');
  28. define('TAB_POST_TAG', 'post_tag');
  29. define('TAB_ROUTE', 'route');
  30. define('TAB_ROUTE_POINT', 'route_point');
  31. define('TAB_SETTINGS', 'settings');
  32. define('TAB_SPONSOR', 'sponsor');
  33. //Posible actions
  34. define('ACTION_SYNC', 'sync');
  35. define('ACTION_VERSION', 'version');
  36. //Default action
  37. define('DEF_ACTION', ACTION_SYNC);
  38. //Output keys
  39. define('KEY_VERSION', 'version');
  40. define('KEY_DATA', 'data');
  41. //$_GET valid parameters
  42. define('GET_CLIENT', 'client');
  43. define('GET_USER', 'user');
  44. define('GET_FOREGROUND', 'foreground');
  45. //Error messages
  46. define('ERR_CLIENT', 'CLIENT');
  47. //List of all tables to sync, sorted by priority.
  48. $tab_list = [TAB_SETTINGS, TAB_PLACE, TAB_ROUTE_POINT, TAB_ROUTE, TAB_PEOPLE, TAB_FESTIVAL_EVENT_GM, TAB_FESTIVAL, TAB_FESTIVAL_DAY, TAB_FESTIVAL_OFFER, TAB_FESTIVAL_EVENT_CITY, TAB_ACTIVITY, TAB_ACTIVITY_IMAGE, TAB_ACTIVITY_ITINERARY, TAB_SPONSOR, TAB_ALBUM, TAB_PHOTO, TAB_PHOTO_ALBUM, TAB_POST, TAB_POST_IMAGE, TAB_PHOTO_COMMENT, TAB_POST_COMMENT, TAB_ACTIVITY_COMMENT, TAB_ACTIVITY_TAG, TAB_POST_TAG];
  49. /****************************************************
  50. * This function is called from almost everywhere at *
  51. * the beggining of the page. It initializes the *
  52. * session variables, connect to the db, enabling *
  53. * the variable $con for futher use everywhere in *
  54. * the php code, and populates the arrays $user *
  55. * and $permission, with info about the user. *
  56. * *
  57. * @return: (db connection): The connection handler. *
  58. *****************************************************/
  59. function startdb(){
  60. //Include the db configuration file. It's somehow like this
  61. /*
  62. <?php
  63. $host = 'XXXX';
  64. $db_name = 'XXXX';
  65. $username_ro = 'XXXX';
  66. $username_rw = 'XXXX';
  67. $pass_ro = 'XXXX';
  68. $pass_rw = 'XXXX';
  69. ?>
  70. */
  71. include('../../.htpasswd');
  72. //Connect to to database
  73. $con = mysqli_connect($host, $username_rw, $pass_rw, $db_name);
  74. //Set encoding options
  75. mysqli_set_charset($con, 'utf-8');
  76. header('Content-Type: text/html; charset=utf8');
  77. mysqli_query($con, 'SET NAMES utf8;');
  78. //Return the db connection
  79. return $con;
  80. }
  81. /*****************************************************
  82. * Selects the value of a parameter from the list of *
  83. * GET arguments. It also sanitizes it to prevent *
  84. * SQL injections. *
  85. * *
  86. * @params: *
  87. * get: (string array) Contains the GET *
  88. * parameters. *
  89. * param: (string) Name of the parameter. *
  90. * @return: (string): Value of the parameter or an *
  91. * empty string if it was not passed. *
  92. *****************************************************/
  93. function extract_param($con, $get, $param){
  94. if(isset($_GET[$param])){
  95. return mysqli_real_escape_string($con, $_GET[$param]);
  96. }
  97. else{
  98. return "";
  99. }
  100. }
  101. /*****************************************************
  102. * Gets information about the API call and the *
  103. * assocciated client. If some mandatory parameter *
  104. * is not provided, a error log entry is registered *
  105. * *
  106. * @params: *
  107. * get: (string array) Contains the GET *
  108. * parameters. *
  109. * @return: (string array): Array with the keys *
  110. * 'client', 'user', 'foreground', 'ip', *
  111. * 'os', 'browser', 'uagent' and 'error'. *
  112. * 'error' will contain the key of a *
  113. * mandatory value if it has not been *
  114. * provided, or will be empty if there *
  115. * were no problem. *
  116. *****************************************************/
  117. function get_user_info($con, $get){
  118. $info = array();
  119. $error = "";
  120. $info["client"] = extract_param($con, $get, GET_CLIENT);
  121. if(strlen($info["client"]) == 0) {
  122. error_log("SYNC ERROR: Trying to sync with no client name.");
  123. $error = ERR_CLIENT;
  124. }
  125. $info["user"] = extract_param($con, $get, GET_USER);
  126. $info["foregronud"] = (int) extract_param($con, $get, GET_FOREGROUND);
  127. if($info["foreground"] != 1){
  128. $info["foreground"] = 0;
  129. }
  130. $info["ip"] = get_user_ip();
  131. $browser_data = get_browser(null, true);
  132. $info["os"] = $browser_data['platform'];
  133. $info["browser"] = $browser_data['browser'];
  134. $info["uagent"] = $browser_data['browser_name_pattern'];
  135. $info["error"] = $error;
  136. }
  137. /*****************************************************
  138. * Reads the version of the tables reported by the *
  139. * user as GET parameters. *
  140. * *
  141. * @params: *
  142. * get: (string array) Contains the GET *
  143. * parameters. *
  144. * @return: (int array): Array with the version of *
  145. * the tables in the user app, keyed with *
  146. * the table names. *
  147. *****************************************************/
  148. function get_user_versions($con, $get){
  149. global $tab_list;
  150. $versions = array();
  151. foreach($tab_list as $tab){
  152. $versions[$tab] = intval(extract_param($con, $get, $tab));
  153. }
  154. return $versions;
  155. }
  156. /*****************************************************
  157. * Reads the version of the tables reported by the *
  158. * user as GET parameters. *
  159. * *
  160. * @params: *
  161. * con: (MySQL server connection) RO mode enough. *
  162. * parameters. *
  163. * @return: (int array): Array with the version of *
  164. * the tables in the server, keyed with *
  165. * the table names. *
  166. *****************************************************/
  167. function get_server_versions($con){
  168. $versions = array();
  169. $q = mysqli_query($con, "SELECT section, version FROM version;");
  170. while($r = mysqli_fetch_array($q)){
  171. $versions[$r['section']] = $r['version'];
  172. }
  173. return $versions;
  174. }
  175. /*****************************************************
  176. * Select the tables that need to be synced. *
  177. * *
  178. * @params: *
  179. * user: (int array) Versions of tables in the *
  180. * user app. *
  181. * server: (int array) Versions of tables in the *
  182. * server. *
  183. * @return: (string array): Array with the names of *
  184. * the tables that need to be synced. *
  185. *****************************************************/
  186. function select_tables($user, $server){
  187. global $tab_list;
  188. $tables = array();
  189. foreach($tab_list as $table){
  190. if ($user[$table] < $server[$table]){
  191. array_push($tables, $table);
  192. }
  193. }
  194. }
  195. /****************************************************
  196. * Echoes the contents of a table from the database. *
  197. * Inaccessible or sensitive tables or fields are *
  198. * not printed. *
  199. * *
  200. * @params: *
  201. * con: (MySQL server connection) RO mode enough. *
  202. * table (string): The name of the table. *
  203. * @return: (Assoc Array): Data in the table. *
  204. ****************************************************/
  205. function get_table($con, $table){
  206. $table = strtolower($table);
  207. switch ($table){
  208. case TAB_ACTIVITY:
  209. $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;");
  210. break;
  211. case TAB_ACTIVITY_COMMENT:
  212. $q = mysqli_query($con, "SELECT id, activity, text, dtime, username, lang FROM activity_comment WHERE approved = 1;");
  213. break;
  214. case TAB_ALBUM:
  215. $q = mysqli_query($con, "SELECT id, permalink, title_es, title_en, title_eu, description_es, description_en, description_eu, open FROM album;");
  216. break;
  217. case TAB_PHOTO:
  218. $q = mysqli_query($con, "SELECT photo.id AS id, file, permalink, title_es, title_en, title_eu, description_es, description_en, description_eu, uploaded, place, width, height, size, CONCAT(photo.username, user) AS username FROM photo, user WHERE user.id = photo.user AND approved = 1;");
  219. break;
  220. case TAB_POST:
  221. $q = mysqli_query($con, "SELECT post.id AS id, permalink, title_es, title_en, title_eu, text_es, text_en, text_eu, comments, username, dtime FROM post, user WHERE user.id = user AND visible = 1;");
  222. break;
  223. case TAB_POST_COMMENT:
  224. $q = mysqli_query($con, "SELECT post_comment.id AS id, post, text, dtime, username, lang FROM post_comment WHERE approved = 1;");
  225. break;
  226. case TAB_PHOTO_COMMENT:
  227. $q = mysqli_query($con, "SELECT photo_comment.id AS id, post, text, dtime, username, lang FROM photo_comment WHERE approved = 1;");
  228. break;
  229. case TAB_SPONSOR:
  230. $q = mysqli_query($con, "SELECT id, name_es, name_en, name_eu, text_es, text_en, text_eu, image, address_es, address_en, address_eu, link, lat, lon FROM sponsor;");
  231. break;
  232. case TAB_SETTINGS:
  233. $q = mysqli_query($con, "SELECT name, value FROM settings;");
  234. break;
  235. //Other cases:
  236. default:
  237. $q = mysqli_query($con, "SELECT * FROM $table;");
  238. }
  239. //If no rows, return
  240. if (mysqli_num_rows($q) == 0){
  241. return "";
  242. }
  243. //Create result array
  244. $str = "";
  245. $str = $str. "\"$table\":[";
  246. while($r = mysqli_fetch_assoc($q)) {
  247. $str = $str . json_encode($r) . ",";
  248. }
  249. $str = rtrim($str,',');
  250. $str = $str . "]";
  251. return $str;
  252. }
  253. /*****************************************************
  254. * Prints out required tables. *
  255. * *
  256. * @return: (String): Client IP address. *
  257. *****************************************************/
  258. function sync($con, $tables){
  259. $str = "";
  260. if(sizeof($tables) > 0){
  261. $str = "{" . get_table('version');
  262. foreach($tables as $table){
  263. $str = $str . get_table($con, $table) . ",";
  264. }
  265. $str = rtrim($str,',');
  266. $str = $str . "}";
  267. echo($str);
  268. return true;
  269. }
  270. return false;
  271. }
  272. /*****************************************************
  273. * Gets the IP address of the client. *
  274. * *
  275. * @return: (String): Client IP address. *
  276. *****************************************************/
  277. function get_user_ip(){
  278. $client = @$_SERVER['HTTP_CLIENT_IP'];
  279. $forward = @$_SERVER['HTTP_X_FORWARDED_FOR'];
  280. $remote = $_SERVER['REMOTE_ADDR'];
  281. if(filter_var($client, FILTER_VALIDATE_IP)){
  282. $ip = $client;
  283. }
  284. elseif(filter_var($forward, FILTER_VALIDATE_IP)){
  285. $ip = $forward;
  286. }
  287. else{
  288. $ip = $remote;
  289. }
  290. return $ip;
  291. }
  292. /****************************************************
  293. * Registers the request in the database. *
  294. * *
  295. * @params: *
  296. * con: (MySQL server connection) RO mode enough. *
  297. * client: (string): The client identifier. *
  298. * user: (string): A unique end user identifier. *
  299. * action: (string): Requested action. *
  300. * section: (string): Requested database section. *
  301. * version: (int): Version of the client db. *
  302. * new_version: (int): Returned version. *
  303. * foreground: (int): 1 for fg syncs, 0 for bg. *
  304. * format: (string): Requested format. *
  305. * error: (string): Error message to store. *
  306. ****************************************************/
  307. function log_sync($con, $user, $synced){
  308. // TODO: implement once the sync table has been reworked.
  309. //mysqli_query($con, "INSERT INTO sync (client, user, fg, synced, ip, os, uagent) VALUES ('$client', '$user', '$action', '$section', $version, $new_version, $foreground, '$format', '$error', '$ip', '$os', '$uagent');");
  310. }
  311. // Connect to the database
  312. $con = startdb('rw');
  313. // Get info about the user
  314. $user = get_user_info($con, $_GET);
  315. if(strlen($user["error"]) > 0){
  316. http_response_code(400);
  317. exit(-1);
  318. }
  319. // Get tables to sync
  320. $v_user = get_user_versions($con, $_GET);
  321. $v_server = get_server_versions($con);
  322. $tables = select_tables($v_user, $v_server);
  323. $synced = sync($con, $tables);
  324. //Log the sync in the database
  325. log_sync($con, $user, $synced);
  326. ?>