public static function call(OkapiRequest $request) { # "Cache control" parameters. $tmp = $request->get_parameter('min_store'); if ($tmp === null) { $tmp = "300"; } $min_store = intval($tmp); if ("{$min_store}" !== $tmp || $min_store < 0 || $min_store > 64800) { throw new InvalidParam('min_store', "Has to be in the 0..64800 range."); } $tmp = $request->get_parameter('ref_max_age'); if ($tmp === null) { $tmp = "300"; } if ($tmp == "nolimit") { $tmp = "9999999"; } $ref_max_age = intval($tmp); if ("{$ref_max_age}" !== $tmp || $ref_max_age < 300) { throw new InvalidParam('ref_max_age', "Has to be >=300."); } # Search params. $search_assistant = new SearchAssistant($request); $search_assistant->prepare_common_search_params(); $search_params = $search_assistant->get_search_params(); $tables = array_merge(array('caches'), $search_params['extra_tables']); $where_conds = array_merge(array('caches.wp_oc is not null'), $search_params['where_conds']); if (isset($search_params['extra_joins']) && is_array($search_params['extra_joins'])) { $joins = $search_params['extra_joins']; } else { $joins = array(); } unset($search_params); # Generate, or retrieve an existing set, and return the result. # All user-supplied data in $tables and $where_conds MUST be escaped! $result = self::get_set($tables, $joins, $where_conds, $min_store, $ref_max_age); return Okapi::formatted_response($request, $result); }
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); }
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('center'); if (!$tmp) { throw new ParamMissing('center'); } $parts = explode('|', $tmp); if (count($parts) != 2) { throw new InvalidParam('center', "Expecting 2 pipe-separated parts, got " . count($parts) . "."); } foreach ($parts as &$part_ref) { if (!preg_match("/^-?[0-9]+(\\.?[0-9]*)\$/", $part_ref)) { throw new InvalidParam('center', "'{$part_ref}' is not a valid float number."); } $part_ref = floatval($part_ref); } list($center_lat, $center_lon) = $parts; if ($center_lat > 90 || $center_lat < -90) { throw new InvalidParam('center', "Latitudes have to be within -90..90 range."); } if ($center_lon > 180 || $center_lon < -180) { throw new InvalidParam('center', "Longitudes have to be within -180..180 range."); } # # In the method description, we promised to return caches ordered by the *rough* # distance from the center point. We'll use ORDER BY with a simplified distance # formula and combine it with the LIMIT clause to get the best results. # $search_assistant = new SearchAssistant($request); $search_assistant->prepare_common_search_params(); $search_assistant->prepare_location_search_params(); $distance_formula = Okapi::get_distance_sql($center_lat, $center_lon, $search_assistant->get_latitude_expr(), $search_assistant->get_longitude_expr()); # 'radius' parameter is optional. If not given, we'll have to calculate the # distance for every cache in the database. $where_conds = array(); $radius = null; if ($tmp = $request->get_parameter('radius')) { if (!preg_match("/^-?[0-9]+(\\.?[0-9]*)\$/", $tmp)) { throw new InvalidParam('radius', "'{$tmp}' is not a valid float number."); } $radius = floatval($tmp); # is given in kilometers if ($radius <= 0) { throw new InvalidParam('radius', "Has to be a positive number."); } # Apply a latitude-range prefilter if it looks promising. # See https://github.com/opencaching/okapi/issues/363 for more info. $optimization_radius = 100; # in kilometers, optimized for Opencaching.de $km2degrees_upper_estimate_factor = 0.01; if ($radius <= $optimization_radius) { $radius_degrees = $radius * $km2degrees_upper_estimate_factor; $where_conds[] = "\n caches.latitude >= '" . Db::escape_string($center_lat - $radius_degrees) . "'\n and caches.latitude <= '" . Db::escape_string($center_lat + $radius_degrees) . "'\n "; } $radius *= 1000; # convert from kilometers to meters $where_conds[] = "{$distance_formula} <= '" . Db::escape_string($radius) . "'"; } $search_params = $search_assistant->get_search_params(); $search_params['where_conds'] = array_merge($where_conds, $search_params['where_conds']); $search_params['caches_indexhint'] = "use index (latitude)"; $search_params['order_by'][] = $distance_formula; # not replaced; added to the end! $search_assistant->set_search_params($search_params); $result = $search_assistant->get_common_search_result(); if ($radius == null) { # 'more' is meaningless in this case, we'll remove it. unset($result['more']); } return Okapi::formatted_response($request, $result); }