Esempio n. 1
0
 public static function call(OkapiRequest $request)
 {
     # Read the parameters.
     $acode = $request->get_parameter('acode');
     if ($acode === null) {
         throw new ParamMissing('acode');
     }
     if (strstr($acode, '|')) {
         throw new InvalidParam('acode', "Only a single A-code must be supplied.");
     }
     $langpref = $request->get_parameter('langpref');
     if (!$langpref) {
         $langpref = "en";
     }
     $fields = $request->get_parameter('fields');
     if (!$fields) {
         $fields = "name";
     }
     $forward_compatible = $request->get_parameter('forward_compatible');
     if (!$forward_compatible) {
         $forward_compatible = "true";
     }
     # Pass them all to the attributes method.
     $params = array('acodes' => $acode, 'langpref' => $langpref, 'fields' => $fields, 'forward_compatible' => $forward_compatible);
     $results = OkapiServiceRunner::call('services/attrs/attributes', new OkapiInternalRequest($request->consumer, $request->token, $params));
     $result = $results[$acode];
     if ($result === null) {
         /* Note, this can happen only when $forward_compatible is false. */
         throw new InvalidParam('acode', "Unknown A-code.");
     }
     return Okapi::formatted_response($request, $result);
 }
Esempio n. 2
0
 public static function call(OkapiRequest $request)
 {
     # User is already verified (via OAuth), but we need to verify the
     # cache code (check if it exists). We will simply call a geocache method
     # on it - this will also throw a proper exception if it doesn't exist.
     $cache_code = $request->get_parameter('cache_code');
     if ($cache_code == null) {
         throw new ParamMissing('cache_code');
     }
     $geocache = OkapiServiceRunner::call('services/caches/geocache', new OkapiInternalRequest($request->consumer, $request->token, array('cache_code' => $cache_code, 'fields' => 'internal_id')));
     # watched
     if ($tmp = $request->get_parameter('watched')) {
         if (!in_array($tmp, array('true', 'false', 'unchanged'))) {
             throw new InvalidParam('watched', $tmp);
         }
         if ($tmp == 'true') {
             Db::execute("\n                    insert ignore into cache_watches (cache_id, user_id)\n                    values (\n                        '" . Db::escape_string($geocache['internal_id']) . "',\n                        '" . Db::escape_string($request->token->user_id) . "'\n                    );\n                ");
         } elseif ($tmp == 'false') {
             Db::execute("\n                    delete from cache_watches\n                    where\n                        cache_id = '" . Db::escape_string($geocache['internal_id']) . "'\n                        and user_id = '" . Db::escape_string($request->token->user_id) . "';\n                ");
         }
     }
     # ignored
     if ($tmp = $request->get_parameter('ignored')) {
         if (!in_array($tmp, array('true', 'false', 'unchanged'))) {
             throw new InvalidParam('ignored', $tmp);
         }
         if ($tmp == 'true') {
             Db::execute("\n                    insert ignore into cache_ignore (cache_id, user_id)\n                    values (\n                        '" . Db::escape_string($geocache['internal_id']) . "',\n                        '" . Db::escape_string($request->token->user_id) . "'\n                    );\n                ");
         } elseif ($tmp == 'false') {
             Db::execute("\n                    delete from cache_ignore\n                    where\n                        cache_id = '" . Db::escape_string($geocache['internal_id']) . "'\n                        and user_id = '" . Db::escape_string($request->token->user_id) . "'\n                ");
         }
     }
     $result = array('success' => true);
     return Okapi::formatted_response($request, $result);
 }
Esempio n. 3
0
 public static function get_installations()
 {
     $installations = OkapiServiceRunner::call("services/apisrv/installations", new OkapiInternalRequest(new OkapiInternalConsumer(), null, array()));
     foreach ($installations as &$inst_ref) {
         $inst_ref['selected'] = $inst_ref['site_url'] == Settings::get('SITE_URL');
     }
     return $installations;
 }
Esempio n. 4
0
 /**
  * This works like service_call with two exceptions: 1. It passes all your
  * current HTTP request headers to OKAPI (which can make use of them in
  * terms of caching), 2. It outputs the service response directly, instead
  * of returning it.
  */
 public static function service_display($service_name, $user_id_or_null, $parameters)
 {
     $request = new OkapiInternalRequest(new OkapiFacadeConsumer(), $user_id_or_null !== null ? new OkapiFacadeAccessToken($user_id_or_null) : null, $parameters);
     $request->perceive_as_http_request = true;
     if (isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
         $request->etag = $_SERVER['HTTP_IF_NONE_MATCH'];
     }
     $response = OkapiServiceRunner::call($service_name, $request);
     $response->display();
 }
 public static function call($methodname)
 {
     require_once $GLOBALS['rootpath'] . 'okapi/service_runner.php';
     if (!OkapiServiceRunner::exists($methodname)) {
         throw new BadRequest("Method '{$methodname}' does not exist. " . "See OKAPI docs at " . Settings::get('SITE_URL') . "okapi/");
     }
     $options = OkapiServiceRunner::options($methodname);
     $request = new OkapiHttpRequest($options);
     return OkapiServiceRunner::call($methodname, $request);
 }
Esempio n. 6
0
 public static function call(OkapiRequest $request)
 {
     $cache_code = $request->get_parameter('cache_code');
     if (!$cache_code) {
         throw new ParamMissing('cache_code');
     }
     if (strpos($cache_code, "|") !== false) {
         throw new InvalidParam('cache_code');
     }
     $langpref = $request->get_parameter('langpref');
     if (!$langpref) {
         $langpref = "en";
     }
     $langpref .= "|" . Settings::get('SITELANG');
     $fields = $request->get_parameter('fields');
     if (!$fields) {
         $fields = "code|name|location|type|status";
     }
     $log_fields = $request->get_parameter('log_fields');
     if (!$log_fields) {
         $log_fields = "uuid|date|user|type|comment";
     }
     $lpc = $request->get_parameter('lpc');
     if (!$lpc) {
         $lpc = 10;
     }
     $attribution_append = $request->get_parameter('attribution_append');
     if (!$attribution_append) {
         $attribution_append = 'full';
     }
     $params = array('cache_codes' => $cache_code, 'langpref' => $langpref, 'fields' => $fields, 'attribution_append' => $attribution_append, 'lpc' => $lpc, 'log_fields' => $log_fields);
     $my_location = $request->get_parameter('my_location');
     if ($my_location) {
         $params['my_location'] = $my_location;
     }
     $user_uuid = $request->get_parameter('user_uuid');
     if ($user_uuid) {
         $params['user_uuid'] = $user_uuid;
     }
     # There's no need to validate the fields/lpc parameters as the 'geocaches'
     # method does this (it will raise a proper exception on invalid values).
     $results = OkapiServiceRunner::call('services/caches/geocaches', new OkapiInternalRequest($request->consumer, $request->token, $params));
     $result = $results[$cache_code];
     if ($result === null) {
         # Two errors messages (for OCDE). Makeshift solution for issue #350.
         $exists = Db::select_value("\n                select 1\n                from caches\n                where wp_oc='" . Db::escape_string($cache_code) . "'\n            ");
         if ($exists) {
             throw new InvalidParam('cache_code', "This cache is not accessible via OKAPI.");
         } else {
             throw new InvalidParam('cache_code', "This cache does not exist.");
         }
     }
     return Okapi::formatted_response($request, $result);
 }
 public static function call()
 {
     require_once $GLOBALS['rootpath'] . 'okapi/service_runner.php';
     require_once $GLOBALS['rootpath'] . 'okapi/views/menu.inc.php';
     $vars = array('menu' => OkapiMenu::get_menu_html("introduction.html"), 'okapi_base_url' => Settings::get('SITE_URL') . "okapi/", 'site_url' => Settings::get('SITE_URL'), 'method_index' => OkapiServiceRunner::call('services/apiref/method_index', new OkapiInternalRequest(new OkapiInternalConsumer(), null, array())), 'installations' => OkapiMenu::get_installations(), 'okapi_rev' => Okapi::$version_number);
     $response = new OkapiHttpResponse();
     $response->content_type = "text/html; charset=utf-8";
     ob_start();
     include 'introduction.tpl.php';
     $response->body = ob_get_clean();
     return $response;
 }
Esempio n. 8
0
 public static function call()
 {
     # By default, this view is turned off in the urls.php file.
     # This view is for debugging TileMap performace only!
     set_time_limit(0);
     header("Content-Type: text/plain; charset=utf-8");
     $user_id = $_GET['u'];
     self::out("Yo. I'm {$user_id}.\n\n");
     while (true) {
         srand(floor(time() / 10));
         $mode2 = rand(0, 9) <= 7;
         if ($mode2) {
             $row = Db::select_row("\n                    select z, x, y\n                    from okapi_tile_status\n                    where status = 2 and z < 20\n                    order by rand()\n                    limit 1;\n                ");
             $z = $row['z'] + 1;
             $x = $row['x'] << 1;
             $y = $row['y'] << 1;
             $x += rand(0, 1);
             $y += rand(0, 1);
         } else {
             $z = rand(5, 21);
             $x = rand(0, (1 << $z) - 1);
             $y = rand(0, (1 << $z) - 1);
         }
         $tiles = array();
         for ($xx = $x; $xx < $x + 4; $xx++) {
             for ($yy = $y; $yy < $y + 4; $yy++) {
                 $tiles[] = array($xx, $yy);
             }
         }
         srand();
         shuffle($tiles);
         foreach ($tiles as $tile) {
             list($x, $y) = $tile;
             self::out("Loading " . str_pad("({$z}, {$x}, {$y})... ", 30));
             $time_started = microtime(true);
             try {
                 $response = OkapiServiceRunner::call('services/caches/map/tile', new OkapiInternalRequest(new OkapiInternalConsumer(), new OkapiInternalAccessToken($user_id), array('z' => "{$z}", 'x' => "{$x}", 'y' => "{$y}")));
                 $runtime = microtime(true) - $time_started;
                 $ds = floor($runtime * 100);
                 self::out(str_repeat("#", $ds) . " ");
                 $b = floor(strlen($response->get_body()) / 256);
                 self::out(str_repeat("@", $b) . "\n");
             } catch (Exception $e) {
                 self::out("\n\n" . OkapiExceptionHandler::get_exception_info($e));
                 die;
             }
         }
     }
 }
Esempio n. 9
0
 public static function call(OkapiRequest $request)
 {
     $username = $request->get_parameter('username');
     if (!$username) {
         throw new ParamMissing('username');
     }
     $fields = $request->get_parameter('fields');
     # There's no need to validate the fields parameter.
     $results = OkapiServiceRunner::call('services/users/by_usernames', new OkapiInternalRequest($request->consumer, $request->token, array('usernames' => $username, 'fields' => $fields)));
     $result = $results[$username];
     if ($result == null) {
         throw new InvalidParam('username', "There is no user by this username.");
     }
     return Okapi::formatted_response($request, $result);
 }
Esempio n. 10
0
 public static function call(OkapiRequest $request)
 {
     $methodnames = OkapiServiceRunner::$all_names;
     sort($methodnames);
     $cache_key = "api_ref/method_index#" . md5(implode("#", $methodnames));
     $results = Cache::get($cache_key);
     if ($results == null) {
         $results = array();
         foreach ($methodnames as $methodname) {
             $info = OkapiServiceRunner::call('services/apiref/method', new OkapiInternalRequest(new OkapiInternalConsumer(), null, array('name' => $methodname)));
             $results[] = array('name' => $info['name'], 'brief_description' => $info['brief_description']);
         }
         Cache::set($cache_key, $results, 3600);
     }
     return Okapi::formatted_response($request, $results);
 }
Esempio n. 11
0
 public static function call(OkapiRequest $request)
 {
     $cache_code = $request->get_parameter('cache_code');
     if (!$cache_code) {
         throw new ParamMissing('cache_code');
     }
     if (strpos($cache_code, "|") !== false) {
         throw new InvalidParam('cache_code');
     }
     $langpref = $request->get_parameter('langpref');
     if (!$langpref) {
         $langpref = "en|" . Settings::get('SITELANG');
     }
     $fields = $request->get_parameter('fields');
     if (!$fields) {
         $fields = "code|name|location|type|status";
     }
     $log_fields = $request->get_parameter('log_fields');
     if (!$log_fields) {
         $log_fields = "uuid|date|user|type|comment";
     }
     $lpc = $request->get_parameter('lpc');
     if (!$lpc) {
         $lpc = 10;
     }
     $attribution_append = $request->get_parameter('attribution_append');
     if (!$attribution_append) {
         $attribution_append = 'full';
     }
     $params = array('cache_codes' => $cache_code, 'langpref' => $langpref, 'fields' => $fields, 'attribution_append' => $attribution_append, 'lpc' => $lpc, 'log_fields' => $log_fields);
     $my_location = $request->get_parameter('my_location');
     if ($my_location) {
         $params['my_location'] = $my_location;
     }
     $user_uuid = $request->get_parameter('user_uuid');
     if ($user_uuid) {
         $params['user_uuid'] = $user_uuid;
     }
     # There's no need to validate the fields/lpc parameters as the 'geocaches'
     # method does this (it will raise a proper exception on invalid values).
     $results = OkapiServiceRunner::call('services/caches/geocaches', new OkapiInternalRequest($request->consumer, $request->token, $params));
     $result = $results[$cache_code];
     if ($result === null) {
         throw new InvalidParam('cache_code', "This cache does not exist.");
     }
     return Okapi::formatted_response($request, $result);
 }
Esempio n. 12
0
 public static function call(OkapiRequest $request)
 {
     # Get current notes, and verify cache_code
     $cache_code = $request->get_parameter('cache_code');
     if ($cache_code == null) {
         throw new ParamMissing('cache_code');
     }
     $geocache = OkapiServiceRunner::call('services/caches/geocache', new OkapiInternalRequest($request->consumer, $request->token, array('cache_code' => $cache_code, 'fields' => 'my_notes|internal_id')));
     $current_value = $geocache['my_notes'];
     if ($current_value == null) {
         $current_value = "";
     }
     $cache_id = $geocache['internal_id'];
     # old_value
     $old_value = $request->get_parameter('old_value');
     if ($old_value === null) {
         $old_value = '';
     }
     # new_value (force "no HTML" policy).
     $new_value = $request->get_parameter('new_value');
     if ($new_value === null) {
         throw new ParamMissing('new_value');
     }
     # Force "no HTML" policy.
     $new_value = strip_tags($new_value);
     # Placeholders for returned values.
     $ret_saved_value = null;
     $ret_replaced = false;
     if (trim($current_value) == "" || self::str_equals($old_value, $current_value)) {
         /* REPLACE mode */
         $ret_replaced = true;
         if (trim($new_value) == "") {
             /* empty new value means delete */
             self::remove_notes($cache_id, $request->token->user_id);
             $ret_saved_value = null;
         } else {
             self::update_notes($cache_id, $request->token->user_id, $new_value);
             $ret_saved_value = $new_value;
         }
     } else {
         /* APPEND mode */
         $ret_saved_value = trim($current_value) . "\n\n" . trim($new_value);
         self::update_notes($cache_id, $request->token->user_id, $ret_saved_value);
     }
     $result = array('saved_value' => $ret_saved_value, 'replaced' => $ret_replaced);
     return Okapi::formatted_response($request, $result);
 }
Esempio n. 13
0
 public static function call(OkapiRequest $request)
 {
     $cache_code = $request->get_parameter('cache_code');
     if (!$cache_code) {
         throw new ParamMissing('cache_code');
     }
     $fields = $request->get_parameter('fields');
     if (!$fields) {
         $fields = "uuid|date|user|type|comment";
     }
     $offset = $request->get_parameter('offset');
     if (!$offset) {
         $offset = "0";
     }
     if ((int) $offset != $offset || (int) $offset < 0) {
         throw new InvalidParam('offset', "Expecting non-negative integer.");
     }
     $limit = $request->get_parameter('limit');
     if (!$limit) {
         $limit = "none";
     }
     if ($limit == "none") {
         $limit = "999999999";
     }
     if ((int) $limit != $limit || (int) $limit < 0) {
         throw new InvalidParam('limit', "Expecting non-negative integer or 'none'.");
     }
     # Check if code exists and retrieve cache ID (this will throw
     # a proper exception on invalid code).
     $cache = OkapiServiceRunner::call('services/caches/geocache', new OkapiInternalRequest($request->consumer, null, array('cache_code' => $cache_code, 'fields' => 'internal_id')));
     # Cache exists. Getting the uuids of its logs.
     $log_uuids = Db::select_column("\n            select uuid\n            from cache_logs\n            where\n                cache_id = '" . Db::escape_string($cache['internal_id']) . "'\n                and " . (Settings::get('OC_BRANCH') == 'oc.pl' ? "deleted = 0" : "true") . "\n            order by date desc\n            limit {$offset}, {$limit}\n        ");
     # Getting the logs themselves. Formatting as an ordered list.
     $internal_request = new OkapiInternalRequest($request->consumer, $request->token, array('log_uuids' => implode("|", $log_uuids), 'fields' => $fields));
     $internal_request->skip_limits = true;
     $logs = OkapiServiceRunner::call('services/logs/entries', $internal_request);
     $results = array();
     foreach ($log_uuids as $log_uuid) {
         $results[] = $logs[$log_uuid];
     }
     /* Handle OCPL's "access logs" feature. */
     if (Settings::get('OC_BRANCH') == 'oc.pl' && Settings::get('OCPL_ENABLE_GEOCACHE_ACCESS_LOGS') && count($log_uuids) > 0) {
         require_once $GLOBALS['rootpath'] . 'okapi/lib/ocpl_access_logs.php';
         \okapi\OCPLAccessLogs::log_geocache_access($request, $cache['internal_id']);
     }
     return Okapi::formatted_response($request, $results);
 }
Esempio n. 14
0
 public static function call($methodname)
 {
     require_once $GLOBALS['rootpath'] . 'okapi/service_runner.php';
     require_once $GLOBALS['rootpath'] . 'okapi/views/menu.inc.php';
     try {
         $method = OkapiServiceRunner::call('services/apiref/method', new OkapiInternalRequest(null, null, array('name' => $methodname)));
     } catch (BadRequest $e) {
         throw new Http404();
     }
     $vars = array('method' => $method, 'menu' => OkapiMenu::get_menu_html($methodname . ".html"), 'okapi_base_url' => Settings::get('SITE_URL') . "okapi/", 'installations' => OkapiMenu::get_installations(), 'okapi_rev' => Okapi::$revision);
     $response = new OkapiHttpResponse();
     $response->content_type = "text/html; charset=utf-8";
     ob_start();
     include 'method_doc.tpl.php';
     $response->body = ob_get_clean();
     return $response;
 }
Esempio n. 15
0
 public static function call(OkapiRequest $request)
 {
     $log_uuid = $request->get_parameter('log_uuid');
     if (!$log_uuid) {
         throw new ParamMissing('log_uuid');
     }
     $fields = $request->get_parameter('fields');
     if (!$fields) {
         $fields = "date|user|type|comment";
     }
     $results = OkapiServiceRunner::call('services/logs/entries', new OkapiInternalRequest($request->consumer, $request->token, array('log_uuids' => $log_uuid, 'fields' => $fields)));
     $result = $results[$log_uuid];
     if ($result == null) {
         throw new InvalidParam('log_uuid', "This log entry does not exist.");
     }
     return Okapi::formatted_response($request, $result);
 }
Esempio n. 16
0
 public static function get_installations()
 {
     $installations = OkapiServiceRunner::call("services/apisrv/installations", new OkapiInternalRequest(new OkapiInternalConsumer(), null, array()));
     $site_url = Settings::get('SITE_URL');
     foreach ($installations as &$inst_ref) {
         # $inst_ref['site_url'] and $site_url can have different protocols
         # (http / https). We compare only the domain parts and use
         # $site_url (which has the current request's protocol) for the menu
         # so that the menu works properly.
         if (self::domains_are_equal($inst_ref['site_url'], $site_url)) {
             $inst_ref['site_url'] = $site_url;
             $inst_ref['okapi_base_url'] = $site_url . 'okapi/';
             $inst_ref['selected'] = true;
         } else {
             $inst_ref['selected'] = false;
         }
     }
     return $installations;
 }
Esempio n. 17
0
 public static function call(OkapiRequest $request)
 {
     $user_uuid = $request->get_parameter('user_uuid');
     if (!$user_uuid) {
         if ($request->token) {
             $tmp = OkapiServiceRunner::call('services/users/by_internal_id', new OkapiInternalRequest($request->consumer, null, array('internal_id' => $request->token->user_id, 'fields' => 'uuid')));
             $user_uuid = $tmp['uuid'];
         } else {
             throw new BadRequest("You must either: 1. supply the user_uuid argument, or " . "2. sign your request with an Access Token.");
         }
     }
     $fields = $request->get_parameter('fields');
     # There's no need to validate the fields parameter as the 'users'
     # method does this (it will raise a proper exception on invalid values).
     $results = OkapiServiceRunner::call('services/users/users', new OkapiInternalRequest($request->consumer, $request->token, array('user_uuids' => $user_uuid, 'fields' => $fields)));
     $result = $results[$user_uuid];
     if ($result == null) {
         throw new InvalidParam('user_uuid', "There is no user by this ID.");
     }
     return Okapi::formatted_response($request, $result);
 }
Esempio n. 18
0
 public static function call(OkapiRequest $request)
 {
     $usernames = $request->get_parameter('usernames');
     if (!$usernames) {
         throw new ParamMissing('usernames');
     }
     $usernames = explode("|", $usernames);
     if (count($usernames) > 500) {
         throw new InvalidParam('usernames', "Maximum allowed number of referenced users " . "is 500. You provided " . count($usernames) . " usernames.");
     }
     $fields = $request->get_parameter('fields');
     if (!$fields) {
         throw new ParamMissing('fields');
     }
     # There's no need to validate the fields parameter as the 'users'
     # method does this (it will raise a proper exception on invalid values).
     $rs = Db::query("\n            select username, uuid\n            from user\n            where username collate " . Settings::get('DB_CHARSET') . "_general_ci in ('" . implode("','", array_map('\\okapi\\Db::escape_string', $usernames)) . "')\n        ");
     $lower_username2useruuid = array();
     while ($row = Db::fetch_assoc($rs)) {
         $lower_username2useruuid[mb_strtolower($row['username'], 'utf-8')] = $row['uuid'];
     }
     Db::free_result($rs);
     # Retrieve data for the found user_uuids.
     if (count($lower_username2useruuid) > 0) {
         $id_results = OkapiServiceRunner::call('services/users/users', new OkapiInternalRequest($request->consumer, $request->token, array('user_uuids' => implode("|", array_values($lower_username2useruuid)), 'fields' => $fields)));
     } else {
         $id_results = array();
     }
     # Map user_uuids back to usernames. Also check which usernames were not found
     # and mark them with null.
     $results = array();
     foreach ($usernames as $username) {
         if (!isset($lower_username2useruuid[mb_strtolower($username, 'utf-8')])) {
             $results[$username] = null;
         } else {
             $results[$username] = $id_results[$lower_username2useruuid[mb_strtolower($username, 'utf-8')]];
         }
     }
     return Okapi::formatted_response($request, $results);
 }
Esempio n. 19
0
 public static function call(OkapiRequest $request)
 {
     $user_uuid = $request->get_parameter('user_uuid');
     if (!$user_uuid) {
         throw new ParamMissing('user_uuid');
     }
     $limit = $request->get_parameter('limit');
     if (!$limit) {
         $limit = "20";
     }
     if (!is_numeric($limit)) {
         throw new InvalidParam('limit', "'{$limit}'");
     }
     $limit = intval($limit);
     if ($limit < 1 || $limit > 1000) {
         throw new InvalidParam('limit', "Has to be in range 1..1000.");
     }
     $offset = $request->get_parameter('offset');
     if (!$offset) {
         $offset = "0";
     }
     if (!is_numeric($offset)) {
         throw new InvalidParam('offset', "'{$offset}'");
     }
     $offset = intval($offset);
     if ($offset < 0) {
         throw new InvalidParam('offset', "'{$offset}'");
     }
     # Check if user exists and retrieve user's ID (this will throw
     # a proper exception on invalid UUID).
     $user = OkapiServiceRunner::call('services/users/user', new OkapiInternalRequest($request->consumer, null, array('user_uuid' => $user_uuid, 'fields' => 'internal_id')));
     # User exists. Retrieving logs.
     $rs = Db::query("\n            select cl.id, cl.uuid, cl.type, unix_timestamp(cl.date) as date, cl.text,\n                c.wp_oc as cache_code\n            from cache_logs cl, caches c\n            where\n                cl.user_id = '" . Db::escape_string($user['internal_id']) . "'\n                and " . (Settings::get('OC_BRANCH') == 'oc.pl' ? "cl.deleted = 0" : "true") . "\n                and c.status in (1,2,3)\n                and cl.cache_id = c.cache_id\n            order by cl.date desc\n            limit {$offset}, {$limit}\n        ");
     $results = array();
     while ($row = Db::fetch_assoc($rs)) {
         $results[] = array('uuid' => $row['uuid'], 'date' => date('c', $row['date']), 'cache_code' => $row['cache_code'], 'type' => Okapi::logtypeid2name($row['type']), 'comment' => $row['text']);
     }
     return Okapi::formatted_response($request, $results);
 }
 private static function handle_geocache_replace($c)
 {
     # Check if any relevant geocache attributes have changed.
     # We will pick up "our" copy of the cache from zero-zoom level.
     try {
         $cache = OkapiServiceRunner::call("services/caches/geocache", new OkapiInternalRequest(new OkapiInternalConsumer(), null, array('cache_code' => $c['object_key']['code'], 'fields' => 'internal_id|code|name|location|type|status|rating|recommendations|founds|trackables_count')));
     } catch (InvalidParam $e) {
         # Unprobable, but possible. Ignore changelog entry.
         return;
     }
     # Fetch our copy of the cache.
     $ours = mysql_fetch_row(Db::query("\n            select cache_id, z21x, z21y, status, type, rating, flags, name_crc\n            from okapi_tile_caches\n            where\n                z=0\n                and cache_id = '" . mysql_real_escape_string($cache['internal_id']) . "'\n        "));
     # Caches near the poles caused our computations to break here. We will
     # ignore such caches!
     list($lat, $lon) = explode("|", $cache['location']);
     if (floatval($lat) >= 89.98999999999999 || floatval($lat) <= -89.98999999999999) {
         if ($ours) {
             self::remove_geocache_from_cached_tiles($ours[0]);
         }
         return;
     }
     # Compute the new row for okapi_tile_caches. Compare with the old one.
     $theirs = TileTree::generate_short_row($cache);
     if (!$ours) {
         # Aaah, a new geocache! How nice... ;)
         self::add_geocache_to_cached_tiles($theirs);
     } elseif ($ours[1] != $theirs[1] || $ours[2] != $theirs[2]) {
         # Location changed.
         self::remove_geocache_from_cached_tiles($ours[0]);
         self::add_geocache_to_cached_tiles($theirs);
     } elseif ($ours != $theirs) {
         self::update_geocache_attributes_in_cached_tiles($theirs);
     } else {
         # No need to update anything. This is very common (i.e. when the
         # cache was simply found, not actually changed). Replicate module generates
         # many updates which do not influence our cache.
     }
 }
 public static function call(OkapiRequest $request)
 {
     # Read the parameters.
     $langpref = $request->get_parameter('langpref');
     if (!$langpref) {
         $langpref = "en";
     }
     $fields = $request->get_parameter('fields');
     if (!$fields) {
         $fields = "name";
     }
     $only_locally_used = $request->get_parameter('only_locally_used');
     if (!$only_locally_used) {
         $only_locally_used = "false";
     }
     $only_locally_used = $only_locally_used == "true";
     # Get the list of attributes and filter the A-codes based on the
     # parameters.
     require_once 'attr_helper.inc.php';
     $attrdict = AttrHelper::get_attrdict();
     $acodes = array();
     foreach ($attrdict as $acode => &$attr_ref) {
         if ($only_locally_used && $attr_ref['internal_id'] === null) {
             /* Skip. */
             continue;
         }
         $acodes[] = $acode;
     }
     # Retrieve the attribute objects and return the results.
     if (count($acodes) > 0) {
         $params = array('acodes' => implode("|", $acodes), 'langpref' => $langpref, 'fields' => $fields);
         $results = OkapiServiceRunner::call('services/attrs/attributes', new OkapiInternalRequest($request->consumer, $request->token, $params));
     } else {
         $results = new ArrayObject();
     }
     return Okapi::formatted_response($request, $results);
 }
 public static function call(OkapiRequest $request)
 {
     $internal_ids = $request->get_parameter('internal_ids');
     if (!$internal_ids) {
         throw new ParamMissing('internal_ids');
     }
     $internal_ids = explode("|", $internal_ids);
     if (count($internal_ids) > 500) {
         throw new InvalidParam('internal_ids', "Maximum allowed number of referenced users " . "is 500. You provided " . count($internal_ids) . " references.");
     }
     $fields = $request->get_parameter('fields');
     if (!$fields) {
         throw new ParamMissing('fields');
     }
     # There's no need to validate the fields parameter as the 'users'
     # method does this (it will raise a proper exception on invalid values).
     $rs = Db::query("\n            select user_id, uuid\n            from user\n            where user_id in ('" . implode("','", array_map('mysql_real_escape_string', $internal_ids)) . "')\n        ");
     $internalid2useruuid = array();
     while ($row = mysql_fetch_assoc($rs)) {
         $internalid2useruuid[$row['user_id']] = $row['uuid'];
     }
     mysql_free_result($rs);
     # Retrieve data on given user_uuids.
     $id_results = OkapiServiceRunner::call('services/users/users', new OkapiInternalRequest($request->consumer, $request->token, array('user_uuids' => implode("|", array_values($internalid2useruuid)), 'fields' => $fields)));
     # Map user_uuids to internal_ids. Also check which internal_ids were not found
     # and mark them with null.
     $results = array();
     foreach ($internal_ids as $internal_id) {
         if (!isset($internalid2useruuid[$internal_id])) {
             $results[$internal_id] = null;
         } else {
             $results[$internal_id] = $id_results[$internalid2useruuid[$internal_id]];
         }
     }
     return Okapi::formatted_response($request, $results);
 }
Esempio n. 23
0
 /**
  * Register new OKAPI Consumer, send him an email with his key-pair, etc.
  * This method does not verify parameter values, check if they are in
  * a correct format prior the execution.
  */
 public static function register_new_consumer($appname, $appurl, $email)
 {
     require_once $GLOBALS['rootpath'] . "okapi/service_runner.php";
     $consumer = new OkapiConsumer(Okapi::generate_key(20), Okapi::generate_key(40), $appname, $appurl, $email);
     $sample_cache = OkapiServiceRunner::call("services/caches/search/all", new OkapiInternalRequest($consumer, null, array('limit', 1)));
     if (count($sample_cache['results']) > 0) {
         $sample_cache_code = $sample_cache['results'][0];
     } else {
         $sample_cache_code = "CACHECODE";
     }
     # Message for the Consumer.
     ob_start();
     print "This is the key-pair we have created for your application:\n\n";
     print "Consumer Key: {$consumer->key}\n";
     print "Consumer Secret: {$consumer->secret}\n\n";
     print "Note: Consumer Secret is needed only when you intend to use OAuth.\n";
     print "You don't need Consumer Secret for Level 1 Authentication.\n\n";
     print "Now you can easily access Level 1 OKAPI methods. E.g.:\n";
     print Settings::get('SITE_URL') . "okapi/services/caches/geocache?cache_code={$sample_cache_code}&consumer_key={$consumer->key}\n\n";
     print "If you plan on using OKAPI for a longer time, then you may want to\n";
     print "subscribe to the OKAPI News blog to stay up-to-date:\n";
     print "http://opencaching-api.blogspot.com/\n\n";
     print "Have fun!\n\n";
     print "-- \n";
     print "OKAPI Team\n";
     Okapi::mail_from_okapi($email, "Your OKAPI Consumer Key", ob_get_clean());
     # Message for the Admins.
     ob_start();
     print "Name: {$consumer->name}\n";
     print "Developer: {$consumer->email}\n";
     print $consumer->url ? "URL: {$consumer->url}\n" : "";
     print "Consumer Key: {$consumer->key}\n";
     Okapi::mail_admins("New OKAPI app registered!", ob_get_clean());
     Db::execute("\n            insert into okapi_consumers (`key`, name, secret, url, email, date_created)\n            values (\n                '" . mysql_real_escape_string($consumer->key) . "',\n                '" . mysql_real_escape_string($consumer->name) . "',\n                '" . mysql_real_escape_string($consumer->secret) . "',\n                '" . mysql_real_escape_string($consumer->url) . "',\n                '" . mysql_real_escape_string($consumer->email) . "',\n                now()\n            );\n        ");
 }
Esempio n. 24
0
 /**
  * Check if the URL can be safely retrieved. See issue #252.
  */
 private static function requireSafe($url)
 {
     require_once $GLOBALS['rootpath'] . 'okapi/service_runner.php';
     $installations = OkapiServiceRunner::call("services/apisrv/installations", new OkapiInternalRequest(new OkapiInternalConsumer(), null, array()));
     $allowed = array();
     foreach ($installations as $i) {
         $allowed_url = $i['okapi_base_url'] . "devel/dbstruct";
         $allowed[] = $allowed_url;
         if ($url == $allowed_url) {
             return;
         }
     }
     throw new BadRequest("The following URL is not on our whitelist: \"" . $url . "\".\n\n" . "Please use one of the following:\n" . "\"" . implode("\",\n\"", $allowed) . "\".");
 }
 /**
  * Generate OKAPI changelog entries. This method will call $feeder_method OKAPI
  * service with the following parameters: array($feeder_keys_param => implode('|', $key_values),
  * 'fields' => $fields). Then it will generate the changelog, based on the result.
  * This looks pretty much the same for various object types, that's why it's here.
  *
  * If $use_cache is true, then all the dictionaries from $feeder_method will be also
  * kept in OKAPI cache, for future comparison.
  *
  * In normal mode, update the changelog and don't return anything.
  * In fulldump mode, return the generated changelog entries *instead* of
  * updating it.
  */
 private static function generate_changelog_entries($feeder_method, $object_type, $feeder_keys_param, $key_name, $key_values, $fields, $fulldump_mode, $use_cache, $cache_timeout = 86400)
 {
     # Retrieve the previous versions of all objects from OKAPI cache.
     if ($use_cache) {
         $cache_keys1 = array();
         $cache_keys2 = array();
         foreach ($key_values as $key) {
             $cache_keys1[] = 'clog#' . $object_type . '#' . $key;
         }
         foreach ($key_values as $key) {
             $cache_keys2[] = 'clogmd5#' . $object_type . '#' . $key;
         }
         $cached_values1 = Cache::get_many($cache_keys1);
         $cached_values2 = Cache::get_many($cache_keys2);
         if (!$fulldump_mode) {
             Cache::delete_many($cache_keys1);
             Cache::delete_many($cache_keys2);
         }
         unset($cache_keys1);
         unset($cache_keys2);
     }
     # Get the current values for objects. Compare them with their previous versions
     # and generate changelog entries.
     require_once $GLOBALS['rootpath'] . 'okapi/service_runner.php';
     $current_values = OkapiServiceRunner::call($feeder_method, new OkapiInternalRequest(new OkapiInternalConsumer(), null, array($feeder_keys_param => implode("|", $key_values), 'fields' => $fields, 'attribution_append' => 'static')));
     $entries = array();
     foreach ($current_values as $key => $object) {
         if ($object !== null) {
             # Currently, the object exists.
             if ($use_cache) {
                 # First, compare the cached hash. The hash has much longer lifetime
                 # than the actual cached object.
                 $cached_md5 = $cached_values2['clogmd5#' . $object_type . '#' . $key];
                 $current_md5 = md5(serialize($object));
                 if ($cached_md5 == $current_md5) {
                     # The object was not changed since it was last replaced.
                     continue;
                 }
                 $diff = self::get_diff($cached_values1['clog#' . $object_type . '#' . $key], $object);
                 if (count($diff) == 0) {
                     # Md5 differs, but diff does not. Weird, but it can happen
                     # (e.g. just after the md5 extension was introduced, or if
                     # md5 somehow expired before the actual object did).
                     continue;
                 }
             }
             $entries[] = array('object_type' => $object_type, 'object_key' => array($key_name => $key), 'change_type' => 'replace', 'data' => $use_cache ? $diff : $object);
             if ($use_cache) {
                 # Save the last-published state of the object, for future comparison.
                 $cached_values2['clogmd5#' . $object_type . '#' . $key] = $current_md5;
                 $cached_values1['clog#' . $object_type . '#' . $key] = $object;
             }
         } else {
             # Currently, the object does not exist.
             if ($use_cache && $cached_values1['clog#' . $object_type . '#' . $key] === false) {
                 # No need to delete, we have already published its deletion.
                 continue;
             }
             $entries[] = array('object_type' => $object_type, 'object_key' => array($key_name => $key), 'change_type' => 'delete');
             if ($use_cache) {
                 # Cache the fact, that the object was deleted.
                 $cached_values2['clogmd5#' . $object_type . '#' . $key] = false;
                 $cached_values1['clog#' . $object_type . '#' . $key] = false;
             }
         }
     }
     if ($fulldump_mode) {
         return $entries;
     } else {
         # Save the entries to the clog table.
         if (count($entries) > 0) {
             $data_values = array();
             foreach ($entries as $entry) {
                 $data_values[] = gzdeflate(serialize($entry));
             }
             Db::execute("\n                    insert into okapi_clog (data)\n                    values ('" . implode("'),('", array_map('mysql_real_escape_string', $data_values)) . "');\n                ");
         }
         # Update the values kept in OKAPI cache.
         if ($use_cache) {
             Cache::set_many($cached_values1, $cache_timeout);
             Cache::set_many($cached_values2, null);
             # make it persistent
         }
     }
 }
Esempio n. 26
0
 public function execute()
 {
     ob_start();
     $apisrv_stats = OkapiServiceRunner::call('services/apisrv/stats', new OkapiInternalRequest(new OkapiInternalConsumer(), null, array()));
     $active_apps_count = Db::select_value("\n            select count(distinct s.consumer_key)\n            from\n                okapi_stats_hourly s,\n                okapi_consumers c\n            where\n                s.consumer_key = c.`key`\n                and s.period_start > date_add(now(), interval -7 day)\n        ");
     $weekly_stats = Db::select_row("\n            select\n                sum(s.http_calls) as total_http_calls,\n                sum(s.http_runtime) as total_http_runtime\n            from okapi_stats_hourly s\n            where\n                s.consumer_key != 'internal' -- we don't want to exclude 'anonymous' nor 'facade'\n                and s.period_start > date_add(now(), interval -7 day)\n        ");
     print "Hello! This is your weekly summary of OKAPI usage.\n\n";
     print "Apps active this week: " . $active_apps_count . " out of " . $apisrv_stats['apps_count'] . ".\n";
     print "Total of " . $weekly_stats['total_http_calls'] . " requests were made (" . sprintf("%01.1f", $weekly_stats['total_http_runtime']) . " seconds).\n\n";
     $consumers = Db::select_all("\n            select\n                s.consumer_key,\n                c.name,\n                sum(s.http_calls) as http_calls,\n                sum(s.http_runtime) as http_runtime\n            from\n                okapi_stats_hourly s\n                left join okapi_consumers c\n                    on s.consumer_key = c.`key`\n            where s.period_start > date_add(now(), interval -7 day)\n            group by s.consumer_key\n            having sum(s.http_calls) > 0\n            order by sum(s.http_calls) desc\n        ");
     print "== Consumers ==\n\n";
     print "Consumer name                         Calls     Runtime\n";
     print "----------------------------------- ------- -----------\n";
     foreach ($consumers as $row) {
         $name = $row['name'];
         if ($row['consumer_key'] == 'anonymous') {
             $name = "Anonymous (Level 0 Authentication)";
         } elseif ($row['consumer_key'] == 'facade') {
             $name = "Internal usage via Facade";
         }
         if (mb_strlen($name) > 35) {
             $name = mb_substr($name, 0, 32) . "...";
         }
         print self::mb_str_pad($name, 35, " ", STR_PAD_RIGHT);
         print str_pad($row['http_calls'], 8, " ", STR_PAD_LEFT);
         print str_pad(sprintf("%01.2f", $row['http_runtime']), 11, " ", STR_PAD_LEFT) . "s\n";
     }
     print "\n";
     $methods = Db::select_all("\n            select\n                s.service_name,\n                sum(s.http_calls) as http_calls,\n                sum(s.http_runtime) as http_runtime\n            from okapi_stats_hourly s\n            where s.period_start > date_add(now(), interval -7 day)\n            group by s.service_name\n            having sum(s.http_calls) > 0\n            order by sum(s.http_calls) desc\n        ");
     print "== Methods ==\n\n";
     print "Service name                          Calls     Runtime      Avg\n";
     print "----------------------------------- ------- ----------- --------\n";
     foreach ($methods as $row) {
         $name = $row['service_name'];
         if (mb_strlen($name) > 35) {
             $name = mb_substr($name, 0, 32) . "...";
         }
         print self::mb_str_pad($name, 35, " ", STR_PAD_RIGHT);
         print str_pad($row['http_calls'], 8, " ", STR_PAD_LEFT);
         print str_pad(sprintf("%01.2f", $row['http_runtime']), 11, " ", STR_PAD_LEFT) . "s";
         print str_pad(sprintf("%01.4f", $row['http_calls'] > 0 ? $row['http_runtime'] / $row['http_calls'] : 0), 8, " ", STR_PAD_LEFT) . "s\n";
     }
     print "\n";
     $oauth_users = Db::select_all("\n            select\n                c.name,\n                count(*) as users\n            from\n                okapi_authorizations a,\n                okapi_consumers c\n            where a.consumer_key = c.`key`\n            group by a.consumer_key\n            having count(*) >= 5\n            order by count(*) desc;\n        ");
     print "== Current OAuth usage by Consumers with at least 5 users ==\n\n";
     print "Consumer name                         Users\n";
     print "----------------------------------- -------\n";
     foreach ($oauth_users as $row) {
         $name = $row['name'];
         if (mb_strlen($name) > 35) {
             $name = mb_substr($name, 0, 32) . "...";
         }
         print self::mb_str_pad($name, 35, " ", STR_PAD_RIGHT);
         print str_pad($row['users'], 8, " ", STR_PAD_LEFT) . "\n";
     }
     print "\n";
     print "This report includes requests from external consumers and those made via\n";
     print "Facade class (used by OC code). It does not include methods used by OKAPI\n";
     print "internally (i.e. while running cronjobs). Runtimes do not include HTTP\n";
     print "request handling overhead.\n";
     $message = ob_get_clean();
     Okapi::mail_admins("Weekly OKAPI usage report", $message);
 }
Esempio n. 27
0
 /**
  * Load, parse and check common geocache search parameters (the ones
  * described in services/caches/search/all method) from $this->request.
  * Most cache search methods share a common set
  * of filtering parameters recognized by this method. It initalizes
  * search params, which can be further altered by calls to other methods
  * of this class, or outside of this class by a call to get_search_params();
  *
  * This method doesn't return anything. See get_search_params method.
  */
 public function prepare_common_search_params()
 {
     $where_conds = array('true');
     $extra_tables = array();
     $extra_joins = array();
     # At the beginning we have to set up some "magic e$Xpressions".
     # We will use them to make our query run on both OCPL and OCDE databases.
     if (Settings::get('OC_BRANCH') == 'oc.pl') {
         # OCPL's 'caches' table contains some fields which OCDE's does not
         # (topratings, founds, notfounds, last_found, votes, score). If
         # we're being run on OCPL installation, we will simply use them.
         $X_TOPRATINGS = 'caches.topratings';
         $X_FOUNDS = 'caches.founds';
         $X_NOTFOUNDS = 'caches.notfounds';
         $X_LAST_FOUND = 'caches.last_found';
         $X_VOTES = 'caches.votes';
         $X_SCORE = 'caches.score';
     } else {
         # OCDE holds this data in a separate table. Additionally, OCDE
         # does not provide a rating system (votes and score fields).
         # If we're being run on OCDE database, we will include this
         # additional table in our query and we will map the field
         # expressions to approriate places.
         # stat_caches entries are optional, therefore we must do a left join:
         $extra_joins[] = 'left join stat_caches on stat_caches.cache_id = caches.cache_id';
         $X_TOPRATINGS = 'ifnull(stat_caches.toprating,0)';
         $X_FOUNDS = 'ifnull(stat_caches.found,0)';
         $X_NOTFOUNDS = 'ifnull(stat_caches.notfound,0)';
         $X_LAST_FOUND = 'ifnull(stat_caches.last_found,0)';
         $X_VOTES = '0';
         // no support for ratings
         $X_SCORE = '0';
         // no support for ratings
     }
     #
     # type
     #
     if ($tmp = $this->request->get_parameter('type')) {
         $operator = "in";
         if ($tmp[0] == '-') {
             $tmp = substr($tmp, 1);
             $operator = "not in";
         }
         $types = array();
         foreach (explode("|", $tmp) as $name) {
             try {
                 $id = Okapi::cache_type_name2id($name);
                 $types[] = $id;
             } catch (Exception $e) {
                 throw new InvalidParam('type', "'{$name}' is not a valid cache type.");
             }
         }
         if (count($types) > 0) {
             $where_conds[] = "caches.type {$operator} ('" . implode("','", array_map('mysql_real_escape_string', $types)) . "')";
         } else {
             if ($operator == "in") {
                 $where_conds[] = "false";
             }
         }
     }
     #
     # size2
     #
     if ($tmp = $this->request->get_parameter('size2')) {
         $operator = "in";
         if ($tmp[0] == '-') {
             $tmp = substr($tmp, 1);
             $operator = "not in";
         }
         $types = array();
         foreach (explode("|", $tmp) as $name) {
             try {
                 $id = Okapi::cache_size2_to_sizeid($name);
                 $types[] = $id;
             } catch (Exception $e) {
                 throw new InvalidParam('size2', "'{$name}' is not a valid cache size.");
             }
         }
         $where_conds[] = "caches.size {$operator} ('" . implode("','", array_map('mysql_real_escape_string', $types)) . "')";
     }
     #
     # status - filter by status codes
     #
     $tmp = $this->request->get_parameter('status');
     if ($tmp == null) {
         $tmp = "Available";
     }
     $codes = array();
     foreach (explode("|", $tmp) as $name) {
         try {
             $codes[] = Okapi::cache_status_name2id($name);
         } catch (Exception $e) {
             throw new InvalidParam('status', "'{$name}' is not a valid cache status.");
         }
     }
     $where_conds[] = "caches.status in ('" . implode("','", array_map('mysql_real_escape_string', $codes)) . "')";
     #
     # owner_uuid
     #
     if ($tmp = $this->request->get_parameter('owner_uuid')) {
         $operator = "in";
         if ($tmp[0] == '-') {
             $tmp = substr($tmp, 1);
             $operator = "not in";
         }
         try {
             $users = OkapiServiceRunner::call("services/users/users", new OkapiInternalRequest($this->request->consumer, null, array('user_uuids' => $tmp, 'fields' => 'internal_id')));
         } catch (InvalidParam $e) {
             throw new InvalidParam('owner_uuid', $e->whats_wrong_about_it);
         }
         $user_ids = array();
         foreach ($users as $user) {
             $user_ids[] = $user['internal_id'];
         }
         $where_conds[] = "caches.user_id {$operator} ('" . implode("','", array_map('mysql_real_escape_string', $user_ids)) . "')";
     }
     #
     # terrain, difficulty, size, rating - these are similar, we'll do them in a loop
     #
     foreach (array('terrain', 'difficulty', 'size', 'rating') as $param_name) {
         if ($tmp = $this->request->get_parameter($param_name)) {
             if (!preg_match("/^[1-5]-[1-5](\\|X)?\$/", $tmp)) {
                 throw new InvalidParam($param_name, "'{$tmp}'");
             }
             list($min, $max) = explode("-", $tmp);
             if (strpos($max, "|X") !== false) {
                 $max = $max[0];
                 $allow_null = true;
             } else {
                 $allow_null = false;
             }
             if ($min > $max) {
                 throw new InvalidParam($param_name, "'{$tmp}'");
             }
             switch ($param_name) {
                 case 'terrain':
                     if ($allow_null) {
                         throw new InvalidParam($param_name, "The '|X' suffix is not allowed here.");
                     }
                     if ($min == 1 && $max == 5) {
                         /* no extra condition necessary */
                     } else {
                         $where_conds[] = "caches.terrain between 2*{$min} and 2*{$max}";
                     }
                     break;
                 case 'difficulty':
                     if ($allow_null) {
                         throw new InvalidParam($param_name, "The '|X' suffix is not allowed here.");
                     }
                     if ($min == 1 && $max == 5) {
                         /* no extra condition necessary */
                     } else {
                         $where_conds[] = "caches.difficulty between 2*{$min} and 2*{$max}";
                     }
                     break;
                 case 'size':
                     # Deprecated. Leave it for backward-compatibility. See issue 155.
                     if ($min == 1 && $max == 5 && $allow_null) {
                         # No extra condition necessary ('other' caches will be
                         # included).
                     } else {
                         # 'other' size caches will NOT be included (user must use the
                         # 'size2' parameter to search these). 'nano' caches will be
                         # included whenever 'micro' caches are included ($min=1).
                         $where_conds[] = "(caches.size between {$min}+1 and {$max}+1)" . ($allow_null ? " or caches.size=7" : "") . ($min == 1 ? " or caches.size=8" : "");
                     }
                     break;
                 case 'rating':
                     if (Settings::get('OC_BRANCH') == 'oc.pl') {
                         if ($min == 1 && $max == 5 && $allow_null) {
                             /* no extra condition necessary */
                         } else {
                             $divisors = array(-999, -1.0, 0.1, 1.4, 2.2, 999);
                             $min = $divisors[$min - 1];
                             $max = $divisors[$max];
                             $where_conds[] = "({$X_SCORE} >= {$min} and {$X_SCORE} < {$max} and {$X_VOTES} >= 3)" . ($allow_null ? " or ({$X_VOTES} < 3)" : "");
                         }
                     } else {
                         # OCDE does not support rating. We will ignore this parameter.
                     }
                     break;
             }
         }
     }
     #
     # min_rcmds
     #
     if ($tmp = $this->request->get_parameter('min_rcmds')) {
         if ($tmp[strlen($tmp) - 1] == '%') {
             $tmp = substr($tmp, 0, strlen($tmp) - 1);
             if (!is_numeric($tmp)) {
                 throw new InvalidParam('min_rcmds', "'{$tmp}'");
             }
             $tmp = intval($tmp);
             if ($tmp > 100 || $tmp < 0) {
                 throw new InvalidParam('min_rcmds', "'{$tmp}'");
             }
             $tmp = floatval($tmp) / 100.0;
             $where_conds[] = "{$X_TOPRATINGS} >= {$X_FOUNDS} * '" . mysql_real_escape_string($tmp) . "'";
             $where_conds[] = "{$X_FOUNDS} > 0";
         }
         if (!is_numeric($tmp)) {
             throw new InvalidParam('min_rcmds', "'{$tmp}'");
         }
         $where_conds[] = "{$X_TOPRATINGS} >= '" . mysql_real_escape_string($tmp) . "'";
     }
     #
     # min_founds
     #
     if ($tmp = $this->request->get_parameter('min_founds')) {
         if (!is_numeric($tmp)) {
             throw new InvalidParam('min_founds', "'{$tmp}'");
         }
         $where_conds[] = "{$X_FOUNDS} >= '" . mysql_real_escape_string($tmp) . "'";
     }
     #
     # max_founds
     # may be '0' for FTF hunts
     #
     if (!is_null($tmp = $this->request->get_parameter('max_founds'))) {
         if (!is_numeric($tmp)) {
             throw new InvalidParam('max_founds', "'{$tmp}'");
         }
         $where_conds[] = "{$X_FOUNDS} <= '" . mysql_real_escape_string($tmp) . "'";
     }
     #
     # modified_since
     #
     if ($tmp = $this->request->get_parameter('modified_since')) {
         $timestamp = strtotime($tmp);
         if ($timestamp) {
             $where_conds[] = "unix_timestamp(caches.last_modified) > '" . mysql_real_escape_string($timestamp) . "'";
         } else {
             throw new InvalidParam('modified_since', "'{$tmp}' is not in a valid format or is not a valid date.");
         }
     }
     #
     # found_status
     #
     if ($tmp = $this->request->get_parameter('found_status')) {
         if ($this->request->token == null) {
             throw new InvalidParam('found_status', "Might be used only for requests signed with an Access Token.");
         }
         if (!in_array($tmp, array('found_only', 'notfound_only', 'either'))) {
             throw new InvalidParam('found_status', "'{$tmp}'");
         }
         if ($tmp != 'either') {
             $found_cache_ids = self::get_found_cache_ids($this->request->token->user_id);
             $operator = $tmp == 'found_only' ? "in" : "not in";
             $where_conds[] = "caches.cache_id {$operator} ('" . implode("','", array_map('mysql_real_escape_string', $found_cache_ids)) . "')";
         }
     }
     #
     # found_by
     #
     if ($tmp = $this->request->get_parameter('found_by')) {
         try {
             $user = OkapiServiceRunner::call("services/users/user", new OkapiInternalRequest($this->request->consumer, null, array('user_uuid' => $tmp, 'fields' => 'internal_id')));
         } catch (InvalidParam $e) {
             # invalid uuid
             throw new InvalidParam('found_by', $e->whats_wrong_about_it);
         }
         $found_cache_ids = self::get_found_cache_ids($user['internal_id']);
         $where_conds[] = "caches.cache_id in ('" . implode("','", array_map('mysql_real_escape_string', $found_cache_ids)) . "')";
     }
     #
     # not_found_by
     #
     if ($tmp = $this->request->get_parameter('not_found_by')) {
         try {
             $user = OkapiServiceRunner::call("services/users/user", new OkapiInternalRequest($this->request->consumer, null, array('user_uuid' => $tmp, 'fields' => 'internal_id')));
         } catch (InvalidParam $e) {
             # invalid uuid
             throw new InvalidParam('not_found_by', $e->whats_wrong_about_it);
         }
         $found_cache_ids = self::get_found_cache_ids($user['internal_id']);
         $where_conds[] = "caches.cache_id not in ('" . implode("','", array_map('mysql_real_escape_string', $found_cache_ids)) . "')";
     }
     #
     # watched_only
     #
     if ($tmp = $this->request->get_parameter('watched_only')) {
         if ($this->request->token == null) {
             throw new InvalidParam('watched_only', "Might be used only for requests signed with an Access Token.");
         }
         if (!in_array($tmp, array('true', 'false'))) {
             throw new InvalidParam('watched_only', "'{$tmp}'");
         }
         if ($tmp == 'true') {
             $watched_cache_ids = Db::select_column("\n                    select cache_id\n                    from cache_watches\n                    where user_id = '" . mysql_real_escape_string($this->request->token->user_id) . "'\n                ");
             if (Settings::get('OC_BRANCH') == 'oc.de') {
                 $watched_cache_ids = array_merge($watched_cache_ids, Db::select_column("\n                        select cache_id\n                        from cache_list_items cli, cache_list_watches clw\n                        where cli.cache_list_id = clw.cache_list_id\n                        and clw.user_id = '" . mysql_real_escape_string($this->request->token->user_id) . "'\n                    "));
             }
             $where_conds[] = "caches.cache_id in ('" . implode("','", array_map('mysql_real_escape_string', $watched_cache_ids)) . "')";
         }
     }
     #
     # exclude_ignored
     #
     if ($tmp = $this->request->get_parameter('exclude_ignored')) {
         if ($this->request->token == null) {
             throw new InvalidParam('exclude_ignored', "Might be used only for requests signed with an Access Token.");
         }
         if (!in_array($tmp, array('true', 'false'))) {
             throw new InvalidParam('exclude_ignored', "'{$tmp}'");
         }
         if ($tmp == 'true') {
             $ignored_cache_ids = Db::select_column("\n                    select cache_id\n                    from cache_ignore\n                    where user_id = '" . mysql_real_escape_string($this->request->token->user_id) . "'\n                ");
             $where_conds[] = "caches.cache_id not in ('" . implode("','", array_map('mysql_real_escape_string', $ignored_cache_ids)) . "')";
         }
     }
     #
     # exclude_my_own
     #
     if ($tmp = $this->request->get_parameter('exclude_my_own')) {
         if ($this->request->token == null) {
             throw new InvalidParam('exclude_my_own', "Might be used only for requests signed with an Access Token.");
         }
         if (!in_array($tmp, array('true', 'false'))) {
             throw new InvalidParam('exclude_my_own', "'{$tmp}'");
         }
         if ($tmp == 'true') {
             $where_conds[] = "caches.user_id != '" . mysql_real_escape_string($this->request->token->user_id) . "'";
         }
     }
     #
     # name
     #
     if ($tmp = $this->request->get_parameter('name')) {
         # WRTODO: Make this more user-friendly. See:
         # https://github.com/opencaching/okapi/issues/121
         if (strlen($tmp) > 100) {
             throw new InvalidParam('name', "Maximum length of 'name' parameter is 100 characters");
         }
         $tmp = str_replace("*", "%", str_replace("%", "%%", $tmp));
         $where_conds[] = "caches.name LIKE '" . mysql_real_escape_string($tmp) . "'";
     }
     #
     # with_trackables_only
     #
     if ($tmp = $this->request->get_parameter('with_trackables_only')) {
         if (!in_array($tmp, array('true', 'false'), 1)) {
             throw new InvalidParam('with_trackables_only', "'{$tmp}'");
         }
         if ($tmp == 'true') {
             $where_conds[] = "\n                    caches.wp_oc in (\n                        select distinct wp\n                        from gk_item_waypoint\n                    )\n                ";
         }
     }
     #
     # ftf_hunter
     #
     if ($tmp = $this->request->get_parameter('ftf_hunter')) {
         if (!in_array($tmp, array('true', 'false'), 1)) {
             throw new InvalidParam('ftf_hunter', "'{$tmp}'");
         }
         if ($tmp == 'true') {
             $where_conds[] = "{$X_FOUNDS} = 0";
         }
     }
     #
     # powertrail_only, powertrail_ids
     #
     $join_powertrails = false;
     if ($tmp = $this->request->get_parameter('powertrail_only')) {
         if ($tmp === 'true') {
             $join_powertrails = true;
         } elseif ($tmp === 'false') {
             $join_powertrails = false;
         } else {
             throw new InvalidParam('powertrail_only', "Boolean expected, '{$tmp}' found.");
         }
     }
     $powertrail_ids = $this->request->get_parameter('powertrail_ids');
     if ($powertrail_ids) {
         $join_powertrails = true;
     }
     if ($join_powertrails) {
         if (Settings::get('OC_BRANCH') == 'oc.pl') {
             $extra_tables[] = "powerTrail_caches";
             $extra_tables[] = "PowerTrail";
             $where_conds[] = "powerTrail_caches.cacheId = caches.cache_id";
             $where_conds[] = "PowerTrail.id = powerTrail_caches.powerTrailId";
             $where_conds[] = 'PowerTrail.status = 1';
             if ($powertrail_ids) {
                 $where_conds[] = "PowerTrail.id in ('" . implode("','", array_map('mysql_real_escape_string', explode("|", $powertrail_ids))) . "')";
             }
         } else {
             $where_conds[] = "0=1";
         }
     }
     unset($powertrail_ids, $join_powertrails);
     #
     # set_and
     #
     if ($tmp = $this->request->get_parameter('set_and')) {
         # Check if the set exists.
         $exists = Db::select_value("\n                select 1\n                from okapi_search_sets\n                where id = '" . mysql_real_escape_string($tmp) . "'\n            ");
         if (!$exists) {
             throw new InvalidParam('set_and', "Couldn't find a set by given ID.");
         }
         $extra_tables[] = "okapi_search_results osr_and";
         $where_conds[] = "osr_and.cache_id = caches.cache_id";
         $where_conds[] = "osr_and.set_id = '" . mysql_real_escape_string($tmp) . "'";
     }
     #
     # limit
     #
     $limit = $this->request->get_parameter('limit');
     if ($limit == null) {
         $limit = "100";
     }
     if (!is_numeric($limit)) {
         throw new InvalidParam('limit', "'{$limit}'");
     }
     if ($limit < 1 || $limit > 500 && !$this->request->skip_limits) {
         throw new InvalidParam('limit', $this->request->skip_limits ? "Cannot be lower than 1." : "Has to be between 1 and 500.");
     }
     #
     # offset
     #
     $offset = $this->request->get_parameter('offset');
     if ($offset == null) {
         $offset = "0";
     }
     if (!is_numeric($offset)) {
         throw new InvalidParam('offset', "'{$offset}'");
     }
     if ($offset + $limit > 500 && !$this->request->skip_limits) {
         throw new BadRequest("The sum of offset and limit may not exceed 500.");
     }
     if ($offset < 0 || $offset > 499 && !$this->request->skip_limits) {
         throw new InvalidParam('offset', $this->request->skip_limits ? "Cannot be lower than 0." : "Has to be between 0 and 499.");
     }
     #
     # order_by
     #
     $order_clauses = array();
     $order_by = $this->request->get_parameter('order_by');
     if ($order_by != null) {
         $order_by = explode('|', $order_by);
         foreach ($order_by as $field) {
             $dir = 'asc';
             if ($field[0] == '-') {
                 $dir = 'desc';
                 $field = substr($field, 1);
             } elseif ($field[0] == '+') {
                 $field = substr($field, 1);
             }
             # ignore leading "+"
             switch ($field) {
                 case 'code':
                     $cl = "caches.wp_oc";
                     break;
                 case 'name':
                     $cl = "caches.name";
                     break;
                 case 'founds':
                     $cl = "{$X_FOUNDS}";
                     break;
                 case 'rcmds':
                     $cl = "{$X_TOPRATINGS}";
                     break;
                 case 'rcmds%':
                     $cl = "{$X_TOPRATINGS} / if({$X_FOUNDS} = 0, 1, {$X_FOUNDS})";
                     break;
                 default:
                     throw new InvalidParam('order_by', "Unsupported field '{$field}'");
             }
             $order_clauses[] = "({$cl}) {$dir}";
         }
     }
     # To avoid join errors, put each of the $where_conds in extra paranthesis.
     $tmp = array();
     foreach ($where_conds as $cond) {
         $tmp[] = "(" . $cond . ")";
     }
     $where_conds = $tmp;
     unset($tmp);
     $ret_array = array('where_conds' => $where_conds, 'offset' => (int) $offset, 'limit' => (int) $limit, 'order_by' => $order_clauses, 'extra_tables' => $extra_tables, 'extra_joins' => $extra_joins);
     if ($this->search_params === NULL) {
         $this->search_params = $ret_array;
     } else {
         $this->search_params = array_merge_recursive($this->search_params, $ret_array);
     }
 }
Esempio n. 28
0
 /**
  * Precache the ($zoom, $x, $y) slot in the okapi_tile_caches table.
  */
 public static function compute_tile($zoom, $x, $y)
 {
     $time_started = microtime(true);
     # Note, that multiple threads may try to compute tiles simulatanously.
     # For low-level tiles, this can be expensive.
     $status = self::get_tile_status($zoom, $x, $y);
     if ($status !== null) {
         return $status;
     }
     if ($zoom === 0) {
         # When computing zoom zero, we don't have a parent to speed up
         # the computation. We need to use the caches table. Note, that
         # zoom level 0 contains *entire world*, so we don't have to use
         # any WHERE condition in the following query.
         # This can be done a little faster (without the use of internal requests),
         # but there is *no need* to - this query is run seldom and is cached.
         $params = array();
         $params['status'] = "Available|Temporarily unavailable|Archived";
         # we want them all
         $params['limit'] = "10000000";
         # no limit
         $internal_request = new OkapiInternalRequest(new OkapiInternalConsumer(), null, $params);
         $internal_request->skip_limits = true;
         $response = OkapiServiceRunner::call("services/caches/search/all", $internal_request);
         $cache_codes = $response['results'];
         $internal_request = new OkapiInternalRequest(new OkapiInternalConsumer(), null, array('cache_codes' => implode('|', $cache_codes), 'fields' => 'internal_id|code|name|location|type|status|rating|recommendations|founds|trackables_count'));
         $internal_request->skip_limits = true;
         $caches = OkapiServiceRunner::call("services/caches/geocaches", $internal_request);
         foreach ($caches as $cache) {
             $row = self::generate_short_row($cache);
             if (!$row) {
                 /* Some caches cannot be included, e.g. the ones near the poles. */
                 continue;
             }
             Db::execute("\n                    replace into okapi_tile_caches (\n                        z, x, y, cache_id, z21x, z21y, status, type, rating, flags, name_crc\n                    ) values (\n                        0, 0, 0,\n                        '" . Db::escape_string($row[0]) . "',\n                        '" . Db::escape_string($row[1]) . "',\n                        '" . Db::escape_string($row[2]) . "',\n                        '" . Db::escape_string($row[3]) . "',\n                        '" . Db::escape_string($row[4]) . "',\n                        " . ($row[5] === null ? "null" : "'" . Db::escape_string($row[5]) . "'") . ",\n                        '" . Db::escape_string($row[6]) . "',\n                        '" . Db::escape_string($row[7]) . "'\n                    );\n                ");
         }
         $status = 2;
     } else {
         # We will use the parent tile to compute the contents of this tile.
         $parent_zoom = $zoom - 1;
         $parent_x = $x >> 1;
         $parent_y = $y >> 1;
         $status = self::get_tile_status($parent_zoom, $parent_x, $parent_y);
         if ($status === null) {
             $time_started = microtime(true);
             $status = self::compute_tile($parent_zoom, $parent_x, $parent_y);
         }
         if ($status === 1) {
             # No need to check.
         } else {
             $scale = 8 + 21 - $zoom;
             $parentcenter_z21x = ($parent_x << 1 | 1) << $scale;
             $parentcenter_z21y = ($parent_y << 1 | 1) << $scale;
             $margin = 1 << $scale - 2;
             $left_z21x = ($parent_x << 1 << $scale) - $margin;
             $right_z21x = ($parent_x + 1 << 1 << $scale) + $margin;
             $top_z21y = ($parent_y << 1 << $scale) - $margin;
             $bottom_z21y = ($parent_y + 1 << 1 << $scale) + $margin;
             # Choose the right quarter.
             # |1 2|
             # |3 4|
             if ($x & 1) {
                 # 2 or 4
                 $left_z21x = $parentcenter_z21x - $margin;
             } else {
                 # 1 or 3
                 $right_z21x = $parentcenter_z21x + $margin;
             }
             if ($y & 1) {
                 # 3 or 4
                 $top_z21y = $parentcenter_z21y - $margin;
             } else {
                 # 1 or 2
                 $bottom_z21y = $parentcenter_z21y + $margin;
             }
             # Cache the result.
             # Avoid deadlocks, see https://github.com/opencaching/okapi/issues/388
             Db::execute("lock tables okapi_tile_caches write, okapi_tile_caches tc2 read");
             Db::execute("\n                    replace into okapi_tile_caches (\n                        z, x, y, cache_id, z21x, z21y, status, type, rating,\n                        flags, name_crc\n                    )\n                    select\n                        '" . Db::escape_string($zoom) . "',\n                        '" . Db::escape_string($x) . "',\n                        '" . Db::escape_string($y) . "',\n                        cache_id, z21x, z21y, status, type, rating,\n                        flags, name_crc\n                    from okapi_tile_caches tc2\n                    where\n                        z = '" . Db::escape_string($parent_zoom) . "'\n                        and x = '" . Db::escape_string($parent_x) . "'\n                        and y = '" . Db::escape_string($parent_y) . "'\n                        and z21x between {$left_z21x} and {$right_z21x}\n                        and z21y between {$top_z21y} and {$bottom_z21y}\n                ");
             Db::execute("unlock tables");
             $test = Db::select_value("\n                    select 1\n                    from okapi_tile_caches\n                    where\n                        z = '" . Db::escape_string($zoom) . "'\n                        and x = '" . Db::escape_string($x) . "'\n                        and y = '" . Db::escape_string($y) . "'\n                    limit 1;\n                ");
             if ($test) {
                 $status = 2;
             } else {
                 $status = 1;
             }
         }
     }
     # Mark tile as computed.
     Db::execute("\n            replace into okapi_tile_status (z, x, y, status)\n            values (\n                '" . Db::escape_string($zoom) . "',\n                '" . Db::escape_string($x) . "',\n                '" . Db::escape_string($y) . "',\n                '" . Db::escape_string($status) . "'\n            );\n        ");
     return $status;
 }
Esempio n. 29
0
 public static function call(OkapiRequest $request)
 {
     $cache_codes = $request->get_parameter('cache_codes');
     if ($cache_codes === null) {
         throw new ParamMissing('cache_codes');
     }
     # Issue 106 requires us to allow empty list of cache codes to be passed into this method.
     # All of the queries below have to be ready for $cache_codes to be empty!
     $langpref = $request->get_parameter('langpref');
     if (!$langpref) {
         $langpref = "en|" . Settings::get('SITELANG');
     }
     $images = $request->get_parameter('images');
     if (!$images) {
         $images = "all";
     }
     if (!in_array($images, array("none", "all", "spoilers", "nonspoilers"))) {
         throw new InvalidParam('images');
     }
     $format = $request->get_parameter('caches_format');
     if (!$format) {
         $format = "gpx";
     }
     if (!in_array($format, array("gpx", "ggz"))) {
         throw new InvalidParam('caches_format');
     }
     $location_source = $request->get_parameter('location_source');
     $location_change_prefix = $request->get_parameter('location_change_prefix');
     # Start creating ZIP archive.
     $response = new OkapiZIPHttpResponse();
     # Include a GPX/GGZ file compatible with Garmin devices. It should include all
     # Geocaching.com (groundspeak:) and Opencaching.com (ox:) extensions. It will
     # also include image references (actual images will be added as separate files later)
     # and personal data (if the method was invoked using Level 3 Authentication).
     switch ($format) {
         case 'gpx':
             $data_filename = "Garmin/GPX/opencaching" . time() . rand(100000, 999999) . ".gpx";
             $data_method = 'services/caches/formatters/gpx';
             $data_use_compression = true;
             break;
         case 'ggz':
             $data_filename = "Garmin/GGZ/opencaching" . time() . rand(100000, 999999) . ".ggz";
             $data_method = 'services/caches/formatters/ggz';
             $data_use_compression = false;
             break;
     }
     $response->zip->FileAdd($data_filename, OkapiServiceRunner::call($data_method, new OkapiInternalRequest($request->consumer, $request->token, array('cache_codes' => $cache_codes, 'langpref' => $langpref, 'ns_ground' => 'true', 'ns_ox' => 'true', 'images' => 'ox:all', 'attrs' => 'ox:tags', 'trackables' => 'desc:count', 'alt_wpts' => 'true', 'recommendations' => 'desc:count', 'latest_logs' => 'true', 'lpc' => 'all', 'my_notes' => $request->token != null ? "desc:text" : "none", 'location_source' => $location_source, 'location_change_prefix' => $location_change_prefix)))->get_body(), clsTbsZip::TBSZIP_STRING, $data_use_compression);
     # Then, include all the images.
     $caches = OkapiServiceRunner::call('services/caches/geocaches', new OkapiInternalRequest($request->consumer, $request->token, array('cache_codes' => $cache_codes, 'langpref' => $langpref, 'fields' => "images")));
     if (count($caches) > 50) {
         throw new InvalidParam('cache_codes', "The maximum number of caches allowed to be downloaded with this method is 50.");
     }
     if ($images != 'none') {
         $supported_extensions = array('jpg', 'jpeg', 'gif', 'png', 'bmp');
         foreach ($caches as $cache_code => $dict) {
             $imgs = $dict['images'];
             if (count($imgs) == 0) {
                 continue;
             }
             $dir = "Garmin/GeocachePhotos/" . $cache_code[strlen($cache_code) - 1];
             $dir .= "/" . $cache_code[strlen($cache_code) - 2];
             $dir .= "/" . $cache_code;
             foreach ($imgs as $no => $img) {
                 if ($images == 'spoilers' && !$img['is_spoiler']) {
                     continue;
                 }
                 if ($images == 'nonspoilers' && $img['is_spoiler']) {
                     continue;
                 }
                 $tmp = false;
                 foreach ($supported_extensions as $ext) {
                     if (strtolower(substr($img['url'], strlen($img['url']) - strlen($ext) - 1)) != "." . $ext) {
                         $tmp = true;
                         continue;
                     }
                 }
                 if (!$tmp) {
                     continue;
                 }
                 # unsupported file extension
                 if ($img['is_spoiler']) {
                     $zippath = $dir . "/Spoilers/" . $img['unique_caption'] . ".jpg";
                 } else {
                     $zippath = $dir . "/" . $img['unique_caption'] . ".jpg";
                 }
                 # The safest way would be to use the URL, but that would be painfully slow!
                 # That's why we're trying to access files directly (and fail silently on error).
                 # This was tested on OCPL server only.
                 # Note: Oliver Dietz (oc.de) replied that images with 'local' set to 0 could not
                 # be accessed locally. But all the files have 'local' set to 1 anyway.
                 $syspath = Settings::get('IMAGES_DIR') . "/" . $img['uuid'] . ".jpg";
                 if (file_exists($syspath)) {
                     $response->zip->FileAdd($zippath, $syspath, clsTbsZip::TBSZIP_FILE, false);
                 } else {
                     # If file exists, but does not end with ".jpg", we will create
                     # JPEG version of it and store it in the cache.
                     $cache_key = "jpg#" . $img['uuid'];
                     $jpeg_contents = Cache::get($cache_key);
                     if ($jpeg_contents === null) {
                         foreach ($supported_extensions as $ext) {
                             $syspath_other = Settings::get('IMAGES_DIR') . "/" . $img['uuid'] . "." . $ext;
                             if (file_exists($syspath_other)) {
                                 try {
                                     $image = imagecreatefromstring(file_get_contents($syspath_other));
                                     ob_start();
                                     imagejpeg($image);
                                     $jpeg_contents = ob_get_clean();
                                     imagedestroy($image);
                                 } catch (Exception $e) {
                                     # GD couldn't parse the file. We will skip it, and cache
                                     # the "false" value as the contents. This way, we won't
                                     # attempt to parse it during the next 24 hours.
                                     $jpeg_contents = false;
                                 }
                                 Cache::set($cache_key, $jpeg_contents, 86400);
                                 break;
                             }
                         }
                     }
                     if ($jpeg_contents) {
                         # This can be "null" *or* "false"!
                         $response->zip->FileAdd($zippath, $jpeg_contents, clsTbsZip::TBSZIP_STRING, false);
                     }
                 }
             }
         }
     }
     # The result could be big, but it's created and streamed right
     # to the browser, so it shouldn't hit our memory limit. We also
     # should set a higher time limit, because downloading this response
     # may take some time over slow network connections (and I'm not sure
     # what is the PHP's default way of handling such scenario).
     set_time_limit(600);
     $response->content_type = "application/zip";
     $response->content_disposition = 'attachment; filename="results.zip"';
     return $response;
 }
Esempio n. 30
0
 /**
  * Generate a GPX file.
  *
  * @param OkapiRequest $request
  * @param integer $flags
  * @throws BadRequest
  * @return An array with GPX file content under 'gpx' key
  */
 public static function create_gpx(OkapiRequest $request, $flags = null)
 {
     $vars = array();
     # Validating arguments. We will also assign some of them to the
     # $vars variable which we will use later in the GPS template.
     $cache_codes = $request->get_parameter('cache_codes');
     if ($cache_codes === null) {
         throw new ParamMissing('cache_codes');
     }
     # Issue 106 requires us to allow empty list of cache codes to be passed into this method.
     # All of the queries below have to be ready for $cache_codes to be empty!
     $langpref = $request->get_parameter('langpref');
     if (!$langpref) {
         $langpref = "en";
     }
     $langpref .= "|" . Settings::get('SITELANG');
     foreach (array('ns_ground', 'ns_gsak', 'ns_ox', 'latest_logs', 'alt_wpts', 'mark_found') as $param) {
         $val = $request->get_parameter($param);
         if (!$val) {
             $val = "false";
         } elseif (!in_array($val, array("true", "false"))) {
             throw new InvalidParam($param);
         }
         $vars[$param] = $val == "true";
     }
     if ($vars['latest_logs'] && !$vars['ns_ground']) {
         throw new BadRequest("In order for 'latest_logs' to work you have to also include 'ns_ground' extensions.");
     }
     $tmp = $request->get_parameter('my_notes');
     $vars['my_notes'] = array();
     if ($tmp && $tmp != 'none') {
         $tmp = explode('|', $tmp);
         foreach ($tmp as $elem) {
             if ($elem == 'none') {
                 /* pass */
             } elseif (in_array($elem, array('desc:text', 'gc:personal_note'))) {
                 if (in_array('none', $tmp)) {
                     throw new InvalidParam('my_notes', "You cannot mix 'none' and '{$elem}'");
                 }
                 if ($request->token == null) {
                     throw new BadRequest("Level 3 Authentication is required to access my_notes data.");
                 }
                 $vars['my_notes'][] = $elem;
             } else {
                 throw new InvalidParam('my_notes', "Invalid list entry: '{$elem}'");
             }
         }
     }
     $images = $request->get_parameter('images');
     if (!$images) {
         $images = 'descrefs:nonspoilers';
     }
     if (!in_array($images, array('none', 'descrefs:thumblinks', 'descrefs:nonspoilers', 'descrefs:all', 'ox:all'))) {
         throw new InvalidParam('images', "'{$images}'");
     }
     $vars['images'] = $images;
     $tmp = $request->get_parameter('attrs');
     if (!$tmp) {
         $tmp = 'desc:text';
     }
     $tmp = explode("|", $tmp);
     $vars['attrs'] = array();
     foreach ($tmp as $elem) {
         if ($elem == 'none') {
             /* pass */
         } elseif (in_array($elem, array('desc:text', 'ox:tags', 'gc:attrs', 'gc_ocde:attrs'))) {
             if ($elem == 'gc_ocde:attrs' && Settings::get('OC_BRANCH') != 'oc.de') {
                 $vars['attrs'][] = 'gc:attrs';
             } else {
                 $vars['attrs'][] = $elem;
             }
         } else {
             throw new InvalidParam('attrs', "Invalid list entry: '{$elem}'");
         }
     }
     $protection_areas = $request->get_parameter('protection_areas');
     if (!$protection_areas || $protection_areas == 'desc:auto') {
         if (Settings::get('OC_BRANCH') == 'oc.de') {
             $protection_areas = 'desc:text';
         } else {
             $protection_areas = 'none';
         }
     }
     if (!in_array($protection_areas, array('none', 'desc:text'))) {
         throw new InvalidParam('protection_areas', "'{$protection_areas}'");
     }
     $vars['protection_areas'] = $protection_areas;
     $tmp = $request->get_parameter('trackables');
     if (!$tmp) {
         $tmp = 'none';
     }
     if (!in_array($tmp, array('none', 'desc:list', 'desc:count'))) {
         throw new InvalidParam('trackables', "'{$tmp}'");
     }
     $vars['trackables'] = $tmp;
     $tmp = $request->get_parameter('recommendations');
     if (!$tmp) {
         $tmp = 'none';
     }
     if (!in_array($tmp, array('none', 'desc:count'))) {
         throw new InvalidParam('recommendations', "'{$tmp}'");
     }
     $vars['recommendations'] = $tmp;
     $lpc = $request->get_parameter('lpc');
     if ($lpc === null) {
         $lpc = 10;
     }
     # will be checked in services/caches/geocaches call
     $user_uuid = $request->get_parameter('user_uuid');
     # location_source (part 1 of 2)
     $location_source = $request->get_parameter('location_source');
     if (!$location_source) {
         $location_source = 'default-coords';
     }
     # Make sure location_source has prefix alt_wpt:
     if ($location_source != 'default-coords' && strncmp($location_source, 'alt_wpt:', 8) != 0) {
         throw new InvalidParam('location_source', '\'' . $location_source . '\'');
     }
     # Make sure we have sufficient authorization
     if ($location_source == 'alt_wpt:user-coords' && $request->token == null) {
         throw new BadRequest("Level 3 Authentication is required to access 'alt_wpt:user-coords'.");
     }
     # Which fields of the services/caches/geocaches method do we need?
     $fields = 'code|name|location|date_created|url|type|status|size|size2|oxsize' . '|difficulty|terrain|description|hint2|rating|owner|url|internal_id' . '|protection_areas|short_description';
     if ($vars['images'] != 'none') {
         $fields .= "|images";
     }
     if (count($vars['attrs']) > 0) {
         $fields .= "|attrnames|attr_acodes";
     }
     if ($vars['trackables'] == 'desc:list') {
         $fields .= "|trackables";
     } elseif ($vars['trackables'] == 'desc:count') {
         $fields .= "|trackables_count";
     }
     if ($vars['alt_wpts'] == 'true' || $location_source != 'default-coords') {
         $fields .= "|alt_wpts";
     }
     if ($vars['recommendations'] != 'none') {
         $fields .= "|recommendations|founds";
     }
     if (count($vars['my_notes']) > 0) {
         $fields .= "|my_notes";
     }
     if ($vars['latest_logs']) {
         $fields .= "|latest_logs";
     }
     if ($vars['mark_found']) {
         $fields .= "|is_found";
     }
     $vars['caches'] = OkapiServiceRunner::call('services/caches/geocaches', new OkapiInternalRequest($request->consumer, $request->token, array('cache_codes' => $cache_codes, 'langpref' => $langpref, 'fields' => $fields, 'lpc' => $lpc, 'user_uuid' => $user_uuid, 'log_fields' => 'uuid|date|user|type|comment|internal_id|was_recommended')));
     # Get rid of invalid cache references.
     $valid = array();
     foreach ($vars['caches'] as $key => &$ref) {
         if ($ref !== null) {
             $valid[$key] =& $ref;
         }
     }
     $vars['caches'] =& $valid;
     unset($valid);
     # Get all the other data need.
     $vars['installation'] = OkapiServiceRunner::call('services/apisrv/installation', new OkapiInternalRequest(new OkapiInternalConsumer(), null, array()));
     $vars['cache_GPX_types'] = self::$cache_GPX_types;
     $vars['cache_GPX_sizes'] = self::$cache_GPX_sizes;
     if (count($vars['attrs']) > 0) {
         /* The user asked for some kind of attribute output. We'll fetch all
          * the data we MAY need. This is often far too much, but thanks to
          * caching, it will work fast. */
         $vars['attr_index'] = OkapiServiceRunner::call('services/attrs/attribute_index', new OkapiInternalRequest($request->consumer, $request->token, array('only_locally_used' => 'true', 'langpref' => $langpref, 'fields' => 'name|gc_equivs')));
         # prepare GS attribute data
         $vars['gc_attrs'] = in_array('gc:attrs', $vars['attrs']);
         $vars['gc_ocde_attrs'] = in_array('gc_ocde:attrs', $vars['attrs']);
         if ($vars['gc_attrs'] || $vars['gc_ocde_attrs']) {
             if ($vars['gc_ocde_attrs']) {
                 # As this is an OCDE compatibility feature, we use the same Pseudo-GS
                 # attribute names here as OCDE. Note that this code is specific to OCDE
                 # database; OCPL stores attribute names in a different way and may use
                 # different names for equivalent attributes.
                 $ocde_attrnames = Db::select_group_by('id', "\n                        select id, name\n                        from cache_attrib\n                    ");
                 $attr_dict = AttrHelper::get_attrdict();
             }
             foreach ($vars['caches'] as &$cache_ref) {
                 $cache_ref['gc_attrs'] = array();
                 foreach ($cache_ref['attr_acodes'] as $acode) {
                     $has_gc_equivs = false;
                     foreach ($vars['attr_index'][$acode]['gc_equivs'] as $gc) {
                         # The assignment via GC-ID as array key will prohibit duplicate
                         # GC attributes, which can result from
                         # - assigning the same GC ID to multiple A-Codes,
                         # - contradicting attributes in one OC listing, e.g. 24/4 + not 24/7.
                         $cache_ref['gc_attrs'][$gc['id']] = $gc;
                         $has_gc_equivs = true;
                     }
                     if (!$has_gc_equivs && $vars['gc_ocde_attrs']) {
                         # Generate an OCDE pseudo-GS attribute;
                         # see https://github.com/opencaching/okapi/issues/190 and
                         # https://github.com/opencaching/okapi/issues/271.
                         #
                         # Groundspeak uses ID 1..65 (as of June, 2013), and OCDE makeshift
                         # IDs start at 106, so there is space for 40 new GS attributes.
                         $internal_id = $attr_dict[$acode]['internal_id'];
                         $cache_ref['gc_attrs'][100 + $internal_id] = array('inc' => 1, 'name' => $ocde_attrnames[$internal_id][0]['name']);
                     }
                 }
             }
         }
     }
     /* OC sites always used internal user_ids in their generated GPX files.
      * This might be considered an error in itself (Groundspeak's XML namespace
      * doesn't allow that), but it very common (Garmin's OpenCaching.COM
      * also does that). Therefore, for backward-compatibility reasons, OKAPI
      * will do it the same way. See issue 174.
      *
      * Currently, the caches method does not expose "owner.internal_id" and
      * "latest_logs.user.internal_id" fields, we will read them manually
      * from the database here. */
     $dict = array();
     foreach ($vars['caches'] as &$cache_ref) {
         $dict[$cache_ref['owner']['uuid']] = true;
         if (isset($cache_ref['latest_logs'])) {
             foreach ($cache_ref['latest_logs'] as &$log_ref) {
                 $dict[$log_ref['user']['uuid']] = true;
             }
         }
     }
     $rs = Db::query("\n            select uuid, user_id\n            from user\n            where uuid in ('" . implode("','", array_map('mysql_real_escape_string', array_keys($dict))) . "')\n        ");
     while ($row = mysql_fetch_assoc($rs)) {
         $dict[$row['uuid']] = $row['user_id'];
     }
     $vars['user_uuid_to_internal_id'] =& $dict;
     unset($dict);
     # location_source (part 2 of 2)
     if ($location_source != 'default-coords') {
         $location_change_prefix = $request->get_parameter('location_change_prefix');
         if (!$location_change_prefix) {
             $location_change_prefix = '# ';
         }
         # lets find requested coords
         foreach ($vars['caches'] as &$cache_ref) {
             foreach ($cache_ref['alt_wpts'] as $alt_wpt_key => $alt_wpt) {
                 if ('alt_wpt:' . $alt_wpt['type'] == $location_source) {
                     # Switch locations between primary wpt and alternate wpt.
                     # Also alter the cache name and make sure to append a proper
                     # notice.
                     $original_location = $cache_ref['location'];
                     $cache_ref['location'] = $alt_wpt['location'];
                     $cache_ref['name_2'] = $location_change_prefix . $cache_ref['name'];
                     if ($location_source == "alt_wpt:user-coords") {
                         # In case of "user-coords", replace the default warning with a custom-tailored one.
                         $cache_ref['warning_prefix'] = _("<b>Geocache coordinates have been changed.</b> They have been replaced with " . "your own custom coordinates which you have provided for this geocache.");
                     } else {
                         # Default warning
                         $cache_ref['warning_prefix'] = _("<b>Geocache coordinates have been changed.</b> Currently they " . "point to one of the alternate waypoints originally described as:") . " " . $alt_wpt['description'];
                     }
                     # remove current alt waypoint
                     unset($cache_ref['alt_wpts'][$alt_wpt_key]);
                     # add original location as alternate
                     if ($vars['alt_wpts']) {
                         $cache_ref['alt_wpts'][] = array('name' => $cache_ref['code'] . '-DEFAULT-COORDS', 'location' => $original_location, 'type' => 'default-coords', 'type_name' => _("Original geocache location"), 'sym' => 'Block, Blue', 'description' => sprintf(_("Original (owner-supplied) location of the %s geocache"), $cache_ref['code']));
                     }
                     break;
                 }
             }
         }
     }
     # Do we need a GGZ index?
     if ($flags & self::FLAG_CREATE_GGZ_IDX) {
         # GGZ index consist of entries - one per each waypoint in the GPX file.
         # We will keep a list of all such entries here.
         $ggz_entries = array();
         foreach ($vars['caches'] as &$cache_ref) {
             # Every $cache_ref will also be holding a reference to its entry.
             # Note, that more attributes are added while processing gpsfile.tpl.php!
             if (!isset($cache_ref['ggz_entry'])) {
                 $cache_ref['ggz_entry'] = array();
             }
             $ggz_entry =& $cache_ref['ggz_entry'];
             $ggz_entries[] =& $ggz_entry;
             $ggz_entry['code'] = $cache_ref['code'];
             $ggz_entry['name'] = isset($cache_ref['name_2']) ? $cache_ref['name_2'] : $cache_ref['name'];
             $ggz_entry['type'] = $vars['cache_GPX_types'][$cache_ref['type']];
             list($lat, $lon) = explode("|", $cache_ref['location']);
             $ggz_entry['lat'] = $lat;
             $ggz_entry['lon'] = $lon;
             $ggz_entry['ratings'] = array();
             $ratings_ref =& $ggz_entry['ratings'];
             if (isset($cache_ref['rating'])) {
                 $ratings_ref['awesomeness'] = $cache_ref['rating'];
             }
             $ratings_ref['difficulty'] = $cache_ref['difficulty'];
             if (!isset($cache_ref['size'])) {
                 $ratings_ref['size'] = 0;
                 // Virtual, Event
             } else {
                 if ($cache_ref['oxsize'] !== null) {
                     // is this ox size one-to-one?
                     $ratings_ref['size'] = $cache_ref['oxsize'];
                 }
             }
             $ratings_ref['terrain'] = $cache_ref['terrain'];
             if ($vars['mark_found'] && $cache_ref['is_found']) {
                 $ggz_entry['found'] = true;
             }
             # Additional waypoints. Currently, we're not 100% sure if their entries should
             # be included in the GGZ file (the format is undocumented).
             if (isset($cache_ref['alt_wpts'])) {
                 $idx = 1;
                 foreach ($cache_ref['alt_wpts'] as &$alt_wpt_ref) {
                     if (!isset($alt_wpt_ref['ggz_entry'])) {
                         $alt_wpt_ref['ggz_entry'] = array();
                     }
                     $ggz_entry =& $alt_wpt_ref['ggz_entry'];
                     $ggz_entries[] =& $ggz_entry;
                     $ggz_entry['code'] = $cache_ref['code'] . '-' . $idx;
                     $ggz_entry['name'] = $alt_wpt_ref['type_name'];
                     $ggz_entry['type'] = $alt_wpt_ref['sym'];
                     list($lat, $lon) = explode("|", $alt_wpt_ref['location']);
                     $ggz_entry['lat'] = $lat;
                     $ggz_entry['lon'] = $lon;
                     $idx++;
                 }
             }
         }
     }
     ob_start();
     Okapi::gettext_domain_init(explode("|", $langpref));
     # Consumer gets properly localized GPX file.
     include 'gpxfile.tpl.php';
     Okapi::gettext_domain_restore();
     $result = array('gpx' => ob_get_clean());
     if ($flags & self::FLAG_CREATE_GGZ_IDX) {
         $result['ggz_entries'] = $ggz_entries;
     }
     return $result;
 }