add('name', PLUGIN_EVENT_GEOTAG_TITLE); $propbag->add('description', PLUGIN_EVENT_GEOTAG_DESC); $propbag->add('stackable', false); $propbag->add('author', PLUGIN_EVENT_GEOTAG_AUTHOR); $propbag->add('version', PLUGIN_EVENT_GEOTAG_VERSION); $propbag->add('requirements', array( 'serendipity' => '0.8', 'smarty' => '2.6.7', 'php' => '4.1.0' )); $propbag->add('event_hooks', array( 'backend_publish' => true, 'backend_save' => true, 'backend_display' => true, 'backend_delete_entry' => true, 'css' => true, 'entry_display' => true, 'frontend_entryproperties' => true, 'frontend_entryproperties_query' => true, 'frontend_fetchentries' => true, 'frontend_fetchentry' => true, 'frontend_display:rss-2.0:namespace' => true, 'frontend_display:rss-2.0:per_entry' => true, 'frontend_header' => true, 'external_plugin' => true, 'xmlrpc_updertEntry' => true, 'xmlrpc_deleteEntry' => true, )); $propbag->add('groups', array('BACKEND_EDITOR')); $propbag->add('configuration', array('content_geourl_warning', 'content_editor', 'api_key','init_latitude','init_longitude','zoom','editor_autofill', 'content_geotag_header', 'hdr_default_lat', 'hdr_default_long', 'content_footer', 'map_url_desc','map_url','map_link_blank','service', 'content_footer_list', 'geo_image', 'geo_image_height','geo_image_width','geo_image_zoom','geo_image_marker_size', 'content_footer_single', 'article_geo_image','article_geo_image_height','article_geo_image_width','article_geo_image_zoom','article_geo_image_marker_size', 'footer_example','article_example')); $this->supported_properties = array('geo_long', 'geo_lat'); } function introspect_config_item($name, &$propbag) { // // mid, small, normal $markers = array( 'tiny' => PLUGIN_EVENT_GEOTAG_IMAGE_MARKER_SIZE_TINY, 'small' => PLUGIN_EVENT_GEOTAG_IMAGE_MARKER_SIZE_SMALL, 'mid' => PLUGIN_EVENT_GEOTAG_IMAGE_MARKER_SIZE_MID, 'normal' => PLUGIN_EVENT_GEOTAG_IMAGE_MARKER_SIZE_NORMAL, ); switch($name) { case 'content_geourl_warning': $propbag->add('type', 'content'); if (class_exists('serendipity_event_geourl')) { $propbag->add('default', '
'. PLUGIN_EVENT_GEOTAG_WARNING_GEOURL_PLUGIN .'
'); } break; case 'content_editor': $propbag->add('type', 'content'); $propbag->add('default', '


' . PLUGIN_EVENT_GEOTAG_HEADER_EDITOR . '

'); break; case 'content_footer': $propbag->add('type', 'content'); $propbag->add('default', '


' . PLUGIN_EVENT_GEOTAG_HEADER_FOOTER . '

'); break; case 'content_footer_list': $propbag->add('type', 'content'); $propbag->add('default', '


' . PLUGIN_EVENT_GEOTAG_HEADER_FOOTER_LIST . '

'); break; case 'content_footer_single': $propbag->add('type', 'content'); $propbag->add('default', '


' . PLUGIN_EVENT_GEOTAG_HEADER_FOOTER_SINGLE . '

'); break; case 'content_geotag_header': $propbag->add('type', 'content'); $propbag->add('default', '


' . PLUGIN_EVENT_GEOTAG_HEADER_HDRTAG . '

' . PLUGIN_EVENT_GEOTAG_HEADER_HDRTAG_DESC); break; case 'footer_example': $propbag->add('type', 'content'); $propbag->add('default', '
Articlelist example:
'. $this->getFooterImage("Test Example", "52.47216", "13.44418", FALSE, TRUE) . '
'); break; case 'article_example': $propbag->add('type', 'content'); $propbag->add('default', '
Single article example:
'. $this->getFooterImage("Test Example", "52.47216", "13.44418", TRUE, TRUE) . '
'); break; case 'service': $propbag->add('type', 'select'); $propbag->add('select_values', array( 'google' => 'Google Maps', 'osm' => 'Openstreetmap', )); $propbag->add('name', PLUGIN_GEOTAG_SERVICE); $propbag->add('description', PLUGIN_EVENT_GEOTAG_SERVICE_DESC); $propbag->add('default', 'google'); break; case 'map_url_desc': $propbag->add('type', 'content'); $propbag->add('default', PLUGIN_EVENT_GEOTAG_MAP_DESC); break; case 'map_url': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_GEOTAG_MAP_URL); $propbag->add('default', 'http://www.openstreetmap.org/?mlat=%GEO_LAT%&mlon=%GEO_LONG%&zoom=15&layers=M'); break; case 'api_key': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_GEOTAG_API_KEY); $propbag->add('description', PLUGIN_EVENT_GEOTAG_API_KEY_DESC); break; case 'init_latitude': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_GEOTAG_LAT); $propbag->add('description', PLUGIN_EVENT_GEOTAG_LAT_DESC); break; case 'init_longitude': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_GEOTAG_LONG); $propbag->add('description', PLUGIN_EVENT_GEOTAG_LONG_DESC); break; case 'zoom': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_GEOTAG_ZOOM); $propbag->add('description', PLUGIN_EVENT_GEOTAG_ZOOM_DESC); $propbag->add('default', 14); break; case 'editor_autofill': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_EVENT_GEOTAG_EDITOR_AUTOFILL); $propbag->add('description', PLUGIN_EVENT_GEOTAG_EDITOR_AUTOFILL_DESC); $propbag->add('default', false); break; case 'map_link_blank': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_EVENT_GEOTAG_MAP_LINK_BLANK); $propbag->add('description', PLUGIN_EVENT_GEOTAG_MAP_LINK_BLANK_DESC); $propbag->add('default', false); break; // HTML HEAD tagging case 'hdr_default_lat': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_GEOTAG_HDRTAG_DEFAULT_LAT); $propbag->add('description', PLUGIN_EVENT_GEOTAG_HDRTAG_DEFAULT_LAT_DESC); break; case 'hdr_default_long': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_GEOTAG_HDRTAG_DEFAULT_LONG); $propbag->add('description', PLUGIN_EVENT_GEOTAG_HDRTAG_DEFAULT_LONG_DESC); break; // Footer article list case 'geo_image': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_EVENT_GEOTAG_SHOW_IMAGE); $propbag->add('description', PLUGIN_EVENT_GEOTAG_SHOW_IMAGE_DESC); $propbag->add('default', false); break; case 'geo_image_height': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_GEOTAG_SHOW_IMAGE_HEIGHT); $propbag->add('description', PLUGIN_EVENT_GEOTAG_SHOW_IMAGE_HEIGHT_DESC); $propbag->add('default', 20); break; case 'geo_image_width': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_GEOTAG_SHOW_IMAGE_WIDTH); $propbag->add('description', PLUGIN_EVENT_GEOTAG_SHOW_IMAGE_WIDTH_DESC); $propbag->add('default', 150); break; case 'geo_image_zoom': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_GEOTAG_SHOW_IMAGE_ZOOM); $propbag->add('description', PLUGIN_EVENT_GEOTAG_SHOW_IMAGE_ZOOM_DESC); $propbag->add('default', 10); break; case 'geo_image_marker_size': $propbag->add('type', 'select'); $propbag->add('name', PLUGIN_EVENT_GEOTAG_IMAGE_MARKER_SIZE); $propbag->add('description', PLUGIN_EVENT_GEOTAG_IMAGE_MARKER_SIZE_DESC); $propbag->add('select_values', $markers); $propbag->add('default', 'tiny'); break; // Footer single article case 'article_geo_image': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_EVENT_GEOTAG_SHOW_IMAGE); $propbag->add('description', PLUGIN_EVENT_GEOTAG_SHOW_IMAGE_DESC); $propbag->add('default', false); break; case 'article_geo_image_height': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_GEOTAG_SHOW_IMAGE); $propbag->add('description', PLUGIN_EVENT_GEOTAG_SHOW_IMAGE_HEIGHT_DESC); $propbag->add('default', 150); break; case 'article_geo_image_width': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_GEOTAG_SHOW_IMAGE_WIDTH); $propbag->add('description', PLUGIN_EVENT_GEOTAG_SHOW_IMAGE_WIDTH_DESC); $propbag->add('default', 200); break; case 'article_geo_image_zoom': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_GEOTAG_SHOW_IMAGE_ZOOM); $propbag->add('description', PLUGIN_EVENT_GEOTAG_SHOW_IMAGE_ZOOM_DESC); $propbag->add('default', 14); break; case 'article_geo_image_marker_size': $propbag->add('type', 'select'); $propbag->add('name', PLUGIN_EVENT_GEOTAG_IMAGE_MARKER_SIZE); $propbag->add('description', PLUGIN_EVENT_GEOTAG_IMAGE_MARKER_SIZE_DESC); $propbag->add('select_values', $markers); $propbag->add('default', 'small'); break; } return true; } /** * Will be called while saving settings */ function cleanup() { global $serendipity; // *Always* clean up the cache after changing configuration $cacheDir = $this->getCacheDirectory(); if (is_dir($cacheDir) && $handle = opendir($cacheDir)) { while (false !== ($file = readdir($handle))) { $filename = $cacheDir . '/' . $file; if (!is_dir($filename)) { unlink($filename); } } echo '
Footer map cache cleared
'; } // Cleanup of GeoURL plugin: ping the geourl service: if($this->get_config('hdr_default_lat') && $this->get_config('hdr_default_long')) { echo '
'; // Try to get the URL $geourl = "http://geourl.org/ping/?p=" . $serendipity['baseURL']; if (function_exists('serendipity_request_url')) { $data = serendipity_request_url($geourl); if (empty($data)) { printf(REMOTE_FILE_NOT_FOUND, $geourl); } else { echo PLUGIN_EVENT_GEOTAG_GEOURL_PINGED; } } else { include_once S9Y_PEAR_PATH . 'HTTP/Request.php'; $req = new HTTP_Request($geourl); if (PEAR::isError($req->sendRequest($geourl))) { printf(REMOTE_FILE_NOT_FOUND, $geourl); } else { echo PLUGIN_EVENT_GEOTAG_GEOURL_PINGED; } } echo '
'; } } function generate_content(&$title) { $title = $this->title; } function event_hook($event, &$bag, &$eventData, $addData = null) { global $serendipity; $hooks = &$bag->get('event_hooks'); $is_cache = serendipity_db_bool($this->get_config('cache', 'true')); if (isset($hooks[$event])) { switch($event) { // Cached Maps case 'external_plugin': $parts = explode('_', $eventData); if (count($parts)!=4) { return false; } $lat = $parts[1]; $long = $parts[2]; $isArticle = $parts[3] === 'a'; if ($parts[0] == 'fetchGeoTagMap') { // Fetch and cache it $this->fetchCacheMap($lat, $long, $isArticle); } else if ($parts[0] == 'cachedGeoTagMap') { // Load cached version $this->loadCachedMap($lat, $long, $isArticle); } break; case 'backend_display': if (isset($eventData['properties']['geo_long'])) { $geo_long = $eventData['properties']['geo_long']; } elseif (isset($serendipity['POST']['properties']['geo_long'])) { $geo_long = $serendipity['POST']['properties']['geo_long']; } else { $geo_long = ""; } if (isset($eventData['properties']['geo_lat'])) { $geo_lat = $eventData['properties']['geo_lat']; } elseif (isset($serendipity['POST']['properties']['geo_lat'])) { $geo_lat = $serendipity['POST']['properties']['geo_lat']; } else { $geo_lat = ""; } // initialise from config $initZoom = $this->get_config('zoom', 14); $autofill_editor = serendipity_db_bool($this->get_config('editor_autofill',false)); ?>
get_config('api_key') !== ''): ?>

get_config('api_key'))!="") { ?>
supported_properties, $serendipity['POST']['properties']); return true; case 'backend_delete_entry': GeoTagDb::delete($eventData['id'], $this->supported_properties); return true; case 'frontend_entryproperties': $q = "SELECT entryid, property, value FROM {$serendipity['dbPrefix']}entryproperties WHERE entryid IN (" . implode(', ', array_keys($addData)) . ")"; $properties = serendipity_db_query($q); if (!is_array($properties)) { return true; } foreach($properties AS $idx => $row) { $eventData[$addData[$row['entryid']]]['properties'][$row['property']] = $row['value']; } return true; case 'css': if (strpos($eventData, '.serendipity_geotag')) { // class exists in CSS, so a user has customized it and we don't need default return true; } ?> .serendipity_plugin_geotag img { max-width: none !important; } &$myEvent) { if ($i !== 'clean_page') { // Check if geo_lat and geo_long are both set $props = $myEvent['properties'] ?? null; $geotagged = true; foreach($this->supported_properties AS $prop_key) { if (!isset($props[$prop_key])) { $geotagged = false; } } if ($geotagged) { if (!isset($myEvent['add_footer'])) { $myEvent['add_footer'] = ""; } // If extended is set, it's a single article $singleArticle = $addData['extended']; $myEvent['add_footer'] .= $this->getFooterImage($myEvent['title'], $props["geo_lat"], $props["geo_long"],$singleArticle); } } } } return true; case 'frontend_header': if (!($serendipity['GET']['id'] ?? 0) && $serendipity['view'] != 'entry') { $lat = $this->get_config('hdr_default_lat'); $long = $this->get_config('hdr_default_long'); $this->headerGeoTagging($lat, $long, $GLOBALS['serendipity']['blogTitle']); return true; } // we fetch the internal smarty object to get the current entry body $entry = (array)$eventData['smarty']->tpl_vars['entry']->value; $props = $entry['properties']; $geotagged = true; foreach($this->supported_properties AS $prop_key) { if (!isset($props[$prop_key])) { $geotagged = false; } } if ($geotagged) { // echo ""; $this->headerGeoTagging($props["geo_lat"], $props["geo_long"], $entry['title']); } else { $long = $this->get_config('hdr_default_lat'); $lat = $this->get_config('hdr_default_long'); $this->headerGeoTagging($lat,$long, $GLOBALS['serendipity']['blogTitle']); } break; case 'frontend_display:rss-2.0:namespace': $eventData['display_dat'] .= ' xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" '; return true; case 'frontend_display:rss-2.0:per_entry': // Check if geo_lat and geo_long are both set $props = &$eventData['properties']; foreach($this->supported_properties AS $prop_key) { if (!isset($props[$prop_key])) { return true; } } $eventData['display_dat'] = '' . $props["geo_long"] . ''; $eventData['display_dat'] .= '' . $props["geo_lat"] . ''; return true; case 'xmlrpc_deleteEntry': GeoTagDb::delete($eventData['id'], $this->supported_properties); return true; case 'xmlrpc_updertEntry': GeoTagDb::addEntryProperties($eventData['id'], $this->supported_properties, $eventData, false); return true; default: return false; } } else { return false; } } function getFooterImage($title, $lat, $long, $article=FALSE, $uncached=FALSE) { global $serendipity; $config_pre = $article?'article_':''; $use_image= serendipity_db_bool($this->get_config($config_pre.'geo_image',false)); $use_targetblank = serendipity_db_bool($this->get_config('map_link_blank',false)); $replace_by = isset($title) ? urlencode($title) : "GeoTag"; if ($use_image) { // Mit Karte if ($uncached) { $imgLink = $this->createMapImageLink($lat, $long, $article); } else { $cachedFileName = $this->getCacheFilePath($lat, $long, $article); if (file_exists($cachedFileName)) { $imgLink = $serendipity['baseURL'] . $serendipity['indexFile'] . '?/' . $this->getPermaPluginPath() . '/cachedGeoTagMap_' . $lat . '_' . $long . '_' . ($article?'a':'l'); } else { // fetchGeoTagMap $imgLink = $serendipity['baseURL'] . $serendipity['indexFile'] . '?/' . $this->getPermaPluginPath() . '/fetchGeoTagMap_' . $lat . '_' . $long . '_' . ($article?'a':'l'); } } $img_title = PLUGIN_EVENT_GEOTAG_SHOW_IMAGE_TITLE; $linkdesc = ""; $msg = '
%s
'; } else { $linkdesc = "%GEO_LAT%, %GEO_LONG%"; $msg = '
' . PLUGIN_EVENT_GEOTAG_FRONTEND_LABEL . ': %s
'; } // Write the link $link = "get_config('map_url') . "\"" . ($use_targetblank?" target=\"_blank\"":"") .">$linkdesc"; $link = str_replace("%GEO_LAT%", preg_replace('@[^0-9\.,\-]@i', '', $lat), $link); $link = str_replace("%GEO_LONG%", preg_replace('@[^0-9\.,\-]@i', '', $long), $link); $link = str_replace("%TITLE%", $replace_by, $link); return sprintf($msg,$link); } function createMapImageLink($lat, $long, $article) { global $serendipity; $config_pre = $article?'article_':''; $use_imageheight = $this->get_config($config_pre . 'geo_image_height',$article?150:20); if (!is_numeric($use_imageheight)) $use_imageheight=$article?150:20; $use_imagewidth = $this->get_config($config_pre.'geo_image_width',$article?200:150); if (!is_numeric($use_imagewidth)) $use_imagewidth=$article?200:150; $use_zoom = $this->get_config($config_pre.'geo_image_zoom', $article?14:10); if (!is_numeric($use_zoom)) $use_zoom=$article?14:10; $markersize = $this->get_config($config_pre.'geo_image_marker_size','tiny'); //maptype=osmarenderer& $osmImgLink = "http://staticmap.openstreetmap.de/staticmap.php?center=%GEO_LAT%,%GEO_LONG%&zoom=$use_zoom&size=".$use_imagewidth."x".$use_imageheight."&markers=%GEO_LAT%,%GEO_LONG%,ol-marker-blue"; $googleImgLink = "http://maps.google.com/maps/api/staticmap?markers=color:blue|size:$markersize|label:Bl|%GEO_LAT%,%GEO_LONG%&size=".$use_imagewidth."x".$use_imageheight."&sensor=true&zoom=$use_zoom"; $imgLink = ($service = $this->get_config('service','google')==='google')? $googleImgLink:$osmImgLink; $imgLink = str_replace("%GEO_LAT%", preg_replace('@[^0-9\.,\-]@i', '', $lat), $imgLink); $imgLink = str_replace("%GEO_LONG%", preg_replace('@[^0-9\.,\-]@i', '', $long), $imgLink); return $imgLink; } function headerGeoTagging($lat, $long, $title) { if (empty($lat) || empty($long)) return; $title = (function_exists('serendipity_specialchars') ? serendipity_specialchars($title) : htmlspecialchars($title, ENT_COMPAT, LANG_CHARSET)); echo '' . "\n"; echo '' . "\n"; echo '' . "\n"; echo '' . "\n"; echo '' . "\n"; } // ======= MAP CACHING START ======================================================================================== function log($message) { if (!PLUGIN_EVENT_GEOTAG_DEBUG) return; $fp = fopen($this->getCacheDirectory() . '.log','a'); fwrite($fp, $message . "\n"); fflush($fp); fclose($fp); } function fetchCacheMap($lat, $long, $isArticle) { $this->log("lat: $lat long: $long a: $isArticle"); $url = $this->createMapImageLink($lat, $long, $isArticle); $this->log($url); $this->saveAndResponseMap($url, $lat, $long, $isArticle); } function loadCachedMap($lat, $long, $isArticle) { $filename = $this->getCacheFilePath($lat, $long, $isArticle); $this->showMap($filename); } /** * Caches a map and streams it back to the browser. */ function saveAndResponseMap($url, $lat, $long, $isArticle) { global $serendipity; $fContent = null; if (function_exists('serendipity_request_url')) { $fContent = serendipity_request_url($url); } else { require_once S9Y_PEAR_PATH . 'HTTP/Request.php'; if (function_exists('serendipity_request_start')) { serendipity_request_start(); } $request_pars['allowRedirects'] = TRUE; $req = new HTTP_Request($url, $request_pars); // if the request leads to an error we don't want to have it: return false if (PEAR::isError($req->sendRequest()) || ($req->getResponseCode() != '200')) { $fContent = null; } else { // Allow only images! $mime = $req->getResponseHeader("content-type"); $mimeparts = explode('/',$mime); if (count($mimeparts)==2 && $mimeparts[0]=='image') { $fContent = $req->getResponseBody(); } } if (function_exists('serendipity_request_start')) { serendipity_request_end(); } } // if no content was fetched, return false if (!isset($fContent)){ return false; } $cache_file = $this->cacheMap($lat, $long, $isArticle, $fContent, $req); if ($cache_file) { $this->showMap($cache_file); } return true; } function cacheMap($lat, $long, $isArticle, $fContent){ $cache_file = $this->getCacheFilePath($lat, $long, $isArticle); if (file_exists($cache_file)) return $cache_file; // Save image @mkdir($this->getCacheDirectory()); $fp = @fopen($cache_file, 'wb'); if (!$fp) { if (file_exists($cache_file)) { return $cache_file; } else { return false; } } fwrite($fp, $fContent); fclose($fp); return $cache_file; } /** * Return binary response for an image */ function showMap($filename) { if (!file_exists($filename)) { header('X-GeoTag: No-Image'); return false; } else { header('X-GeoTag: Found'); } $size = @getimagesize($filename); $mime_type = $size['mime']; $this->avatarConfiguration['mime-type'] = $mime_type; // test wether this really is (at least declared as) an image! // else deny it. $mime_parts = explode('/', $mime_type); if (count($mime_parts)!=2 || $mime_parts[0]!='image') { return false; } $fp = @fopen($filename, "rb"); if ($fp) { $nextcheck = time() + (60*60*24*7); // invalidate 7 days later $expires_txt = date("D, d M Y H:i:s T",(int)$nextcheck); $filemtime = filemtime($filename); header("Content-type: $mime_type"); header("Content-Length: ". filesize($filename)); header("Date: " . date("D, d M Y H:i:s T")); header("Last-Modified: " . date("D, d M Y H:i:s T", $filemtime), true); header("Cache-Control: public, max-age=" . ((int)$nextcheck - time()) , true); header("Expires: $expires_txt". true); header("Pragma:", true); fpassthru($fp); fclose($fp); } return true; } /** * Returns the cache directory */ function getCacheDirectory(){ global $serendipity; if (($this->cache_dir ?? null) === null) { $this->cache_dir = $serendipity['serendipityPath'] . PATH_SMARTY_COMPILE . '/serendipity_event_geotag'; } return $this->cache_dir; } function getCacheFilePath($lat, $long, $isarticle=FALSE){ global $serendipity; $cache_filename = ($isarticle?'a':'l') . md5($lat . "|" . $long); return $this->getCacheDirectory() .'/' . $cache_filename;; } function getPermaPluginPath() { global $serendipity; // Get configured plugin path: $pluginPath = 'plugin'; if (isset($serendipity['permalinkPluginPath'])){ $pluginPath = $serendipity['permalinkPluginPath']; } return $pluginPath; } // ======= MAP CACHING END ========================================================================================== }