| @@ -1,10 +1,8 @@ | ||
| 1 | 1 | <?php |
| 2 | 2 | /** |
| 3 | 3 | * Leaflet Map Class File |
| 4 | 4 | * |
| 5 | - * PHP Version 5.5 | |
| 6 | - * | |
| 7 | 5 | * @category Admin |
| 8 | 6 | * @author Benjamin J DeLong <ben@bozdoz.com> |
| 9 | 7 | */ |
| 10 | 8 | |
| @@ -23,9 +21,9 @@ | ||
| 23 | 21 | * Leaflet version |
| 24 | 22 | * |
| 25 | 23 | * @var string major minor patch version |
| 26 | 24 | */ |
| 27 | - public static $leaflet_version = '1.6.0'; | |
| 25 | + public static $leaflet_version = '1.9.4'; | |
| 28 | 26 | |
| 29 | 27 | /** |
| 30 | 28 | * Files to include upon init |
| 31 | 29 | * |
| @@ -47,8 +45,12 @@ | ||
| 47 | 45 | 'leaflet-gpx' => array( |
| 48 | 46 | 'file' => 'class.gpx-shortcode.php', |
| 49 | 47 | 'class' => 'Leaflet_Gpx_Shortcode' |
| 50 | 48 | ), |
| 49 | + 'leaflet-wms' => array( | |
| 50 | + 'file' => 'class.wms-shortcode.php', | |
| 51 | + 'class' => 'Leaflet_Wms_Shortcode' | |
| 52 | + ), | |
| 51 | 53 | 'leaflet-line' => array( |
| 52 | 54 | 'file' => 'class.line-shortcode.php', |
| 53 | 55 | 'class' => 'Leaflet_Line_Shortcode' |
| 54 | 56 | ), |
| @@ -66,9 +68,21 @@ | ||
| 66 | 68 | ), |
| 67 | 69 | 'leaflet-marker' => array( |
| 68 | 70 | 'file' => 'class.marker-shortcode.php', |
| 69 | 71 | 'class' => 'Leaflet_Marker_Shortcode' |
| 70 | - ) | |
| 72 | + ), | |
| 73 | + 'leaflet-scale' => array( | |
| 74 | + 'file' => 'class.scale-shortcode.php', | |
| 75 | + 'class' => 'Leaflet_Scale_Shortcode' | |
| 76 | + ), | |
| 77 | + 'leaflet-image-overlay' => array( | |
| 78 | + 'file' => 'class.image-overlay-shortcode.php', | |
| 79 | + 'class' => 'Leaflet_Image_Overlay_Shortcode' | |
| 80 | + ), | |
| 81 | + 'leaflet-video-overlay' => array( | |
| 82 | + 'file' => 'class.video-overlay-shortcode.php', | |
| 83 | + 'class' => 'Leaflet_Video_Overlay_Shortcode' | |
| 84 | + ), | |
| 71 | 85 | ); |
| 72 | 86 | |
| 73 | 87 | /** |
| 74 | 88 | * Singleton Instance of Leaflet Map |
| @@ -226,10 +240,50 @@ | ||
| 226 | 240 | return array_filter($arr, 'remove_null'); |
| 227 | 241 | } |
| 228 | 242 | |
| 229 | 243 | /** |
| 230 | - * Sanitize JSON | |
| 244 | + * Filter for removing empty strings from array | |
| 231 | 245 | * |
| 246 | + * @param array $arr | |
| 247 | + * | |
| 248 | + * @return array with empty strings removed | |
| 249 | + */ | |
| 250 | + public function filter_empty_string($arr) | |
| 251 | + { | |
| 252 | + if (!function_exists('remove_empty_string')) { | |
| 253 | + function remove_empty_string ($var) { | |
| 254 | + return $var !== ""; | |
| 255 | + } | |
| 256 | + } | |
| 257 | + | |
| 258 | + return array_filter($arr, 'remove_empty_string'); | |
| 259 | + } | |
| 260 | + | |
| 261 | + /** | |
| 262 | + * Sanitize any given validations, but concatenate with the remaining keys from $arr | |
| 263 | + */ | |
| 264 | + public function sanitize_inclusive($arr, $validations) { | |
| 265 | + return array_merge( | |
| 266 | + $arr, | |
| 267 | + $this->sanitize_exclusive($arr, $validations) | |
| 268 | + ); | |
| 269 | + } | |
| 270 | + | |
| 271 | + /** | |
| 272 | + * Sanitize and return ONLY given validations | |
| 273 | + */ | |
| 274 | + public function sanitize_exclusive($arr, $validations) { | |
| 275 | + // remove nulls | |
| 276 | + $arr = $this->filter_null($arr); | |
| 277 | + | |
| 278 | + // sanitize output | |
| 279 | + $args = array_intersect_key($validations, $arr); | |
| 280 | + return filter_var_array($arr, $args); | |
| 281 | + } | |
| 282 | + | |
| 283 | + /** | |
| 284 | + * Sanitize JSON | |
| 285 | + * | |
| 232 | 286 | * Takes options for filtering/correcting inputs for use in JavaScript |
| 233 | 287 | * |
| 234 | 288 | * @param array $arr user-input array |
| 235 | 289 | * @param array $args array with key-value definitions on how to convert values |
| @@ -236,16 +290,18 @@ | ||
| 236 | 290 | * @return array corrected for JavaScript |
| 237 | 291 | */ |
| 238 | 292 | public function json_sanitize($arr, $args) |
| 239 | 293 | { |
| 240 | - // remove nulls | |
| 241 | - $arr = $this->filter_null($arr); | |
| 294 | + $arr = $this->sanitize_exclusive($arr, $args); | |
| 242 | 295 | |
| 243 | - // sanitize output | |
| 244 | - $args = array_intersect_key($args, $arr); | |
| 245 | - $arr = filter_var_array($arr, $args); | |
| 296 | + $output = json_encode($arr); | |
| 246 | 297 | |
| 247 | - return json_encode($arr); | |
| 298 | + // always return object; not array | |
| 299 | + if ($output === '[]') { | |
| 300 | + $output = '{}'; | |
| 301 | + } | |
| 302 | + | |
| 303 | + return $output; | |
| 248 | 304 | } |
| 249 | 305 | |
| 250 | 306 | /** |
| 251 | 307 | * Get Style JSON for map shapes/geojson (svg or canvas) |
| @@ -258,9 +314,9 @@ | ||
| 258 | 314 | */ |
| 259 | 315 | public function get_style_json($atts) |
| 260 | 316 | { |
| 261 | 317 | if ($atts) { |
| 262 | - extract($atts); | |
| 318 | + extract($atts, EXTR_SKIP); | |
| 263 | 319 | } |
| 264 | 320 | |
| 265 | 321 | // from http://leafletjs.com/reference-1.0.3.html#path |
| 266 | 322 | $style = array( |
| @@ -281,20 +337,20 @@ | ||
| 281 | 337 | ); |
| 282 | 338 | |
| 283 | 339 | $args = array( |
| 284 | 340 | 'stroke' => FILTER_VALIDATE_BOOLEAN, |
| 285 | - 'color' => FILTER_SANITIZE_STRING, | |
| 341 | + 'color' => FILTER_SANITIZE_FULL_SPECIAL_CHARS, | |
| 286 | 342 | 'weight' => FILTER_VALIDATE_FLOAT, |
| 287 | 343 | 'opacity' => FILTER_VALIDATE_FLOAT, |
| 288 | - 'lineCap' => FILTER_SANITIZE_STRING, | |
| 289 | - 'lineJoin' => FILTER_SANITIZE_STRING, | |
| 290 | - 'dashArray' => FILTER_SANITIZE_STRING, | |
| 291 | - 'dashOffset' => FILTER_SANITIZE_STRING, | |
| 344 | + 'lineCap' => FILTER_SANITIZE_FULL_SPECIAL_CHARS, | |
| 345 | + 'lineJoin' => FILTER_SANITIZE_FULL_SPECIAL_CHARS, | |
| 346 | + 'dashArray' => FILTER_SANITIZE_FULL_SPECIAL_CHARS, | |
| 347 | + 'dashOffset' => FILTER_SANITIZE_FULL_SPECIAL_CHARS, | |
| 292 | 348 | 'fill' => FILTER_VALIDATE_BOOLEAN, |
| 293 | - 'fillColor' => FILTER_SANITIZE_STRING, | |
| 349 | + 'fillColor' => FILTER_SANITIZE_FULL_SPECIAL_CHARS, | |
| 294 | 350 | 'fillOpacity' => FILTER_VALIDATE_FLOAT, |
| 295 | - 'fillRule' => FILTER_SANITIZE_STRING, | |
| 296 | - 'className' => FILTER_SANITIZE_STRING, | |
| 351 | + 'fillRule' => FILTER_SANITIZE_FULL_SPECIAL_CHARS, | |
| 352 | + 'className' => FILTER_SANITIZE_FULL_SPECIAL_CHARS, | |
| 297 | 353 | 'radius' => FILTER_VALIDATE_FLOAT |
| 298 | 354 | ); |
| 299 | 355 | |
| 300 | 356 | return $this->json_sanitize($style, $args); |
| @@ -313,27 +369,49 @@ | ||
| 313 | 369 | */ |
| 314 | 370 | public function add_popup_to_shape($atts, $content, $shape) |
| 315 | 371 | { |
| 316 | 372 | if (!empty($atts)) { |
| 317 | - extract($atts); | |
| 373 | + // don't overwrite existing variables | |
| 374 | + extract($atts, EXTR_SKIP); | |
| 318 | 375 | } |
| 319 | 376 | |
| 320 | 377 | $message = empty($message) ? |
| 321 | 378 | (empty($content) ? '' : $content) : $message; |
| 379 | + | |
| 380 | + if (empty($message)) { | |
| 381 | + return; | |
| 382 | + } | |
| 383 | + | |
| 384 | + // save variable for filter | |
| 385 | + $original = $message; | |
| 386 | + | |
| 387 | + // execute shortcodes if present: | |
| 388 | + // e.g. [leaflet-marker][some-shortcode][/leaflet-marker] | |
| 389 | + $message = do_shortcode($message); | |
| 390 | + | |
| 391 | + // save variable for filter | |
| 392 | + $shortcoded = $message; | |
| 393 | + | |
| 322 | 394 | $message = str_replace(array("\r\n", "\n", "\r"), '<br>', $message); |
| 323 | - $message = addslashes($message); | |
| 324 | - $message = htmlspecialchars($message); | |
| 395 | + $message = wp_kses_post( $message ); | |
| 396 | + $message = esc_html( $message ); | |
| 397 | + | |
| 398 | + $message = "window.WPLeafletMapPlugin.unescape('{$message}')"; | |
| 399 | + | |
| 400 | + // use with: add_filter('leaflet_map_popup_message', 'example_callback', 10, 3); | |
| 401 | + // function takes default message, message after do_shortcode, and original/raw | |
| 402 | + $message = apply_filters('leaflet_map_popup_message', $message, $shortcoded, $original); | |
| 403 | + | |
| 404 | + echo "{$shape}.bindPopup({$message})"; | |
| 405 | + | |
| 325 | 406 | $visible = empty($visible) |
| 326 | 407 | ? false |
| 327 | 408 | : filter_var($visible, FILTER_VALIDATE_BOOLEAN); |
| 328 | - | |
| 329 | - if (!empty($message)) { | |
| 330 | - echo "{$shape}.bindPopup(window.WPLeafletMapPlugin.unescape('{$message}'))"; | |
| 331 | - if ($visible) { | |
| 332 | - echo ".openPopup()"; | |
| 333 | - } | |
| 334 | - echo ";"; | |
| 409 | + | |
| 410 | + if ($visible) { | |
| 411 | + echo ".openPopup()"; | |
| 335 | 412 | } |
| 413 | + echo ";"; | |
| 336 | 414 | } |
| 337 | 415 | |
| 338 | 416 | /** |
| 339 | 417 | * Get settings from Leaflet_Map_Plugin_Settings |
| @@ -341,6 +419,113 @@ | ||
| 341 | 419 | */ |
| 342 | 420 | public static function settings () { |
| 343 | 421 | include_once LEAFLET_MAP__PLUGIN_DIR . 'class.plugin-settings.php'; |
| 344 | 422 | return Leaflet_Map_Plugin_Settings::init(); |
| 423 | + } | |
| 424 | + | |
| 425 | + /** | |
| 426 | + * Parses liquid tags from a string | |
| 427 | + * | |
| 428 | + * @param string $str | |
| 429 | + * | |
| 430 | + * @return array|null | |
| 431 | + */ | |
| 432 | + public function liquid ($str) { | |
| 433 | + if (!is_string($str)) { | |
| 434 | + return null; | |
| 435 | + } | |
| 436 | + $templateRegex = "/\{ *(.*?) *\}/"; | |
| 437 | + preg_match_all($templateRegex, $str, $matches); | |
| 438 | + | |
| 439 | + if (!$matches[1]) { | |
| 440 | + return null; | |
| 441 | + } | |
| 442 | + | |
| 443 | + $str = $matches[1][0]; | |
| 444 | + | |
| 445 | + $tags = explode(' | ', $str); | |
| 446 | + | |
| 447 | + $original = array_shift($tags); | |
| 448 | + | |
| 449 | + if (!$tags) { | |
| 450 | + return null; | |
| 451 | + } | |
| 452 | + | |
| 453 | + $output = array(); | |
| 454 | + | |
| 455 | + foreach ($tags as $tag) { | |
| 456 | + $tagParts = explode(': ', $tag); | |
| 457 | + $tagName = array_shift($tagParts); | |
| 458 | + $tagValue = implode(': ', $tagParts) || true; | |
| 459 | + | |
| 460 | + $output[$tagName] = $tagValue; | |
| 461 | + } | |
| 462 | + | |
| 463 | + // preserve the original | |
| 464 | + $output['original'] = $original; | |
| 465 | + | |
| 466 | + return $output; | |
| 467 | + } | |
| 468 | + | |
| 469 | + /** | |
| 470 | + * Renders a json-like string, removing quotes for values | |
| 471 | + * | |
| 472 | + * allows JavaScript variables to be added directly | |
| 473 | + * | |
| 474 | + * @return string | |
| 475 | + */ | |
| 476 | + public function rawDict ($arr) { | |
| 477 | + $obj = '{'; | |
| 478 | + | |
| 479 | + foreach ($arr as $key=>$val) { | |
| 480 | + // removes any JS function calls | |
| 481 | + $safe_val = preg_replace('/[^a-zA-Z0-9_$.!]/', '', $val); | |
| 482 | + $obj .= "\"$key\": $safe_val,"; | |
| 483 | + } | |
| 484 | + | |
| 485 | + $obj .= '}'; | |
| 486 | + | |
| 487 | + return $obj; | |
| 488 | + } | |
| 489 | + | |
| 490 | + /** | |
| 491 | + * Filter all floats to remove commas, force decimals, and validate float | |
| 492 | + * see: https://wordpress.org/support/topic/all-maps-are-gone/page/3/#post-14625548 | |
| 493 | + */ | |
| 494 | + public function filter_float ($flt) { | |
| 495 | + // make sure the value actually is a float | |
| 496 | + $out = filter_var($flt, FILTER_VALIDATE_FLOAT); | |
| 497 | + | |
| 498 | + // some locales seem to force commas | |
| 499 | + $out = str_replace(',', '.', $out); | |
| 500 | + | |
| 501 | + return $out; | |
| 502 | + } | |
| 503 | + | |
| 504 | + /** | |
| 505 | + * Bounds are given as "50, -114; 52, -112" | |
| 506 | + * Converted to 2d-array: [[50, -114], [52, -112]] | |
| 507 | + */ | |
| 508 | + public function convert_bounds_str_to_arr ($bounds) { | |
| 509 | + if (isset($bounds)) { | |
| 510 | + try { | |
| 511 | + // explode by semi-colons and commas | |
| 512 | + $arr = preg_split("[;|,]", $bounds); | |
| 513 | + | |
| 514 | + return array( | |
| 515 | + array( | |
| 516 | + $this->filter_float($arr[0]), | |
| 517 | + $this->filter_float($arr[1]) | |
| 518 | + ), | |
| 519 | + array( | |
| 520 | + $this->filter_float($arr[2]), | |
| 521 | + $this->filter_float($arr[3]) | |
| 522 | + ) | |
| 523 | + ); | |
| 524 | + } catch (Exception $e) { | |
| 525 | + return null; | |
| 526 | + } | |
| 527 | + } | |
| 528 | + | |
| 529 | + return null; | |
| 345 | 530 | } |
| 346 | 531 | } |