public static function call(OkapiRequest $request) { $issue_id = $request->get_parameter('issue_id'); if (!$issue_id) { throw new ParamMissing('issue_id'); } if (!preg_match("/^[0-9]+\$/", $issue_id) || strlen($issue_id) > 6) { throw new InvalidParam('issue_id'); } $cache_key = "apiref/issue#" . $issue_id; $result = Cache::get($cache_key); if ($result == null) { # Download the number of comments from GitHub Issue Tracker. try { $extra_headers = array(); $extra_headers[] = "Accept: application/vnd.github.v3.html+json"; $extra_headers[] = "User-Agent: https://github.com/opencaching/okapi/"; if (Settings::get('GITHUB_ACCESS_TOKEN')) { $extra_headers[] = "Authorization: token " . Settings::get('GITHUB_ACCESS_TOKEN'); } $opts = array('http' => array('method' => "GET", 'timeout' => 2.0, 'header' => implode("\r\n", $extra_headers))); $context = stream_context_create($opts); $json = file_get_contents("https://api.github.com/repos/opencaching/okapi/issues/{$issue_id}", false, $context); } catch (ErrorException $e) { throw new BadRequest("Sorry, we could not retrieve issue stats from the GitHub site. " . "This is probably due to a temporary connection problem. Try again later or contact " . "us if this seems permanent."); } $doc = json_decode($json, true); $result = array('id' => $issue_id + 0, 'last_updated' => $doc['updated_at'], 'title' => $doc['title'], 'url' => $doc['html_url'], 'comment_count' => $doc['comments']); # On one hand, we want newly added comments to show up quickly. # On the other, we don't want OKAPI to spam GitHub with queries. # So it's difficult to choose the best timeout for this. Cache::set($cache_key, $result, 3600); } return Okapi::formatted_response($request, $result); }
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); }
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; }
/** * 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); }
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; }
public static function call(OkapiRequest $request) { $result = array(); $result['site_url'] = Settings::get('SITE_URL'); $result['okapi_base_url'] = $result['site_url'] . "okapi/"; $result['site_name'] = Okapi::get_normalized_site_name(); $result['okapi_revision'] = Okapi::$revision; return Okapi::formatted_response($request, $result); }
/** * Refresh all attributes from the given XML. Usually, this file is * downloaded from Google Code (using refresh_now). */ public static function refresh_from_string($xml) { /* The attribute-definitions.xml file defines relationships between * attributes originating from various OC installations. Each * installation uses internal IDs of its own. Which "attribute schema" * is being used in THIS installation? */ $my_schema = Settings::get('ORIGIN_URL'); $doc = simplexml_load_string($xml); $cachedvalue = array('attr_dict' => array()); # Build cache attributes dictionary $all_internal_ids = array(); foreach ($doc->attr as $attrnode) { $attr = array('acode' => (string) $attrnode['acode'], 'gc_equivs' => array(), 'internal_id' => null, 'names' => array(), 'descriptions' => array(), 'is_discontinued' => true); foreach ($attrnode->groundspeak as $gsnode) { $attr['gc_equivs'][] = array('id' => (int) $gsnode['id'], 'inc' => in_array((string) $gsnode['inc'], array("true", "1")) ? 1 : 0, 'name' => (string) $gsnode['name']); } foreach ($attrnode->opencaching as $ocnode) { /* If it is used by at least one OC node, then it's NOT discontinued. */ $attr['is_discontinued'] = false; if ((string) $ocnode['schema'] == $my_schema) { /* It is used by THIS OC node. */ $internal_id = (int) $ocnode['id']; if (isset($all_internal_ids[$internal_id])) { throw new Exception("The internal attribute " . $internal_id . " has multiple assigments to OKAPI attributes."); } $all_internal_ids[$internal_id] = true; if (!is_null($attr['internal_id'])) { throw new Exception("There are multiple internal IDs for the " . $attr['acode'] . " attribute."); } $attr['internal_id'] = $internal_id; } } foreach ($attrnode->lang as $langnode) { $lang = (string) $langnode['id']; foreach ($langnode->name as $namenode) { if (isset($attr['names'][$lang])) { throw new Exception("Duplicate " . $lang . " name of attribute " . $attr['acode']); } $attr['names'][$lang] = (string) $namenode; } foreach ($langnode->desc as $descnode) { if (isset($attr['descriptions'][$lang])) { throw new Exception("Duplicate " . $lang . " description of attribute " . $attr['acode']); } $xml = $descnode->asxml(); /* contains "<desc>" and "</desc>" */ $innerxml = preg_replace("/(^[^>]+>)|(<[^<]+\$)/us", "", $xml); $attr['descriptions'][$lang] = self::cleanup_string($innerxml); } } $cachedvalue['attr_dict'][$attr['acode']] = $attr; } $cache_key = "attrhelper/dict#" . Okapi::$revision . self::cache_key_suffix(); Cache::set($cache_key, $cachedvalue, self::ttl()); self::$attr_dict = $cachedvalue['attr_dict']; }
/** * Returns one of: array('cache_code', 'OPXXXX'), array('internal_id', '12345'), * array('uuid', 'A408C3...') or null. */ private static function get_cache_key($url) { # Determine our own domain. static $host = null; static $length = null; if ($host == null) { $host = parse_url(Settings::get('SITE_URL'), PHP_URL_HOST); if (strpos($host, "www.") === 0) { $host = substr($host, 4); } $length = strlen($host); } # Parse the URL $uri = parse_url($url); if ($uri == false) { return null; } if (!isset($uri['scheme']) || !in_array($uri['scheme'], array('http', 'https'))) { return null; } if (!isset($uri['host']) || substr($uri['host'], -$length) != $host) { return null; } if (!isset($uri['path'])) { return null; } if (preg_match("#^/(O[A-Z][A-Z0-9]{4,5})\$#", $uri['path'], $matches)) { # Some servers allow "http://oc.xx/<cache_code>" shortcut. return array('cache_code', $matches[1]); } $parts = array(); if (isset($uri['query'])) { $parts = array_merge($parts, explode('&', $uri['query'])); } if (isset($uri['fragment'])) { $parts = array_merge($parts, explode('&', $uri['fragment'])); } foreach ($parts as $param) { $item = explode('=', $param, 2); if (count($item) != 2) { continue; } $key = $item[0]; $value = $item[1]; if ($key == 'wp') { return array('cache_code', $value); } if ($key == 'cacheid') { return array('internal_id', $value); } if ($key == 'uuid') { return array('uuid', $value); } } return null; }
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); }
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); }
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("examples.html"), 'okapi_base_url' => Settings::get('SITE_URL') . "okapi/", 'site_url' => Settings::get('SITE_URL'), 'installations' => OkapiMenu::get_installations(), 'okapi_rev' => Okapi::$version_number, 'site_name' => Okapi::get_normalized_site_name()); $response = new OkapiHttpResponse(); $response->content_type = "text/html; charset=utf-8"; ob_start(); include 'examples.tpl.php'; $response->body = ob_get_clean(); return $response; }
public static function call(OkapiRequest $request) { $result = array(); $result['site_url'] = Settings::get('SITE_URL'); $result['okapi_base_url'] = $result['site_url'] . "okapi/"; $result['site_name'] = Okapi::get_normalized_site_name(); $result['okapi_version_number'] = Okapi::$version_number; $result['okapi_revision'] = Okapi::$version_number; /* Important for backward-compatibility! */ $result['okapi_git_revision'] = Okapi::$git_revision; return Okapi::formatted_response($request, $result); }
public static function call() { require_once 'menu.inc.php'; $vars = array('okapi_base_url' => Settings::get('SITE_URL') . "okapi/", 'menu' => OkapiMenu::get_menu_html(), 'installations' => OkapiMenu::get_installations(), 'okapi_rev' => Okapi::$revision); $response = new OkapiHttpResponse(); $response->status = "404 Not Found"; $response->content_type = "text/html; charset=utf-8"; ob_start(); include 'http404.tpl.php'; $response->body = ob_get_clean(); return $response; }
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; }
public static function call() { require_once $GLOBALS['rootpath'] . 'okapi/views/menu.inc.php'; require_once $GLOBALS['rootpath'] . 'okapi/views/changelog_helper.inc.php'; $changelog = new Changelog(); $vars = array('menu' => OkapiMenu::get_menu_html("changelog.html"), 'okapi_base_url' => Settings::get('SITE_URL') . "okapi/", 'site_url' => Settings::get('SITE_URL'), 'installations' => OkapiMenu::get_installations(), 'okapi_rev' => Okapi::$version_number, 'site_name' => Okapi::get_normalized_site_name(), 'changes' => array('unavailable' => $changelog->unavailable_changes, 'available' => $changelog->available_changes)); $response = new OkapiHttpResponse(); $response->content_type = "text/html; charset=utf-8"; ob_start(); include 'changelog.tpl.php'; $response->body = ob_get_clean(); return $response; }
public static function call() { require_once $GLOBALS['rootpath'] . 'okapi/views/changelog_helper.inc.php'; $changelog = new Changelog(); $changes = array_merge($changelog->unavailable_changes, $changelog->available_changes); $changes = array_slice($changes, 0, 20); $vars = array('changes' => $changes, 'site_url' => Settings::get('SITE_URL')); $response = new OkapiHttpResponse(); $response->content_type = "application/rss+xml; charset=utf-8"; ob_start(); include 'changelog_feed.tpl.php'; $response->body = ob_get_clean(); return $response; }
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); }
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); }
public static function call(OkapiRequest $request) { $result = array(); $result['site_url'] = Settings::get('SITE_URL'); $result['okapi_base_url'] = Okapi::get_recommended_base_url(); $result['okapi_base_urls'] = Okapi::get_allowed_base_urls(); $result['site_name'] = Okapi::get_normalized_site_name(); $result['okapi_version_number'] = Okapi::$version_number; $result['okapi_revision'] = Okapi::$version_number; /* Important for backward-compatibility! */ $result['okapi_git_revision'] = Okapi::$git_revision; $result['registration_url'] = Settings::get('REGISTRATION_URL'); $result['mobile_registration_url'] = Settings::get('MOBILE_REGISTRATION_URL'); $result['image_max_upload_size'] = Settings::get('IMAGE_MAX_UPLOAD_SIZE'); $result['image_rcmd_max_pixels'] = Settings::get('IMAGE_MAX_PIXEL_COUNT'); return Okapi::formatted_response($request, $result); }
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; }
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/"); }
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; }
public static function call() { if (isset($_REQUEST['posted'])) { $appname = isset($_REQUEST['appname']) ? $_REQUEST['appname'] : ""; $appname = trim($appname); $appurl = isset($_REQUEST['appurl']) ? $_REQUEST['appurl'] : ""; $email = isset($_REQUEST['email']) ? $_REQUEST['email'] : ""; $accepted_terms = isset($_REQUEST['terms']) ? $_REQUEST['terms'] : ""; $ok = false; if (!$appname) { $notice = "Please provide a valid application name."; } elseif (mb_strlen($appname) > 100) { $notice = "Application name should be less than 100 characters long."; } elseif (mb_strlen($appurl) > 250) { $notice = "Application URL should be less than 250 characters long."; } elseif ($appurl && substr($appurl, 0, 7) != "http://" && substr($appurl, 0, 8) != "https://") { $notice = "Application homepage URL should start with http(s)://. (Note: this URL is OPTIONAL and it is NOT for OAuth callback.)"; } elseif (!$email) { $notice = "Please provide a valid email address."; } elseif (mb_strlen($email) > 70) { $notice = "Email address should be less than 70 characters long."; } elseif (!$accepted_terms) { $notice = "You have to read and accept OKAPI Terms of Use."; } else { $ok = true; Okapi::register_new_consumer($appname, $appurl, $email); $notice = "Consumer Key generated successfully.\nCheck your email!"; } $response = new OkapiHttpResponse(); $response->content_type = "application/json; charset=utf-8"; $response->body = json_encode(array('ok' => $ok, 'notice' => $notice)); return $response; } require_once $GLOBALS['rootpath'] . 'okapi/service_runner.php'; require_once $GLOBALS['rootpath'] . 'okapi/views/menu.inc.php'; $vars = array('menu' => OkapiMenu::get_menu_html("signup.html"), 'okapi_base_url' => Settings::get('SITE_URL') . "okapi/", 'site_url' => Settings::get('SITE_URL'), 'site_name' => Okapi::get_normalized_site_name(), 'installations' => OkapiMenu::get_installations(), 'okapi_rev' => Okapi::$version_number, 'data_license_html' => Settings::get('DATA_LICENSE_URL') ? "<a href='" . Settings::get('DATA_LICENSE_URL') . "'>Data License</a>" : "Data License"); $response = new OkapiHttpResponse(); $response->content_type = "text/html; charset=utf-8"; ob_start(); include 'signup.tpl.php'; $response->body = ob_get_clean(); return $response; }
public static function call(OkapiRequest $request) { $token_key = $request->get_parameter('oauth_token'); if (!$token_key) { throw new ParamMissing("oauth_token"); } $langpref = $request->get_parameter('langpref'); $interactivity = $request->get_parameter('interactivity'); if (!$interactivity) { $interactivity = 'minimal'; } if (!in_array($interactivity, array('minimal', 'confirm_user'))) { throw new InvalidParam('interactivity', $interactivity); } # Redirect to the "apps" folder. This is done there (not here) # because: 1) we don't want any cookie or session-handling # done in the "services" folder. 2) "services" don't display # any interactive webpages, they just return the result. return new OkapiRedirectResponse(Settings::get('SITE_URL') . "okapi/apps/authorize" . "?oauth_token=" . $token_key . ($langpref != null ? "&langpref=" . $langpref : "") . "&interactivity=" . $interactivity); }
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); }
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) { $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(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; }
public static function call() { # This is a hidden page for OKAPI developers. It will output a complete # structure of the database. This is useful for making OKAPI compatible # across different OC installations. $user = Settings::get('DB_USERNAME'); $password = Settings::get('DB_PASSWORD'); $dbname = Settings::get('DB_NAME'); $dbserver = Settings::get('DB_SERVER'); # Some security measures are taken to hinder us from accidentally dumping # database contents: # - try to set memory limit so that no big data chunk can be stored # - reassure that we use the --no-data option # - plausibility test for data amount # - verify that the output does not contain table contents ini_set('memory_limit', '16M'); $shell_arguments = "mysqldump --no-data -h{$dbserver} -u{$user} -p{$password} {$dbname}"; if (!strpos($shell_arguments, "--no-data")) { throw new Exception("wrong database dump arguments"); } $struct = shell_exec($shell_arguments); if (strlen($struct) > 1000000) { throw new Exception("something went terribly wrong while dumping table structures"); } if (stripos($struct, "dumping data") !== FALSE) { throw new Exception("something went terribly wrong while dumping table structures"); } # Remove the "AUTO_INCREMENT=..." values. They break the diffs. $struct = preg_replace("/ AUTO_INCREMENT=([0-9]+)/i", "", $struct); # Discard local tables that are not part of the OC installation if (Settings::get('OC_BRANCH') == 'oc.de') { $struct = preg_replace("/structure for table `_.*?\n-- Table /s", "", $struct); } # This method can be invoked with "compare_to" parameter, which points to # an alternate database structure (generated by the same script in other # *public* OKAPI instance). When invoked this way, we will attempt to # generate SQL script which alters LOCAL database is such a way that it # will become the other (public) database. $response = new OkapiHttpResponse(); $response->content_type = "text/plain; charset=utf-8"; if (isset($_GET['compare_to'])) { self::requireSafe($_GET['compare_to']); $scheme = parse_url($_GET['compare_to'], PHP_URL_SCHEME); if (in_array($scheme, array('http', 'https'))) { try { $alternate_struct = @file_get_contents($_GET['compare_to']); } catch (Exception $e) { throw new BadRequest("Failed to load " . $_GET['compare_to']); } $response->body = "-- Automatically generated database diff. Use with caution!\n" . "-- Differences obtained with help of cool library by Kirill Gerasimenko.\n\n" . "-- Note: The following script has some limitations. It will render database\n" . "-- structure compatible, but not necessarilly EXACTLY the same. It might be\n" . "-- better to use manual diff instead.\n\n"; require_once "comparator.inc.php"; $updater = new \dbStructUpdater(); if (isset($_GET['reverse']) && $_GET['reverse'] == 'true') { $response->body .= "-- REVERSE MODE. The following will alter [2], so that it has the structure of [1].\n" . "-- 1. " . Settings::get('SITE_URL') . "okapi/devel/dbstruct (" . md5($struct) . ")\n" . "-- 2. " . $_GET['compare_to'] . " (" . md5($alternate_struct) . ")\n\n"; $alters = $updater->getUpdates($alternate_struct, $struct); } else { $response->body .= "-- The following will alter [1], so that it has the structure of [2].\n" . "-- 1. " . Settings::get('SITE_URL') . "okapi/devel/dbstruct (" . md5($struct) . ")\n" . "-- 2. " . $_GET['compare_to'] . " (" . md5($alternate_struct) . ")\n\n"; $alters = $updater->getUpdates($struct, $alternate_struct); } # Add semicolons foreach ($alters as &$alter_ref) { $alter_ref .= ";"; } # Comment out all differences containing "okapi_". These should be executed # by OKAPI update scripts. foreach ($alters as &$alter_ref) { if (strpos($alter_ref, "okapi_") !== false) { $lines = explode("\n", $alter_ref); $alter_ref = "-- Probably you should NOT execute this one. Use okapi/update instead.\n-- {{{\n-- " . implode("\n-- ", $lines) . "\n-- }}}"; } } if (count($alters) > 0) { $response->body .= implode("\n", $alters) . "\n"; } else { $response->body .= "-- No differences found\n"; } } else { $response->body = "HTTP(S) only!"; } } else { $response->body = $struct; } return $response; }