From d3510b917401a41baf3a595e200c6bed6d77a54c Mon Sep 17 00:00:00 2001 From: following Date: Tue, 9 Apr 2013 16:54:36 +0200 Subject: [PATCH] okapi r694 --- htdocs/okapi/core.php | 8 ++++---- htdocs/okapi/cronjobs.php | 20 +++++++++---------- htdocs/okapi/services/attrs/info.xml | 6 +++--- .../okapi/services/caches/formatters/gpx.xml | 2 +- htdocs/okapi/services/caches/geocache.xml | 14 +++++++------ htdocs/okapi/services/caches/geocaches.php | 14 ++++++------- .../caches/map/replicate_listener.inc.php | 14 ++++++------- .../services/caches/map/tiletree.inc.php | 19 ++++++++++-------- htdocs/okapi/services/caches/search/save.php | 4 ++++ .../services/caches/search/searching.inc.php | 3 +++ htdocs/okapi/services/logs/entry.xml | 6 ++++-- htdocs/okapi/services/logs/submit.php | 12 ++++------- htdocs/okapi/services/logs/submit.xml | 2 +- htdocs/okapi/services/logs/userlogs.xml | 6 ++++-- htdocs/okapi/views/devel/dbstruct.php | 3 ++- htdocs/okapi/views/update.php | 2 +- 16 files changed, 73 insertions(+), 62 deletions(-) diff --git a/htdocs/okapi/core.php b/htdocs/okapi/core.php index 7a342083..58e43ab0 100644 --- a/htdocs/okapi/core.php +++ b/htdocs/okapi/core.php @@ -778,7 +778,7 @@ class Okapi { public static $data_store; public static $server; - public static $revision = 672; # This gets replaced in automatically deployed packages + public static $revision = 694; # This gets replaced in automatically deployed packages private static $okapi_vars = null; /** Get a variable stored in okapi_vars. If variable not found, return $default. */ @@ -1716,10 +1716,10 @@ class Cache # just replace it with a big value. $timeout = 100*365*86400; } - $entries = array(); + $entries_escaped = array(); foreach ($dict as $key => $value) { - $entries[] = "( + $entries_escaped[] = "( '".mysql_real_escape_string($key)."', '".mysql_real_escape_string(gzdeflate(serialize($value)))."', date_add(now(), interval '".mysql_real_escape_string($timeout)."' second) @@ -1727,7 +1727,7 @@ class Cache } Db::execute(" replace into okapi_cache (`key`, value, expires) - values ".implode(", ", $entries)." + values ".implode(", ", $entries_escaped)." "); } diff --git a/htdocs/okapi/cronjobs.php b/htdocs/okapi/cronjobs.php index ab355900..4c73cd64 100644 --- a/htdocs/okapi/cronjobs.php +++ b/htdocs/okapi/cronjobs.php @@ -308,7 +308,7 @@ class CacheCleanupCronJob extends Cron5Job Db::execute(" update okapi_cache - set score = score * $multiplier + set score = score * '".mysql_real_escape_string($multiplier)."' where score is not null "); Db::execute(" @@ -333,7 +333,7 @@ class CacheCleanupCronJob extends Cron5Job delete from okapi_cache where score is not null - and score < $limit + and score < '".mysql_real_escape_string($limit)."' "); Db::query("optimize table okapi_cache"); @@ -385,18 +385,18 @@ class StatsWriterCronJob extends PrerequestCronJob '".mysql_real_escape_string($row['user_id'])."', '".mysql_real_escape_string($row['period_start'])."', '".mysql_real_escape_string($row['service_name'])."', - ".$row['calls'].", - ".(($row['calltype'] == 'http') ? $row['calls'] : 0).", - ".$row['runtime'].", - ".(($row['calltype'] == 'http') ? $row['runtime'] : 0)." + '".mysql_real_escape_string($row['calls'])."', + '".mysql_real_escape_string(($row['calltype'] == 'http') ? $row['calls'] : 0)."', + '".mysql_real_escape_string($row['runtime'])."', + '".mysql_real_escape_string(($row['calltype'] == 'http') ? $row['runtime'] : 0)."' ) on duplicate key update ".(($row['calltype'] == 'http') ? " - http_calls = http_calls + ".$row['calls'].", - http_runtime = http_runtime + ".$row['runtime'].", + http_calls = http_calls + '".mysql_real_escape_string($row['calls'])."', + http_runtime = http_runtime + '".mysql_real_escape_string($row['runtime'])."', " : "")." - total_calls = total_calls + ".$row['calls'].", - total_runtime = total_runtime + ".$row['runtime']." + total_calls = total_calls + '".mysql_real_escape_string($row['calls'])."', + total_runtime = total_runtime + '".mysql_real_escape_string($row['runtime'])."' "); } Db::execute("delete from okapi_stats_temp;"); diff --git a/htdocs/okapi/services/attrs/info.xml b/htdocs/okapi/services/attrs/info.xml index 2b6a15a5..8a0aed89 100644 --- a/htdocs/okapi/services/attrs/info.xml +++ b/htdocs/okapi/services/attrs/info.xml @@ -2,11 +2,11 @@ ALPHA: Get the list of all cache attributes 194 - This method is in its ALPHA stage. It's signature will most probably - change, or it might be removed altogether. You should not use it! + This method is in its ALPHA stage. It's signature WILL change, or it + might be removed altogether. You should not use it! - Not yet documented. You should not use this method. + Not yet documented. You should not use this method! \ No newline at end of file diff --git a/htdocs/okapi/services/caches/formatters/gpx.xml b/htdocs/okapi/services/caches/formatters/gpx.xml index b132b27b..057854b8 100644 --- a/htdocs/okapi/services/caches/formatters/gpx.xml +++ b/htdocs/okapi/services/caches/formatters/gpx.xml @@ -41,7 +41,7 @@ Boolean. If true then response will include Garmin's - Opencaching.com + OpenCaching.com GPX extension. This namespace declares an extra <opencaching> element used by Garmin's Opencaching.com. The element includes information on cache difficulty, ratings, tags and images. diff --git a/htdocs/okapi/services/caches/geocache.xml b/htdocs/okapi/services/caches/geocache.xml index a9d0819a..baa8caac 100644 --- a/htdocs/okapi/services/caches/geocache.xml +++ b/htdocs/okapi/services/caches/geocache.xml @@ -192,12 +192,14 @@
  • -

    preview_image - This is either null or a dictionary describing - an image, which has been marked by the owner as preview image. You are - encouraged to display it as a 'teaser' for this cache. - The structure of the dictionary is the same as in the images field above.

    -

    The preview image is no additional image but one of those which - are included in the images list.

    +

    preview_image - On some installations, owners may select one of the images + (see above) as a preview image. You are encouraged to display it as a 'teaser' + for this cache. On other installations this functionality is disabled and you + will always get the null value here.

    + +

    The value of preview_image is either null or a dictionary describing + an image. The structure of this dictionary is the same as of a single entry on + the images list described above.

  • attrnames - list of names of attributes of the cache; the language will diff --git a/htdocs/okapi/services/caches/geocaches.php b/htdocs/okapi/services/caches/geocaches.php index 010f7405..6f467b70 100644 --- a/htdocs/okapi/services/caches/geocaches.php +++ b/htdocs/okapi/services/caches/geocaches.php @@ -179,8 +179,8 @@ class WebService # PL branch: # - Caches have ratings. # - Total numbers of found and notfounds are kept in the "caches" table. - # - search_time is round trip and way_length one way; both can be null; - # 0 or null = not specified + # - search_time is round trip and way_length one way or both ways (this is different on OCDE!); + # both can be null; 0 or null = not specified $rs = Db::query(" select @@ -188,7 +188,7 @@ class WebService c.date_created, c.type, c.status, c.date_hidden, c.size, c.difficulty, c.terrain, c.wp_oc, c.logpw, c.user_id, if(c.search_time=0, null, c.search_time) as trip_time, - if(c.way_length=0, null, 2*c.way_length) as trip_distance, + if(c.way_length=0, null, c.way_length) as trip_distance, c.topratings, c.founds, @@ -850,17 +850,13 @@ class WebService # Country and/or state. - if (Settings::get('OC_BRANCH') == 'oc.de') - $cache_location_state = 'adm2'; - else - $cache_location_state = 'adm3'; if (in_array('country', $fields) || in_array('state', $fields)) { $rs = Db::query(" select c.wp_oc as cache_code, cl.adm1 as country, - cl.".$cache_location_state." as state + cl.".((Settings::get('OC_BRANCH') == 'oc.de') ? 'adm2' : 'adm3')." as state from caches c, cache_location cl @@ -1016,6 +1012,8 @@ class WebService } else { + # OC.de wants the tld in lowercase here + $site_name = ucfirst(strtolower($site_name)); if ($type == 'full') { $note = sprintf( diff --git a/htdocs/okapi/services/caches/map/replicate_listener.inc.php b/htdocs/okapi/services/caches/map/replicate_listener.inc.php index 11b85ab8..6e4fb9f7 100644 --- a/htdocs/okapi/services/caches/map/replicate_listener.inc.php +++ b/htdocs/okapi/services/caches/map/replicate_listener.inc.php @@ -174,17 +174,17 @@ class ReplicateListener # Most of these tiles aren't cached at all. We need to update # only the cached ones. - $alternatives = array(); + $alternatives_escaped = array(); foreach ($tiles_to_update as $coords) { list($z, $x, $y) = $coords; - $alternatives[] = "( + $alternatives_escaped[] = "( z = '".mysql_real_escape_string($z)."' and x = '".mysql_real_escape_string($x)."' and y = '".mysql_real_escape_string($y)."' )"; } - if (count($alternatives) > 0) + if (count($alternatives_escaped) > 0) { Db::execute(" replace into okapi_tile_caches ( @@ -197,11 +197,11 @@ class ReplicateListener '".mysql_real_escape_string($row[2])."', '".mysql_real_escape_string($row[3])."', '".mysql_real_escape_string($row[4])."', - ".(($row[5] === null) ? "null" : $row[5]).", + ".(($row[5] === null) ? "null" : "'".mysql_real_escape_string($row[5])."'").", '".mysql_real_escape_string($row[6])."' from okapi_tile_status where - (".implode(" or ", $alternatives).") + (".implode(" or ", $alternatives_escaped).") and status in (1,2) "); @@ -212,7 +212,7 @@ class ReplicateListener update okapi_tile_status set status=2 where - (".implode(" or ", $alternatives).") + (".implode(" or ", $alternatives_escaped).") and status=1 "); } @@ -231,7 +231,7 @@ class ReplicateListener set status = '".mysql_real_escape_string($row[3])."', type = '".mysql_real_escape_string($row[4])."', - rating = ".(($row[5] === null) ? "null" : $row[5]).", + rating = ".(($row[5] === null) ? "null" : "'".mysql_real_escape_string($row[5])."'").", flags = '".mysql_real_escape_string($row[6])."' where cache_id = '".mysql_real_escape_string($row[0])."' diff --git a/htdocs/okapi/services/caches/map/tiletree.inc.php b/htdocs/okapi/services/caches/map/tiletree.inc.php index 3ad7c8c8..4cac67d6 100644 --- a/htdocs/okapi/services/caches/map/tiletree.inc.php +++ b/htdocs/okapi/services/caches/map/tiletree.inc.php @@ -83,27 +83,30 @@ class TileTree $tile_upper_x = $x << 8; $tile_leftmost_y = $y << 8; + $zoom_escaped = "'".mysql_real_escape_string($zoom)."'"; + $tile_upper_x_escaped = "'".mysql_real_escape_string($tile_upper_x)."'"; + $tile_leftmost_y_escaped = "'".mysql_real_escape_string($tile_leftmost_y)."'"; return Db::query(" select otc.cache_id, - cast(otc.z21x >> (21 - $zoom) as signed) - $tile_upper_x as px, - cast(otc.z21y >> (21 - $zoom) as signed) - $tile_leftmost_y as py, + cast(otc.z21x >> (21 - $zoom_escaped) as signed) - $tile_upper_x_escaped as px, + cast(otc.z21y >> (21 - $zoom_escaped) as signed) - $tile_leftmost_y_escaped as py, otc.status, otc.type, otc.rating, otc.flags, count(*) from okapi_tile_caches otc, okapi_search_results osr where - z = '".mysql_real_escape_string($zoom)."' + z = $zoom_escaped and x = '".mysql_real_escape_string($x)."' and y = '".mysql_real_escape_string($y)."' and otc.cache_id = osr.cache_id and osr.set_id = '".mysql_real_escape_string($set_id)."' group by - z21x >> (3 + (21 - $zoom)), - z21y >> (3 + (21 - $zoom)) + z21x >> (3 + (21 - $zoom_escaped)), + z21y >> (3 + (21 - $zoom_escaped)) order by - z21y >> (3 + (21 - $zoom)), - z21x >> (3 + (21 - $zoom)) + z21y >> (3 + (21 - $zoom_escaped)), + z21x >> (3 + (21 - $zoom_escaped)) "); } @@ -161,7 +164,7 @@ class TileTree '".mysql_real_escape_string($row[2])."', '".mysql_real_escape_string($row[3])."', '".mysql_real_escape_string($row[4])."', - ".(($row[5] === null) ? "null" : $row[5]).", + ".(($row[5] === null) ? "null" : "'".mysql_real_escape_string($row[5])."'").", '".mysql_real_escape_string($row[6])."' ); "); diff --git a/htdocs/okapi/services/caches/search/save.php b/htdocs/okapi/services/caches/search/save.php index d1bf53ae..e51f25d8 100644 --- a/htdocs/okapi/services/caches/search/save.php +++ b/htdocs/okapi/services/caches/search/save.php @@ -80,6 +80,10 @@ class WebService return Okapi::formatted_response($request, $result); } + /** + * Important: YOU HAVE TO make sure $tables and $where_conds don't contain + * unescaped user-supplied data! + */ public static function get_set($tables, $where_conds, $min_store, $ref_max_age) { # Compute the "params hash". diff --git a/htdocs/okapi/services/caches/search/searching.inc.php b/htdocs/okapi/services/caches/search/searching.inc.php index 43ada092..4f3726d1 100644 --- a/htdocs/okapi/services/caches/search/searching.inc.php +++ b/htdocs/okapi/services/caches/search/searching.inc.php @@ -570,6 +570,9 @@ class SearchAssistant * the query, * - order_by - list or SQL clauses to be used with ORDER BY, * - limit - maximum number of cache codes to be returned. + * + * Important: YOU HAVE TO make sure that all options are properly sanitized + * for SQL queries! I.e. they cannot contain unescaped user-supplied data. */ public static function get_common_search_result($options) { diff --git a/htdocs/okapi/services/logs/entry.xml b/htdocs/okapi/services/logs/entry.xml index d9d9835c..cc7bfe29 100644 --- a/htdocs/okapi/services/logs/entry.xml +++ b/htdocs/okapi/services/logs/entry.xml @@ -14,8 +14,10 @@

  • cache_code - code of the cache which the log entry refers to,
  • date - date and time (ISO 8601) when the log entry was submitted.

    -

    Note, that some Opencaching servers don't store the exact times along - with the log entries.

    +

    Please note that log entries often contain dates only (with the times + truncated to midnight, as in the local timezone). In such cases, you may + want to avoid displaying the time. You may assume that if the date + value contains the "00:00:00" string, then it is date-only.

  • user - a dictionary:

    diff --git a/htdocs/okapi/services/logs/submit.php b/htdocs/okapi/services/logs/submit.php index 0cc85baf..9b9439c9 100644 --- a/htdocs/okapi/services/logs/submit.php +++ b/htdocs/okapi/services/logs/submit.php @@ -100,7 +100,7 @@ class WebService throw new InvalidParam('recommend', "Unknown option: '$recommend'."); $recommend = ($recommend == 'true'); if ($recommend && $logtype != 'Found it') - throw new BadRequest(_("Recommending is allowed only for 'Found it' logtypes.")); + throw new BadRequest("Recommending is allowed only for 'Found it' logtypes."); $needs_maintenance = $request->get_parameter('needs_maintenance'); if (!$needs_maintenance) $needs_maintenance = 'false'; @@ -165,10 +165,6 @@ class WebService if ($comment_format == 'plaintext') { - # If we would like to be compatible with old OCDE/OC.nl installation, - # "$comment_format == 'auto'" should go here, too. But we must choose - # to resemble either old OCDE or OCPL behaviour and opt for OCPL compatibility. - $formatted_comment = htmlspecialchars($comment, ENT_QUOTES); $formatted_comment = nl2br($formatted_comment); $value_for_text_html_field = 0; @@ -177,9 +173,9 @@ class WebService { if ($comment_format == 'auto') { - # This does not make sense on HTML comments, but it resembles the - # OCPL implementation and is needed for full compatibility with existing - # OKAPI clients. + # 'Auto' is for backward compatibility. Before the "comment_format" + # was introduced, OKAPI used a weird format in between (it allowed + # HTML, but applied nl2br too). $formatted_comment = nl2br($comment); } diff --git a/htdocs/okapi/services/logs/submit.xml b/htdocs/okapi/services/logs/submit.xml index 29d0f3c6..fdf41867 100644 --- a/htdocs/okapi/services/logs/submit.xml +++ b/htdocs/okapi/services/logs/submit.xml @@ -18,7 +18,7 @@

    Indicates the format of your comment. Three values allowed: - auto, html or plaintext. Usually, you should not + auto, html or plaintext. Usually, you should not use the auto option, because its exact behavior is unspecified and may depend on the installation (more info).

    diff --git a/htdocs/okapi/services/logs/userlogs.xml b/htdocs/okapi/services/logs/userlogs.xml index 7e00c565..3ad4d62f 100644 --- a/htdocs/okapi/services/logs/userlogs.xml +++ b/htdocs/okapi/services/logs/userlogs.xml @@ -23,8 +23,10 @@
  • uuid - ID of the log entry,
  • date - date and time (ISO 8601) when the log entry was submitted.

    -

    Note, that some Opencaching servers don't store the exact times along - with the log entries.

    +

    Please note that log entries often contain dates only (with the times + truncated to midnight, as in the local timezone). In such cases, you may + want to avoid displaying the time. You may assume that if the date + value contains the "00:00:00" string, then it is date-only.

  • cache_code - code of the geocache,
  • diff --git a/htdocs/okapi/views/devel/dbstruct.php b/htdocs/okapi/views/devel/dbstruct.php index 2bb57f23..2b853007 100644 --- a/htdocs/okapi/views/devel/dbstruct.php +++ b/htdocs/okapi/views/devel/dbstruct.php @@ -27,7 +27,8 @@ class View $user = Settings::get('DB_USERNAME'); $password = Settings::get('DB_PASSWORD'); $dbname = Settings::get('DB_NAME'); - $struct = shell_exec("mysqldump --no-data -u$user -p$password $dbname"); + $dbserver = Settings::get('DB_SERVER'); + $struct = shell_exec("mysqldump --no-data -h$dbserver -u$user -p$password $dbname"); # Remove the "AUTO_INCREMENT=..." values. They break the diffs. diff --git a/htdocs/okapi/views/update.php b/htdocs/okapi/views/update.php index 4e3934ac..169f8357 100644 --- a/htdocs/okapi/views/update.php +++ b/htdocs/okapi/views/update.php @@ -146,7 +146,7 @@ class View where sh.consumer_key = c.`key` and sh.service_name in ('".implode("','", array_map('mysql_real_escape_string', $service_names))."') - ".(($days != null) ? "and sh.period_start > date_add(now(), interval -".$days." day)" : "")." + ".(($days != null) ? "and sh.period_start > date_add(now(), interval '".mysql_real_escape_string(-$days)."' day)" : "")." "); }