Example #1
0
 public static function call()
 {
     $langpref = isset($_GET['langpref']) ? $_GET['langpref'] : Settings::get('SITELANG');
     $langprefs = explode("|", $langpref);
     # Determine which user is logged in to OC.
     require_once $GLOBALS['rootpath'] . "okapi/lib/oc_session.php";
     $OC_user_id = OCSession::get_user_id();
     if ($OC_user_id == null) {
         $after_login = "******" . ($langpref != Settings::get('SITELANG') ? "?langpref=" . $langpref : "");
         $login_url = Settings::get('SITE_URL') . "login.php?target=" . urlencode($after_login);
         return new OkapiRedirectResponse($login_url);
     }
     # Get the list of authorized apps.
     $rs = Db::query("\n            select c.`key`, c.name, c.url\n            from\n                okapi_consumers c,\n                okapi_authorizations a\n            where\n                a.user_id = '" . mysql_real_escape_string($OC_user_id) . "'\n                and c.`key` = a.consumer_key\n            order by c.name\n        ");
     $vars = array();
     $vars['okapi_base_url'] = Settings::get('SITE_URL') . "okapi/";
     $vars['site_url'] = Settings::get('SITE_URL');
     $vars['site_name'] = Okapi::get_normalized_site_name();
     $vars['site_logo'] = Settings::get('SITE_LOGO');
     $vars['apps'] = array();
     while ($row = mysql_fetch_assoc($rs)) {
         $vars['apps'][] = $row;
     }
     mysql_free_result($rs);
     $response = new OkapiHttpResponse();
     $response->content_type = "text/html; charset=utf-8";
     ob_start();
     Okapi::gettext_domain_init($langprefs);
     include 'index.tpl.php';
     $response->body = ob_get_clean();
     Okapi::gettext_domain_restore();
     return $response;
 }
Example #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);
 }
Example #3
0
 static function call(OkapiRequest $request)
 {
     require_once 'log_images_common.inc.php';
     list($image_uuid, $log_internal_id) = LogImagesCommon::validate_image_uuid($request);
     $image_uuid_escaped = Db::escape_string($image_uuid);
     Db::execute('start transaction');
     $image_row = Db::select_row("\n            select id, node, url, local\n            from pictures\n            where uuid = '" . $image_uuid_escaped . "'\n        ");
     Db::execute("\n            delete from pictures where uuid = '" . $image_uuid_escaped . "'\n        ");
     # Remember that OCPL picture sequence numbers are always 1, and
     # OCDE sequence numbers may have gaps. So we do not need to adjust
     # any numbers after deleting from table 'pictures'.
     if (Settings::get('OC_BRANCH') == 'oc.de') {
         # OCDE does all the housekeeping by triggers
     } else {
         Db::execute("\n                INSERT INTO removed_objects (\n                    localID, uuid, type, removed_date, node\n                )\n                VALUES (\n                    " . $image_row['id'] . "\n                    '" . $image_uuid_escaped . "',\n                    6,\n                    NOW(),\n                    " . $image_row['node'] . "\n                )\n            ");
         # This will also update cache_logs.okapi_syncbase, so that replication
         # can output the updated log entry with one image less. For OCDE
         # that's done by DB trigges.
         Db::execute("\n                update cache_logs\n                set\n                    picturescount = greatest(0, picturescount - 1),\n                    last_modified = NOW()\n                where id = '" . Db::escape_string($log_internal_id) . "'\n            ");
     }
     Db::execute('commit');
     if ($image_row['local']) {
         $filename = basename($image_row['url']);
         unlink(Settings::get('IMAGES_DIR') . '/' . $filename);
     }
     $result = array('success' => true);
     return Okapi::formatted_response($request, $result);
 }
Example #4
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);
 }
Example #5
0
 public static function call(OkapiRequest $request)
 {
     $cachekey = "apisrv/stats";
     $result = Cache::get($cachekey);
     if (!$result) {
         $result = array('cache_count' => 0 + Db::select_value("\n                    select count(*) from caches where status in (1,2,3)\n                "), 'user_count' => 0 + Db::select_value("\n                    select count(*) from (\n                        select distinct user_id\n                        from cache_logs\n                        where\n                            type in (1,2,7)\n                            and " . (Settings::get('OC_BRANCH') == 'oc.pl' ? "deleted = 0" : "true") . "\n                        UNION DISTINCT\n                        select distinct user_id\n                        from caches\n                    ) as t;\n                "), 'apps_count' => 0 + Db::select_value("select count(*) from okapi_consumers;"), 'apps_active' => 0 + 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 -30 day)\n                "));
         Cache::set($cachekey, $result, 86400);
         # cache it for one day
     }
     return Okapi::formatted_response($request, $result);
 }
Example #6
0
 public static function call()
 {
     if (!isset($_GET['id'])) {
         throw new ParamMissing("id");
     }
     $tmp = Db::select_value("\n            select data\n            from okapi_clog\n            where id='" . Db::escape_string($_GET['id']) . "'\n        ");
     $data = unserialize(gzinflate($tmp));
     $response = new OkapiHttpResponse();
     $response->content_type = "application/json; charset=utf-8";
     $response->body = json_encode($data);
     return $response;
 }
 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;
             }
         }
     }
 }
Example #8
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);
 }
Example #9
0
 public static function call()
 {
     # Determine which user is logged in to OC.
     require_once $GLOBALS['rootpath'] . "okapi/lib/oc_session.php";
     $OC_user_id = OCSession::get_user_id();
     # Ensure a user is logged in.
     if ($OC_user_id == null) {
         $after_login = "******";
         # it is correct, if you're wondering
         $login_url = Settings::get('SITE_URL') . "login.php?target=" . urlencode($after_login);
         return new OkapiRedirectResponse($login_url);
     }
     $consumer_key = isset($_REQUEST['consumer_key']) ? $_REQUEST['consumer_key'] : '';
     # Just remove app (if it doesn't exist - nothing wrong will happen anyway).
     Db::execute("\n            delete from okapi_tokens\n            where\n                user_id = '" . Db::escape_string($OC_user_id) . "'\n                and consumer_key = '" . Db::escape_string($consumer_key) . "'\n        ");
     Db::execute("\n            delete from okapi_authorizations\n            where\n                user_id = '" . Db::escape_string($OC_user_id) . "'\n                and consumer_key = '" . Db::escape_string($consumer_key) . "'\n        ");
     # Redirect back to the apps page.
     return new OkapiRedirectResponse(Settings::get('SITE_URL') . "okapi/apps/");
 }
Example #10
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);
 }
Example #11
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);
 }
 public static function call()
 {
     $token_key = isset($_GET['oauth_token']) ? $_GET['oauth_token'] : '';
     $verifier = isset($_GET['oauth_verifier']) ? $_GET['oauth_verifier'] : '';
     $langpref = isset($_GET['langpref']) ? $_GET['langpref'] : Settings::get('SITELANG');
     $langprefs = explode("|", $langpref);
     $token = Db::select_row("\n            select\n                c.`key` as consumer_key,\n                c.name as consumer_name,\n                c.url as consumer_url,\n                t.verifier\n            from\n                okapi_consumers c,\n                okapi_tokens t\n            where\n                t.`key` = '" . mysql_real_escape_string($token_key) . "'\n                and t.consumer_key = c.`key`\n        ");
     if (!$token) {
         # Probably Request Token has expired or it was already used. We'll
         # just redirect to the Opencaching main page.
         return new OkapiRedirectResponse(Settings::get('SITE_URL'));
     }
     $vars = array('okapi_base_url' => Settings::get('SITE_URL') . "okapi/", 'token' => $token, 'verifier' => $verifier, 'site_name' => Okapi::get_normalized_site_name(), 'site_url' => Settings::get('SITE_URL'), 'site_logo' => Settings::get('SITE_LOGO'));
     $response = new OkapiHttpResponse();
     $response->content_type = "text/html; charset=utf-8";
     ob_start();
     Okapi::gettext_domain_init($langprefs);
     include 'authorized.tpl.php';
     $response->body = ob_get_clean();
     Okapi::gettext_domain_restore();
     return $response;
 }
 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);
 }
Example #14
0
 public function __construct($options)
 {
     Okapi::init_internals();
     $this->init_request();
     #
     # Parsing options.
     #
     $DEBUG_AS_USERNAME = null;
     foreach ($options as $key => $value) {
         switch ($key) {
             case 'min_auth_level':
                 if (!in_array($value, array(0, 1, 2, 3))) {
                     throw new Exception("'min_auth_level' option has invalid value: {$value}");
                 }
                 $this->opt_min_auth_level = $value;
                 break;
             case 'token_type':
                 if (!in_array($value, array("request", "access"))) {
                     throw new Exception("'token_type' option has invalid value: {$value}");
                 }
                 $this->opt_token_type = $value;
                 break;
             case 'DEBUG_AS_USERNAME':
                 $DEBUG_AS_USERNAME = $value;
                 break;
             default:
                 throw new Exception("Unknown option: {$key}");
                 break;
         }
     }
     if ($this->opt_min_auth_level === null) {
         throw new Exception("Required 'min_auth_level' option is missing.");
     }
     if ($DEBUG_AS_USERNAME != null) {
         # Enables debugging Level 2 and Level 3 methods. Should not be committed
         # at any time! If run on production server, make it an error.
         if (!Settings::get('DEBUG')) {
             throw new Exception("Attempted to use DEBUG_AS_USERNAME in " . "non-debug environment. Accidental commit?");
         }
         # Lower required authentication to Level 0, to pass the checks.
         $this->opt_min_auth_level = 0;
     }
     #
     # Let's see if the request is signed. If it is, verify the signature.
     # It it's not, check if it isn't against the rules defined in the $options.
     #
     if ($this->get_parameter('oauth_signature')) {
         # User is using OAuth.
         # Check for duplicate keys in the parameters. (Datastore doesn't
         # do that on its own, it caused vague server errors - issue #307.)
         $this->get_parameter('oauth_consumer');
         $this->get_parameter('oauth_version');
         $this->get_parameter('oauth_token');
         $this->get_parameter('oauth_nonce');
         # Verify OAuth request.
         list($this->consumer, $this->token) = Okapi::$server->verify_request2($this->request, $this->opt_token_type, $this->opt_min_auth_level == 3);
         if ($this->get_parameter('consumer_key') && $this->get_parameter('consumer_key') != $this->get_parameter('oauth_consumer_key')) {
             throw new BadRequest("Inproper mixing of authentication types. You used both 'consumer_key' " . "and 'oauth_consumer_key' parameters (Level 1 and Level 2), but they do not match with " . "each other. Were you trying to hack me? ;)");
         }
         if ($this->opt_min_auth_level == 3 && !$this->token) {
             throw new BadRequest("This method requires a valid Token to be included (Level 3 " . "Authentication). You didn't provide one.");
         }
     } else {
         if ($this->opt_min_auth_level >= 2) {
             throw new BadRequest("This method requires OAuth signature (Level " . $this->opt_min_auth_level . " Authentication). You didn't sign your request.");
         } else {
             $consumer_key = $this->get_parameter('consumer_key');
             if ($consumer_key) {
                 $this->consumer = Okapi::$data_store->lookup_consumer($consumer_key);
                 if (!$this->consumer) {
                     throw new InvalidParam('consumer_key', "Consumer does not exist.");
                 }
             }
             if ($this->opt_min_auth_level == 1 && !$this->consumer) {
                 throw new BadRequest("This method requires the 'consumer_key' argument (Level 1 " . "Authentication). You didn't provide one.");
             }
         }
     }
     if (is_object($this->consumer) && $this->consumer->hasFlag(OkapiConsumer::FLAG_SKIP_LIMITS)) {
         $this->skip_limits = true;
     }
     #
     # Prevent developers from accessing request parameters with PHP globals.
     # Remember, that OKAPI requests can be nested within other OKAPI requests!
     # Search the code for "new OkapiInternalRequest" to see examples.
     #
     $_GET = $_POST = $_REQUEST = null;
     # When debugging, simulate as if been run using a proper Level 3 Authentication.
     if ($DEBUG_AS_USERNAME != null) {
         # Note, that this will override any other valid authentication the
         # developer might have issued.
         $debug_user_id = Db::select_value("select user_id from user where username='******'DEBUG_AS_USERNAME']) . "'");
         if ($debug_user_id == null) {
             throw new Exception("Invalid user name in DEBUG_AS_USERNAME: '******'DEBUG_AS_USERNAME'] . "'");
         }
         $this->consumer = new OkapiDebugConsumer();
         $this->token = new OkapiDebugAccessToken($debug_user_id);
     }
     # Read the ETag.
     if (isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
         $this->etag = $_SERVER['HTTP_IF_NONE_MATCH'];
     }
 }
Example #15
0
 /**
  * Get an array of all site-specific log-types (id => name in English).
  */
 private static function get_all_logtypes()
 {
     if (Settings::get('OC_BRANCH') == 'oc.pl') {
         # OCPL branch does not store cache types in many languages (just two).
         $rs = Db::query("select id, en from log_types order by id");
     } else {
         # OCDE branch uses translation tables.
         $rs = Db::query("\n                select\n                    lt.id,\n                    stt.text as en\n                from\n                    log_types lt\n                    left join sys_trans_text stt\n                        on lt.trans_id = stt.trans_id\n                        and stt.lang = 'EN'\n                order by lt.id\n            ");
     }
     $dict = array();
     while ($row = mysql_fetch_assoc($rs)) {
         $dict[$row['id']] = $row['en'];
     }
     return $dict;
 }
Example #16
0
 public static function call(OkapiRequest $request)
 {
     # You may wonder, why there are no parameters like "bbox" or "center" in the
     # "search/all" method. This is *intentional* and should be kept this way.
     # Such parameters would fall in conflict with each other and - in result -
     # make the documentation very fuzzy. That's why they were intentionally
     # left out of the "search/all" method, and put in separate (individual) ones.
     # It's much easier to grasp their meaning this way.
     $tmp = $request->get_parameter('bbox');
     if (!$tmp) {
         throw new ParamMissing('bbox');
     }
     $parts = explode('|', $tmp);
     if (count($parts) != 4) {
         throw new InvalidParam('bbox', "Expecting 4 pipe-separated parts, got " . count($parts) . ".");
     }
     foreach ($parts as &$part_ref) {
         if (!preg_match("/^-?[0-9]+(\\.?[0-9]*)\$/", $part_ref)) {
             throw new InvalidParam('bbox', "'{$part_ref}' is not a valid float number.");
         }
         $part_ref = floatval($part_ref);
     }
     list($bbsouth, $bbwest, $bbnorth, $bbeast) = $parts;
     if ($bbnorth <= $bbsouth) {
         throw new InvalidParam('bbox', "Northern edge must be situated to the north of the southern edge.");
     }
     if ($bbeast == $bbwest) {
         throw new InvalidParam('bbox', "Eastern edge longitude is the same as the western one.");
     }
     if ($bbnorth > 90 || $bbnorth < -90 || $bbsouth > 90 || $bbsouth < -90) {
         throw new InvalidParam('bbox', "Latitudes have to be within -90..90 range.");
     }
     if ($bbeast > 180 || $bbeast < -180 || $bbwest > 180 || $bbwest < -180) {
         throw new InvalidParam('bbox', "Longitudes have to be within -180..180 range.");
     }
     # Construct SQL conditions for the specified bounding box.
     $search_assistant = new SearchAssistant($request);
     $search_assistant->prepare_common_search_params();
     $search_assistant->prepare_location_search_params();
     $where_conds = array();
     $lat = $search_assistant->get_latitude_expr();
     $lon = $search_assistant->get_longitude_expr();
     $where_conds[] = "(\n            {$lat} >= '" . Db::escape_string($bbsouth) . "'\n            and {$lat} < '" . Db::escape_string($bbnorth) . "'\n        )";
     if ($bbeast > $bbwest) {
         # Easy one.
         $where_conds[] = "(\n                {$lon} >= '" . Db::escape_string($bbwest) . "'\n                and {$lon} < '" . Db::escape_string($bbeast) . "'\n            )";
     } else {
         # We'll have to assume that this bbox goes through the 180-degree meridian.
         # For example, $bbwest = 179 and $bbeast = -179.
         $where_conds[] = "(\n                {$lon} >= '" . Db::escape_string($bbwest) . "'\n                or {$lon} < '" . Db::escape_string($bbeast) . "'\n            )";
     }
     #
     # In the method description, we promised to return caches ordered by the *rough*
     # distance from the center of the bounding box. We'll use ORDER BY with a simplified
     # distance formula and combine it with the LIMIT clause to get the best results.
     #
     $center_lat = ($bbsouth + $bbnorth) / 2.0;
     $center_lon = ($bbwest + $bbeast) / 2.0;
     $search_params = $search_assistant->get_search_params();
     $search_params['where_conds'] = array_merge($where_conds, $search_params['where_conds']);
     $search_params['order_by'][] = Okapi::get_distance_sql($center_lat, $center_lon, $search_assistant->get_latitude_expr(), $search_assistant->get_longitude_expr());
     # not replaced; added to the end!
     $search_assistant->set_search_params($search_params);
     $result = $search_assistant->get_common_search_result();
     return Okapi::formatted_response($request, $result);
 }
 /**
  * Generate a new fulldump file and put it into the OKAPI cache table.
  * Return the cache key.
  */
 public static function generate_fulldump()
 {
     # First we will create temporary files, then compress them in the end.
     $revision = self::get_revision();
     $generated_at = date('c', time());
     $dir = Okapi::get_var_dir() . "/okapi-db-dump";
     $i = 1;
     $json_files = array();
     # Cleanup (from a previous, possibly unsuccessful, execution)
     shell_exec("rm -f {$dir}/*");
     shell_exec("rmdir {$dir}");
     shell_exec("mkdir {$dir}");
     shell_exec("chmod 777 {$dir}");
     # Geocaches
     $cache_codes = Db::select_column("select wp_oc from caches");
     $cache_code_groups = Okapi::make_groups($cache_codes, self::$chunk_size);
     unset($cache_codes);
     foreach ($cache_code_groups as $cache_codes) {
         $basename = "part" . str_pad($i, 5, "0", STR_PAD_LEFT);
         $json_files[] = $basename . ".json";
         $entries = self::generate_changelog_entries('services/caches/geocaches', 'geocache', 'cache_codes', 'code', $cache_codes, self::$logged_cache_fields, true, false);
         $filtered = array();
         foreach ($entries as $entry) {
             if ($entry['change_type'] == 'replace') {
                 $filtered[] = $entry;
             }
         }
         unset($entries);
         file_put_contents("{$dir}/{$basename}.json", json_encode($filtered));
         unset($filtered);
         $i++;
     }
     unset($cache_code_groups);
     # Log entries. We cannot load all the uuids at one time, this would take
     # too much memory. Hence the offset/limit loop.
     $offset = 0;
     while (true) {
         $log_uuids = Db::select_column("\n                select uuid\n                from cache_logs\n                where " . (Settings::get('OC_BRANCH') == 'oc.pl' ? "deleted = 0" : "true") . "\n                order by uuid\n                limit {$offset}, 10000\n            ");
         if (count($log_uuids) == 0) {
             break;
         }
         $offset += 10000;
         $log_uuid_groups = Okapi::make_groups($log_uuids, 500);
         unset($log_uuids);
         foreach ($log_uuid_groups as $log_uuids) {
             $basename = "part" . str_pad($i, 5, "0", STR_PAD_LEFT);
             $json_files[] = $basename . ".json";
             $entries = self::generate_changelog_entries('services/logs/entries', 'log', 'log_uuids', 'uuid', $log_uuids, self::$logged_log_entry_fields, true, false);
             $filtered = array();
             foreach ($entries as $entry) {
                 if ($entry['change_type'] == 'replace') {
                     $filtered[] = $entry;
                 }
             }
             unset($entries);
             file_put_contents("{$dir}/{$basename}.json", json_encode($filtered));
             unset($filtered);
             $i++;
         }
     }
     # Package data.
     $metadata = array('revision' => $revision, 'data_files' => $json_files, 'meta' => array('site_name' => Okapi::get_normalized_site_name(), 'okapi_version_number' => Okapi::$version_number, 'okapi_revision' => Okapi::$version_number, 'okapi_git_revision' => Okapi::$git_revision, 'generated_at' => $generated_at));
     file_put_contents("{$dir}/index.json", json_encode($metadata));
     # Compute uncompressed size.
     $size = filesize("{$dir}/index.json");
     foreach ($json_files as $filename) {
         $size += filesize("{$dir}/{$filename}");
     }
     # Create JSON archive. We use tar options: -j for bzip2, -z for gzip
     # (bzip2 is MUCH slower).
     $use_bzip2 = true;
     $dumpfilename = "okapi-dump.tar." . ($use_bzip2 ? "bz2" : "gz");
     shell_exec("tar --directory {$dir} -c" . ($use_bzip2 ? "j" : "z") . "f {$dir}/{$dumpfilename} index.json " . implode(" ", $json_files) . " 2>&1");
     # Delete temporary files.
     shell_exec("rm -f {$dir}/*.json");
     # Move the archive one directory upwards, replacing the previous one.
     # Remove the temporary directory.
     shell_exec("mv -f {$dir}/{$dumpfilename} " . Okapi::get_var_dir());
     shell_exec("rmdir {$dir}");
     # Update the database info.
     $metadata['meta']['filepath'] = Okapi::get_var_dir() . '/' . $dumpfilename;
     $metadata['meta']['content_type'] = $use_bzip2 ? "application/octet-stream" : "application/x-gzip";
     $metadata['meta']['public_filename'] = 'okapi-dump-r' . $metadata['revision'] . '.tar.' . ($use_bzip2 ? "bz2" : "gz");
     $metadata['meta']['uncompressed_size'] = $size;
     $metadata['meta']['compressed_size'] = filesize($metadata['meta']['filepath']);
     Cache::set("last_fulldump", $metadata, 10 * 86400);
 }
Example #18
0
 public function execute()
 {
     Db::query("optimize table okapi_tile_caches");
     Db::query("optimize table okapi_tile_status");
 }
Example #19
0
 public function cleanup()
 {
     Db::execute("\n            delete from okapi_nonces\n            where\n                timestamp < unix_timestamp(date_add(now(), interval -6 minute))\n                or timestamp > unix_timestamp(date_add(now(), interval 6 minute))\n        ");
     Db::execute("\n            delete from okapi_tokens\n            where\n                token_type = 'request'\n                and timestamp < unix_timestamp(date_add(now(), interval -2 hour))\n        ");
 }
Example #20
0
 private function loadSearchData($searchData)
 {
     \okapi\OkapiErrorHandler::reenable();
     // We need to transform OC's "searchdata" into OKAPI's "search set".
     // First, we need to determine if we ALREADY did that.
     // Note, that this is not exactly thread-efficient. Multiple threads may
     // do this transformation in the same time. However, this is done only once
     // for each searchdata, so we will ignore it.
     $cache_key = "OC_searchdata_" . $searchData;
     $set_id = \okapi\Cache::get($cache_key);
     if ($set_id === null) {
         // Read the searchdata file into a temporary table.
         $filepath = \okapi\Settings::get('VAR_DIR') . "/searchdata/" . $searchData;
         \okapi\Db::execute("\n            create temporary table temp_" . $searchData . " (\n                cache_id integer primary key\n            ) engine=memory\n        ");
         if (file_exists($filepath)) {
             \okapi\Db::execute("\n                        load data local infile '{$filepath}'\n                        into table temp_" . $searchData . "\n                fields terminated by ' '\n                lines terminated by '\\n'\n                (cache_id)\n            ");
         }
         // Tell OKAPI to import the table into its own internal structures.
         // Cache it for two hours.
         $set_info = \okapi\Facade::import_search_set("temp_" . $searchData, 7200, 7200);
         $set_id = $set_info['set_id'];
         \okapi\Cache::set($cache_key, $set_id, 7200);
     }
     $this->search_params['set_and'] = $set_id;
     $this->search_params['status'] = "Available|Temporarily unavailable|Archived";
     \okapi\OkapiErrorHandler::disable();
     return true;
 }
Example #21
0
 public static function call(OkapiRequest $request)
 {
     $user_uuids = $request->get_parameter('user_uuids');
     if (!$user_uuids) {
         throw new ParamMissing('user_uuids');
     }
     $user_uuids = explode("|", $user_uuids);
     if (count($user_uuids) > 500) {
         throw new InvalidParam('user_uuids', "Maximum allowed number of referenced users " . "is 500. You provided " . count($user_uuids) . " user IDs.");
     }
     $fields = $request->get_parameter('fields');
     if (!$fields) {
         throw new ParamMissing('fields');
     }
     $fields = explode("|", $fields);
     foreach ($fields as $field) {
         if (!in_array($field, self::$valid_field_names)) {
             throw new InvalidParam('fields', "'{$field}' is not a valid field code.");
         }
     }
     $rs = Db::query("\n            select user_id, uuid, username, admin, latitude, longitude, date_created\n            from user\n            where uuid in ('" . implode("','", array_map('\\okapi\\Db::escape_string', $user_uuids)) . "')\n        ");
     $results = array();
     $id2uuid = array();
     $uuid2id = array();
     while ($row = Db::fetch_assoc($rs)) {
         $id2uuid[$row['user_id']] = $row['uuid'];
         $uuid2id[$row['uuid']] = $row['user_id'];
         $entry = array();
         foreach ($fields as $field) {
             switch ($field) {
                 case 'uuid':
                     $entry['uuid'] = $row['uuid'];
                     break;
                 case 'username':
                     $entry['username'] = $row['username'];
                     break;
                 case 'profile_url':
                     $entry['profile_url'] = Settings::get('SITE_URL') . "viewprofile.php?userid=" . $row['user_id'];
                     break;
                 case 'is_admin':
                     if (!$request->token) {
                         $entry['is_admin'] = null;
                     } elseif ($request->token->user_id != $row['user_id']) {
                         $entry['is_admin'] = null;
                     } else {
                         $entry['is_admin'] = $row['admin'] ? true : false;
                     }
                     break;
                 case 'internal_id':
                     $entry['internal_id'] = $row['user_id'];
                     break;
                 case 'date_registered':
                     $entry['date_registered'] = date("Y-m-d", strtotime($row['date_created']));
                 case 'caches_found':
                     /* handled separately */
                     break;
                 case 'caches_notfound':
                     /* handled separately */
                     break;
                 case 'caches_hidden':
                     /* handled separately */
                     break;
                 case 'rcmds_given':
                     /* handled separately */
                     break;
                 case 'home_location':
                     if (!$request->token) {
                         $entry['home_location'] = null;
                     } elseif ($request->token->user_id != $row['user_id']) {
                         $entry['home_location'] = null;
                     } elseif (!$row['latitude'] && !$row['longitude']) {
                         # OCPL sets NULL/NULL for unknown location, OCDE sets 0/0.
                         # It is safe to return null also for OCPL 0/0, as this value
                         # does not make sense.
                         $entry['home_location'] = null;
                     } else {
                         $entry['home_location'] = round($row['latitude'], 6) . "|" . round($row['longitude'], 6);
                     }
                     break;
                 default:
                     throw new Exception("Missing field case: " . $field);
             }
         }
         $results[$row['uuid']] = $entry;
     }
     Db::free_result($rs);
     # caches_found, caches_notfound, caches_hidden
     if (in_array('caches_found', $fields) || in_array('caches_notfound', $fields) || in_array('caches_hidden', $fields) || in_array('rcmds_given', $fields)) {
         # We will load all these stats together. Then we may remove these which
         # the user doesn't need.
         $extras = array();
         if (Settings::get('OC_BRANCH') == 'oc.pl') {
             # OCPL stores user stats in 'user' table.
             $rs = Db::query("\n                    select user_id, founds_count, notfounds_count, hidden_count\n                    from user\n                    where user_id in ('" . implode("','", array_map('\\okapi\\Db::escape_string', array_keys($id2uuid))) . "')\n                ");
         } else {
             # OCDE stores user stats in 'stat_user' table.
             $rs = Db::query("\n                    select\n                        u.user_id,\n                        ifnull(su.found, 0) as founds_count,\n                        ifnull(su.notfound, 0) as notfounds_count,\n                        ifnull(su.hidden, 0) as hidden_count\n                    from\n                        user u\n                        left join stat_user su\n                            on su.user_id = u.user_id\n                    where u.user_id in ('" . implode("','", array_map('\\okapi\\Db::escape_string', array_keys($id2uuid))) . "')\n                ");
         }
         while ($row = Db::fetch_assoc($rs)) {
             $extras[$row['user_id']] = array();
             $extra_ref =& $extras[$row['user_id']];
             $extra_ref['caches_found'] = 0 + $row['founds_count'];
             $extra_ref['caches_notfound'] = 0 + $row['notfounds_count'];
             $extra_ref['caches_hidden'] = 0 + $row['hidden_count'];
         }
         Db::free_result($rs);
         if (in_array('rcmds_given', $fields)) {
             $rs = Db::query("\n                    select user_id, count(*) as rcmds_given\n                    from cache_rating\n                    where user_id in ('" . implode("','", array_map('\\okapi\\Db::escape_string', array_keys($id2uuid))) . "')\n                    group by user_id\n                ");
             $rcmds_counts = array();
             while ($row = Db::fetch_assoc($rs)) {
                 $rcmds_counts[$row['user_id']] = $row['rcmds_given'];
             }
             foreach ($extras as $user_id => &$extra_ref) {
                 $extra_ref['rcmds_given'] = isset($rcmds_counts[$user_id]) ? 0 + $rcmds_counts[$user_id] : 0;
             }
         }
         # "Apply" only those fields which the consumer wanted.
         foreach (array('caches_found', 'caches_notfound', 'caches_hidden', 'rcmds_given') as $field) {
             if (!in_array($field, $fields)) {
                 continue;
             }
             foreach ($results as $uuid => &$result_ref) {
                 $result_ref[$field] = $extras[$uuid2id[$uuid]][$field];
             }
         }
     }
     # Check which user IDs were not found and mark them with null.
     foreach ($user_uuids as $user_uuid) {
         if (!isset($results[$user_uuid])) {
             $results[$user_uuid] = null;
         }
     }
     return Okapi::formatted_response($request, $results);
 }
Example #22
0
 public static function call()
 {
     $token_key = isset($_GET['oauth_token']) ? $_GET['oauth_token'] : '';
     $langpref = isset($_GET['langpref']) ? $_GET['langpref'] : Settings::get('SITELANG');
     $langprefs = explode("|", $langpref);
     $locales = array();
     foreach (Locales::$languages as $lang => $attrs) {
         $locales[$attrs['locale']] = $attrs;
     }
     # Current implementation of the "interactivity" parameter is: If developer
     # wants to "confirm_user", then just log out the current user before we
     # continue.
     $force_relogin = isset($_GET['interactivity']) && $_GET['interactivity'] == 'confirm_user';
     $token = Db::select_row("\n            select\n                t.`key` as `key`,\n                c.`key` as consumer_key,\n                c.name as consumer_name,\n                c.url as consumer_url,\n                t.callback,\n                t.verifier\n            from\n                okapi_consumers c,\n                okapi_tokens t\n            where\n                t.`key` = '" . Db::escape_string($token_key) . "'\n                and t.consumer_key = c.`key`\n                and t.user_id is null\n        ");
     $callback_concat_char = strpos($token['callback'], '?') === false ? "?" : "&";
     if (!$token) {
         # Probably Request Token has expired. This will be usually viewed
         # by the user, who knows nothing on tokens and OAuth. Let's be nice then!
         $vars = array('okapi_base_url' => Settings::get('SITE_URL') . "okapi/", 'token' => $token, 'token_expired' => true, 'site_name' => Okapi::get_normalized_site_name(), 'site_url' => Settings::get('SITE_URL'), 'site_logo' => Settings::get('SITE_LOGO'), 'locales' => $locales);
         $response = new OkapiHttpResponse();
         $response->content_type = "text/html; charset=utf-8";
         ob_start();
         $vars['locale_displayed'] = Okapi::gettext_domain_init($langprefs);
         include 'authorize.tpl.php';
         $response->body = ob_get_clean();
         Okapi::gettext_domain_restore();
         return $response;
     }
     # Determine which user is logged in to OC.
     require_once $GLOBALS['rootpath'] . "okapi/lib/oc_session.php";
     $OC_user_id = OCSession::get_user_id();
     # Ensure a user is logged in (or force re-login).
     if ($force_relogin || $OC_user_id == null) {
         # TODO: confirm_user should first ask the user if he's "the proper one",
         # and then offer to sign in as a different user.
         $login_page = 'login.php?';
         if ($OC_user_id !== null) {
             if (Settings::get('OC_BRANCH') == 'oc.de') {
                 # OCDE login.php?action=logout&target=... will NOT logout and
                 # then redirect to the target, but it will log out, prompt for
                 # login and then redirect to the target after logging in -
                 # that's exactly the relogin that we want.
                 $login_page .= 'action=logout&';
             } else {
                 # OCPL uses REAL MAGIC for session handling. I don't get ANY of it.
                 # The logout.php DOES NOT support the "target" parameter, so we
                 # can't just call it. The only thing that comes to mind is...
                 # Try to destroy EVERYTHING. (This still won't necessarilly work,
                 # because OC may store cookies in separate paths, but hopefully
                 # they won't).
                 if (isset($_SERVER['HTTP_COOKIE'])) {
                     $cookies = explode(';', $_SERVER['HTTP_COOKIE']);
                     foreach ($cookies as $cookie) {
                         $parts = explode('=', $cookie);
                         $name = trim($parts[0]);
                         setcookie($name, '', time() - 1000);
                         setcookie($name, '', time() - 1000, '/');
                         foreach (self::getPossibleCookieDomains() as $domain) {
                             setcookie($name, '', time() - 1000, '/', $domain);
                         }
                     }
                 }
                 # We should be logged out now. Let's login again.
             }
         }
         $after_login = "******" . ($langpref != Settings::get('SITELANG') ? "&langpref=" . $langpref : "");
         $login_url = Settings::get('SITE_URL') . $login_page . "target=" . urlencode($after_login) . "&langpref=" . $langpref;
         return new OkapiRedirectResponse($login_url);
     }
     # Check if this user has already authorized this Consumer. If he did,
     # then we will automatically authorize all subsequent Request Tokens
     # from this Consumer.
     $authorized = Db::select_value("\n            select 1\n            from okapi_authorizations\n            where\n                user_id = '" . Db::escape_string($OC_user_id) . "'\n                and consumer_key = '" . Db::escape_string($token['consumer_key']) . "'\n        ", 0);
     if (!$authorized) {
         if (isset($_POST['authorization_result'])) {
             # Not yet authorized, but user have just submitted the authorization form.
             # WRTODO: CSRF protection
             if ($_POST['authorization_result'] == 'granted') {
                 Db::execute("\n                        insert ignore into okapi_authorizations (consumer_key, user_id)\n                        values (\n                            '" . Db::escape_string($token['consumer_key']) . "',\n                            '" . Db::escape_string($OC_user_id) . "'\n                        );\n                    ");
                 $authorized = true;
             } else {
                 # User denied access. Nothing sensible to do now. Will try to report
                 # back to the Consumer application with an error.
                 if ($token['callback']) {
                     return new OkapiRedirectResponse($token['callback'] . $callback_concat_char . "error=access_denied" . "&oauth_token=" . $token['key']);
                 } else {
                     # Consumer did not provide a callback URL (oauth_callback=oob).
                     # We'll have to redirect to the Opencaching main page then...
                     return new OkapiRedirectResponse(Settings::get('SITE_URL') . "index.php");
                 }
             }
         } else {
             # Not yet authorized. Display an authorization request.
             $vars = array('okapi_base_url' => Settings::get('SITE_URL') . "okapi/", 'token' => $token, 'site_name' => Okapi::get_normalized_site_name(), 'site_url' => Settings::get('SITE_URL'), 'site_logo' => Settings::get('SITE_LOGO'), 'locales' => $locales);
             $response = new OkapiHttpResponse();
             $response->content_type = "text/html; charset=utf-8";
             ob_start();
             $vars['locale_displayed'] = Okapi::gettext_domain_init($langprefs);
             include 'authorize.tpl.php';
             $response->body = ob_get_clean();
             Okapi::gettext_domain_restore();
             return $response;
         }
     }
     # User granted access. Now we can authorize the Request Token.
     Db::execute("\n            update okapi_tokens\n            set user_id = '" . Db::escape_string($OC_user_id) . "'\n            where `key` = '" . Db::escape_string($token_key) . "';\n        ");
     # Redirect to the callback_url.
     if ($token['callback']) {
         return new OkapiRedirectResponse($token['callback'] . $callback_concat_char . "oauth_token=" . $token_key . "&oauth_verifier=" . $token['verifier']);
     } else {
         # Consumer did not provide a callback URL (probably the user is using a desktop
         # or mobile application). We'll just have to display the verifier to the user.
         return new OkapiRedirectResponse(Settings::get('SITE_URL') . "okapi/apps/authorized?oauth_token=" . $token_key . "&oauth_verifier=" . $token['verifier'] . "&langpref=" . $langpref);
     }
 }
Example #23
0
 /**
  * Important: YOU HAVE TO make sure $tables and $where_conds don't contain
  * unescaped user-supplied data!
  */
 public static function get_set($tables, $joins, $where_conds, $min_store, $ref_max_age)
 {
     # Compute the "params hash".
     $params_hash = md5(serialize(array($tables, $joins, $where_conds)));
     # Check if there exists an entry for this hash, which also meets the
     # given freshness criteria.
     list($set_id, $date_created, $expires) = self::find_param_set($params_hash, $ref_max_age);
     if ($set_id === null) {
         # To avoid generating the same results by multiple threads at once
         # (the "tile" method uses the "save" method, so the problem is
         # quite real!), we will acquire a write-lock here.
         $lock = OkapiLock::get("search-results-writer");
         $lock->acquire();
         try {
             # Make sure we were the first to acquire the lock.
             list($set_id, $date_created, $expires) = self::find_param_set($params_hash, $ref_max_age);
             if ($set_id === null) {
                 # We are in the first thread which have acquired the lock.
                 # We will proceed with result-set creation. Other threads
                 # will be waiting until we finish.
                 Db::execute("\n                        insert into okapi_search_sets (params_hash, date_created, expires)\n                        values (\n                            'processing in progress',\n                            now(),\n                            date_add(now(), interval '" . mysql_real_escape_string($min_store + 60) . "' second)\n                        )\n                    ");
                 $set_id = Db::last_insert_id();
                 $date_created = time();
                 $expires = $date_created + $min_store + 60;
                 Db::execute("\n                        insert into okapi_search_results (set_id, cache_id)\n                        select distinct\n                            '" . mysql_real_escape_string($set_id) . "',\n                            caches.cache_id\n                        from\n                            " . implode(", ", $tables) . "\n                            " . implode(" ", $joins) . "\n                        where (" . implode(") and (", $where_conds) . ")\n                    ");
                 # Lock barrier, to make sure the data is visible by other
                 # sessions. See http://bugs.mysql.com/bug.php?id=36618
                 Db::execute("lock table okapi_search_results write");
                 Db::execute("unlock tables");
                 Db::execute("\n                        update okapi_search_sets\n                        set params_hash = '" . mysql_real_escape_string($params_hash) . "'\n                        where id = '" . mysql_real_escape_string($set_id) . "'\n                    ");
             } else {
                 # Some other thread acquired the lock before us and it has
                 # generated the result set. We don't need to do anything.
             }
             $lock->release();
         } catch (Exception $e) {
             # SQL error? Make sure the lock is released and rethrow.
             $lock->release();
             throw $e;
         }
     }
     # If we got an old set, we may need to expand its lifetime in order to
     # meet user's "min_store" criterium.
     if (time() + $min_store > $expires) {
         Db::execute("\n                update okapi_search_sets\n                set expires = date_add(now(), interval '" . mysql_real_escape_string($min_store + 60) . "' second)\n                where id = '" . mysql_real_escape_string($set_id) . "'\n            ");
     }
     return array('set_id' => "{$set_id}", 'generated_at' => date('c', $date_created), 'expires' => date('c', $expires));
 }
 public static function call()
 {
     # Flush the stats, so the page is fresh upon every request.
     require_once $GLOBALS['rootpath'] . "okapi/cronjobs.php";
     CronJobController::force_run("StatsWriterCronJob");
     # When services/caches/map/tile method is called, it writes some extra
     # stats in the okapi_stats_hourly table. This page retrieves and
     # formats these stats in a readable manner (for debugging).
     $response = new OkapiHttpResponse();
     $response->content_type = "text/plain; charset=utf-8";
     ob_start();
     $start = isset($_GET['start']) ? $_GET['start'] : date("Y-m-d 00:00:00", time() - 7 * 86400);
     $end = isset($_GET['end']) ? $_GET['end'] : date("Y-m-d 23:59:59");
     print "From: {$start}\n";
     print "  To: {$end}\n\n";
     $rs = Db::query("\n            select\n                service_name,\n                sum(total_calls),\n                sum(total_runtime)\n            from okapi_stats_hourly\n            where\n                period_start >= '" . mysql_real_escape_string($start) . "'\n                and period_start < '" . mysql_real_escape_string($end) . "'\n                and service_name like '%caches/map/tile%'\n            group by service_name\n        ");
     $total_calls = 0;
     $total_runtime = 0.0;
     $calls = array('A' => 0, 'B' => 0, 'C' => 0, 'D' => 0);
     $runtime = array('A' => 0.0, 'B' => 0.0, 'C' => 0.0, 'D' => 0.0);
     while (list($name, $c, $r) = mysql_fetch_array($rs)) {
         if ($name == 'services/caches/map/tile') {
             $total_calls = $c;
             $total_runtime = $r;
         } elseif (strpos($name, 'extra/caches/map/tile/checkpoint') === 0) {
             $calls[$name[32]] = $c;
             $runtime[$name[32]] = $r;
         }
     }
     if ($total_calls != $calls['A']) {
         print "Partial results. Only " . $calls['A'] . " out of {$total_calls} are covered.\n";
         print "All other will count as \"unaccounted for\".\n\n";
         $total_calls = $calls['A'];
     }
     $calls_left = $total_calls;
     $runtime_left = $total_runtime;
     $perc = function ($a, $b) {
         return $b > 0 ? sprintf("%.1f", 100 * $a / $b) . "%" : "(?)";
     };
     $avg = function ($a, $b) {
         return $b > 0 ? sprintf("%.4f", $a / $b) . "s" : "(?)";
     };
     $get_stats = function () use(&$calls_left, &$runtime_left, &$total_calls, &$total_runtime, &$perc) {
         return str_pad($perc($calls_left, $total_calls), 6, " ", STR_PAD_LEFT) . str_pad($perc($runtime_left, $total_runtime), 7, " ", STR_PAD_LEFT);
     };
     print "%CALLS  %TIME  Description\n";
     print "====== ======  ======================================================================\n";
     print $get_stats() . "  {$total_calls} responses served. Total runtime: " . sprintf("%.2f", $total_runtime) . "s\n";
     print "\n";
     print "               All of these requests needed a TileTree build/lookup. The average runtime of\n";
     print "               these lookups was " . $avg($runtime['A'], $total_calls) . ". " . $perc($runtime['A'], $total_runtime) . " of total runtime was spent here.\n";
     print "\n";
     $runtime_left -= $runtime['A'];
     print $get_stats() . "  All calls passed here after ~" . $avg($runtime['A'], $total_calls) . "\n";
     print "\n";
     print "               Lookup result was then processed and \"image description\" was created. It was\n";
     print "               passed on to the TileRenderer to compute the ETag hash string. The average runtime\n";
     print "               of this part was " . $avg($runtime['B'], $total_calls) . ". " . $perc($runtime['B'], $total_runtime) . " of total runtime was spent here.\n";
     print "\n";
     $runtime_left -= $runtime['B'];
     print $get_stats() . "  All calls passed here after ~" . $avg($runtime['A'] + $runtime['B'], $total_calls) . "\n";
     $etag_hits = $calls['B'] - $calls['C'];
     print "\n";
     print "               {$etag_hits} of the requests matched the ETag and were served an HTTP 304 response.\n";
     print "\n";
     $calls_left = $calls['C'];
     print $get_stats() . "  {$calls_left} calls passed here after ~" . $avg($runtime['A'] + $runtime['B'], $total_calls) . "\n";
     $imagecache_hits = $calls['C'] - $calls['D'];
     print "\n";
     print "               {$imagecache_hits} of these calls hit the server image cache.\n";
     print "               " . $perc($runtime['C'], $total_runtime) . " of total runtime was spent to find these.\n";
     print "\n";
     $calls_left = $calls['D'];
     $runtime_left -= $runtime['C'];
     print $get_stats() . "  {$calls_left} calls passed here after ~" . $avg($runtime['A'] + $runtime['B'] + $runtime['C'], $total_calls) . "\n";
     print "\n";
     print "               These calls required the tile to be rendered. On average, it took\n";
     print "               " . $avg($runtime['D'], $calls['D']) . " to *render* a tile.\n";
     print "               " . $perc($runtime['D'], $total_runtime) . " of total runtime was spent here.\n";
     print "\n";
     $runtime_left -= $runtime['D'];
     print $perc($runtime_left, $total_runtime) . " of runtime was unaccounted for (other processing).\n";
     print "Average response time was " . $avg($total_runtime, $total_calls) . ".\n\n";
     print "Current okapi_cache score distribution:\n";
     $rs = Db::query("\n            select floor(log2(score)), count(*), sum(length(value))\n            from okapi_cache\n            where score is not null\n            group by floor(log2(score))\n        ");
     while (list($log2, $count, $size) = mysql_fetch_array($rs)) {
         print $count . " elements ({$size} bytes) with score between " . pow(2, $log2) . " and " . pow(2, $log2 + 1) . ".\n";
     }
     $response->body = ob_get_clean();
     return $response;
 }
Example #25
0
 public static function call(OkapiRequest $request)
 {
     # Retrieve the list of URLs to check.
     $tmp = $request->get_parameter('urls');
     if (!$tmp) {
         throw new ParamMissing('urls');
     }
     $urls = explode('|', $tmp);
     $as_dict = $request->get_parameter('as_dict');
     if (!$as_dict) {
         $as_dict = 'false';
     }
     if (!in_array($as_dict, array('true', 'false'))) {
         throw new InvalidParam('as_dict');
     }
     $as_dict = $as_dict == 'true';
     # Generate the lists of keys.
     $results = array();
     $urls_with = array('cache_code' => array(), 'internal_id' => array(), 'uuid' => array());
     foreach ($urls as &$url_ref) {
         $key = self::get_cache_key($url_ref);
         if ($key != null) {
             $urls_with[$key[0]][$url_ref] = $key[1];
         } else {
             $results[$url_ref] = null;
         }
     }
     # Include 'cache_code' references.
     foreach ($urls_with['cache_code'] as $url => $cache_code) {
         $results[$url] = $cache_code;
     }
     # Include 'internal_id' references.
     $internal_ids = array_values($urls_with['internal_id']);
     if (count($internal_ids) > 0) {
         $rs = Db::query("\n                select cache_id, wp_oc\n                from caches\n                where\n                    cache_id in ('" . implode("','", array_map('mysql_real_escape_string', $internal_ids)) . "')\n                    and status in (1,2,3)\n            ");
         $dict = array();
         while ($row = mysql_fetch_assoc($rs)) {
             $dict[$row['cache_id']] = $row['wp_oc'];
         }
         foreach ($urls_with['internal_id'] as $url => $internal_id) {
             if (isset($dict[$internal_id])) {
                 $results[$url] = $dict[$internal_id];
             } else {
                 $results[$url] = null;
             }
         }
     }
     # Include 'uuid' references.
     $uuids = array_values($urls_with['uuid']);
     if (count($uuids) > 0) {
         $rs = Db::query("\n                select uuid, wp_oc\n                from caches\n                where\n                    uuid in ('" . implode("','", array_map('mysql_real_escape_string', $uuids)) . "')\n                    and status in (1,2,3)\n            ");
         $dict = array();
         while ($row = mysql_fetch_assoc($rs)) {
             $dict[$row['uuid']] = $row['wp_oc'];
         }
         foreach ($urls_with['uuid'] as $url => $uuid) {
             if (isset($dict[$uuid])) {
                 $results[$url] = $dict[$uuid];
             } else {
                 $results[$url] = null;
             }
         }
     }
     # Format the results according to the 'as_dict' parameter.
     if ($as_dict) {
         return Okapi::formatted_response($request, $results);
     } else {
         $cache_codes = array();
         foreach ($results as $url => $cache_code) {
             if ($cache_code != null) {
                 $cache_codes[$cache_code] = true;
             }
         }
         $flattened = array('results' => array_keys($cache_codes));
         return Okapi::formatted_response($request, $flattened);
     }
 }
Example #26
0
 /**
  * Get the list of cache IDs which were found by given user.
  * Parameter needs to be *internal* user id, not uuid.
  */
 private static function get_found_cache_ids($internal_user_id)
 {
     return Db::select_column("\n            select cache_id\n            from cache_logs\n            where\n                user_id = '" . mysql_real_escape_string($internal_user_id) . "'\n                and type in (\n                    '" . mysql_real_escape_string(Okapi::logtypename2id("Found it")) . "',\n                    '" . mysql_real_escape_string(Okapi::logtypename2id("Attended")) . "'\n                )\n                and " . (Settings::get('OC_BRANCH') == 'oc.pl' ? "deleted = 0" : "true") . "\n        ");
 }
Example #27
0
 private static function save_stats($service_name, $request, $runtime)
 {
     # Getting rid of nulls. MySQL PRIMARY keys cannot contain nullable columns.
     # Temp table doesn't have primary key, but other stats tables (which are
     # dependant on stats table) - do.
     if ($request !== null) {
         $consumer_key = $request->consumer != null ? $request->consumer->key : 'anonymous';
         $user_id = $request->token != null && $request->token instanceof OkapiAccessToken ? $request->token->user_id : -1;
         if ($request->is_http_request() && $service_name[0] == 's') {
             # 's' for "services/", we don't want "extra/" included
             $calltype = 'http';
         } else {
             $calltype = 'internal';
         }
     } else {
         $consumer_key = 'internal';
         $user_id = -1;
         $calltype = 'internal';
     }
     Db::execute("\n            insert into okapi_stats_temp (`datetime`, consumer_key, user_id, service_name, calltype, runtime)\n            values (\n                now(),\n                '" . mysql_real_escape_string($consumer_key) . "',\n                '" . mysql_real_escape_string($user_id) . "',\n                '" . mysql_real_escape_string($service_name) . "',\n                '" . mysql_real_escape_string($calltype) . "',\n                '" . mysql_real_escape_string($runtime) . "'\n            );\n        ");
 }
 private static function remove_notes($cache_id, $user_id)
 {
     if (Settings::get('OC_BRANCH') == 'oc.de') {
         # we can delete row if and only if there are no coords in it
         $affected_row_count = Db::execute("\n                delete from coordinates\n                where\n                    type = 2  -- personal note\n                    and cache_id = '" . Db::escape_string($cache_id) . "'\n                    and user_id = '" . Db::escape_string($user_id) . "'\n                    and longitude = 0\n                    and latitude = 0\n            ");
         if ($affected_row_count <= 0) {
             # no rows deleted - record either doesn't exist, or has coords
             # remove only description
             Db::execute("\n                    update coordinates\n                    set description = null\n                    where\n                        type = 2\n                        and cache_id = '" . Db::escape_string($cache_id) . "'\n                        and user_id = '" . Db::escape_string($user_id) . "'\n                ");
         }
     } else {
         # oc.pl branch
         Db::execute("\n                delete from cache_notes\n                where\n                    cache_id = '" . Db::escape_string($cache_id) . "'\n                    and user_id = '" . Db::escape_string($user_id) . "'\n            ");
     }
 }
 /**
  * OCDE supports arbitrary ordering of log images. The pictures table
  * contains sequence numbers, which are always > 0 and need not to be
  * consecutive (may have gaps). There is a unique index which prevents
  * inserting duplicate seq numbers for the same log.
  *
  * OCPL sequence numbers currently are always = 1.
  *
  * The purpose of this function is to bring the supplied 'position'
  * parameter into bounds, and to calculate an appropriate sequence number
  * from it.
  *
  * This function is always called when adding images. When editing images,
  * it is called only for OCDE and if the position parameter was supplied.
  */
 static function prepare_position($log_internal_id, $position, $end_offset)
 {
     if (Settings::get('OC_BRANCH') == 'oc.de' && $position !== null) {
         # Prevent race conditions when creating sequence numbers if a
         # user tries to upload multiple images simultaneously. With a
         # few picture uploads per hour - most of them probably witout
         # a 'position' parameter - the lock is neglectable.
         Db::execute('lock tables pictures write');
     }
     $log_images_count = Db::select_value("\n            select count(*)\n            from pictures\n            where object_type = 1 and object_id = '" . Db::escape_string($log_internal_id) . "'\n        ");
     if (Settings::get('OC_BRANCH') == 'oc.pl') {
         # Ignore the position parameter, always insert at end.
         # Remember that this function is NOT called when editing OCPL images.
         $position = $log_images_count;
         $seq = 1;
     } else {
         if ($position === null || $position >= $log_images_count) {
             $position = $log_images_count - 1 + $end_offset;
             $seq = Db::select_value("\n                    select max(seq)\n                    from pictures\n                    where object_type = 1 and object_id = '" . Db::escape_string($log_internal_id) . "'\n                ") + $end_offset;
         } else {
             if ($position <= 0) {
                 $position = 0;
                 $seq = 1;
             } else {
                 $seq = Db::select_value("\n                    select seq\n                    from pictures\n                    where object_type = 1 and object_id = '" . Db::escape_string($log_internal_id) . "'\n                    order by seq\n                    limit " . ($position + 0) . ", 1\n                ");
             }
         }
     }
     # $position may have become a string, as returned by database queries.
     return array($position + 0, $seq, $log_images_count);
 }
Example #30
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;
 }