title; } function install() { $this->cleanup(); } function cleanup() { global $serendipity; serendipity_plugin_api::hook_event('backend_cache_entries', $this->title); // create directory to store external images from articles $upload_dir = $serendipity['serendipityPath'] . $serendipity['uploadPath'] . 'plugin_mobile_output/'; if(!file_exists($upload_dir)) { mkdir($upload_dir); } // Copy templates to template folder, if not existing $this->copyTemplate(PLUGIN_EVENT_MOBILE_TPL_IPHONE); $this->copyTemplate(PLUGIN_EVENT_MOBILE_TPL_ANDROID); $this->copyTemplate(PLUGIN_EVENT_MOBILE_TPL_XHTML); } private function copyTemplate( $localName ) { $src_template_meta = new serendipity_template_meta('plugins/serendipity_event_mobile_output/templates/' . $localName); $dst_template_meta = new serendipity_template_meta($localName); if (@file_exists($src_template_meta->getTemplateDir()) && !(@file_exists($dst_template_meta->getTemplateDir()))) { $this->recurse_dircopy($src_template_meta->getTemplateDir(), $dst_template_meta->getTemplateDir()); } } function uninstall(&$propbag) { global $serendipity; serendipity_plugin_api::hook_event('backend_cache_purge', $this->title); serendipity_plugin_api::hook_event('backend_cache_entries', $this->title); // delete directory with external images from articles $upload_dir = $serendipity['serendipityPath'] . $serendipity['uploadPath'] . 'plugin_mobile_output/'; if( is_dir($upload_dir) ) { // delete all files in the upload directory $files = glob($upload_dir.'*'); if( is_array($files) && !empty($files) ) { foreach($files as $file) { @unlink($file); } } @rmdir($upload_dir); } } function introspect(&$propbag) { global $serendipity; $propbag->add('name', PLUGIN_EVENT_MOBILE_OUTPUT_NAME); $propbag->add('description', PLUGIN_EVENT_MOBILE_OUTPUT_DESC); $propbag->add('stackable', false); $propbag->add('author', PLUGIN_EVENT_MOBILE_AUTHORS); $propbag->add('website', 'http://c.mobile-seo.de/'); $propbag->add('version', PLUGIN_EVENT_MOBILE_VERSION); $propbag->add('requirements', array( 'serendipity' => '1.0', 'smarty' => '2.6.7', 'php' => '5.0.0', )); $propbag->add('cachable_events', array('frontend_display' => true)); $propbag->add('groups', array('MARKUP')); $propbag->add('configuration', array( 'enable', 'mobile_template', 'iphone_template', 'android_template', 'categories', 'smallteaser', 'images', 'scale_image_width', 'wurfl', 'redirect', 'redirect_url', 'sticky_host', 'remove_tags', 'remove_attributes', 'rewrite_wikipedia', 'sitemap', 'sitemap_pingback', 'sitemap_pingback_urls', 'gzip_sitemap', 'debug_password', )); $propbag->add('event_hooks', array( 'backend_publish' => true, 'backend_save' => true, 'frontend_configure' => true, 'entry_display' => true, )); return true; } function example() { $template = $this->get_config('iphone_template'); $template_meta = new serendipity_template_meta($template); $s = ''; if (!@file_exists($template_meta->getTemplateDir())) { $s .= "Template " . $template . " not installed. You will find one for each type in the plugin directory."; $s .= "
"; } $template = $this->get_config('android_template'); $template_meta = new serendipity_template_meta($template); if (!@file_exists($template_meta->getTemplateDir())) { $s .= "Template " . $template . " not installed. You will find one for each type in the plugin directory."; $s .= "
"; } $template = $this->get_config('mobile_template'); $template_meta = new serendipity_template_meta($template); if (!@file_exists($template_meta->getTemplateDir())) { $s .= "Template " . $template . " not installed. You will find one for each type in the plugin directory."; $s .= "
"; } return $s; } function event_hook($event, &$bag, &$eventData, $addData = null) { global $serendipity; $hooks = &$bag->get('event_hooks'); if(isset($hooks[$event])) { switch($event) { //////////////////////////////////////////////////////////////////// // SITEMAP //////////////////////////////////////////////////////////////////// case 'backend_publish': case 'backend_save': if($this->get_config('sitemap')) $this->generateSitemap($bag); return true; break; } } // plugin enabled? if(!$this->get_config('enable')) return false; // get instance of serendipity_mobile class $this->m = serendipity_mobile::getInstance($this->debugItems); // mobile device? if(!$this->m->isMobileDevice && $_SERVER['HTTP_HOST']!=$this->get_config('sticky_host')) return false; if($this->m->isMobileDevice) $this->debugItems[] = 'Mobile device found'; if ($this->m->isIPhone) { $this->debugItems[] = 'Apple IPhone or IPod Touch device found'; } if ($this->m->isAndroid) { $this->debugItems[] = 'Android device found'; } if($_SERVER['HTTP_HOST']==$this->get_config('sticky_host')) $this->debugItems[] = 'Sticky host! Outputting mobile markup anyways'; if(isset($hooks[$event])) { switch($event) { //////////////////////////////////////////////////////////////////// // FRONTEND //////////////////////////////////////////////////////////////////// case 'frontend_configure': // redirect? don't loop and don't redirect admin backend if($this->get_config('redirect') && $this->get_config('redirect_url') != $_SERVER['HTTP_HOST'] && !strstr($_SERVER['REQUEST_URI'],'serendipity_admin.php')) { header('Status: 302 Found'); header('Location: http://' . $this->get_config('redirect_url') . $_SERVER['REQUEST_URI']); exit; } // set template and css to the included style.css - requires the (normally included) xhtml_mp or iphone template from http://c.seo-mobile.de/ $this->debugItems[] = 'Charset: '.LANG_CHARSET; if($this->m->isIPhone == true) { $template = $this->get_config('iphone_template'); } elseif($this->m->isAndroid == true) { $template = $this->get_config('android_template'); } else { $template = $this->get_config('mobile_template'); } if (!empty($template)) { $eventData['template'] = $template; $eventData['template_engine'] = $template; $serendipity['smarty_vars']['head_link_stylesheet'] = $serendipity['baseURL'] . 'serendipity.css.php?switch=' . $template; $this->debugItems[] = 'Template changed to: '.$template; } return true; break; //////////////////////////////////////////////////////////////////// // ENTRIES //////////////////////////////////////////////////////////////////// case 'entry_display': // AJAX Request (IPhone) if($_SERVER['HTTP_X_XMLHTTPREQUEST']) { $serendipity['smarty']->assign(array('ajax'=>1)); } else { $serendipity['smarty']->assign(array('ajax'=>0)); } // send content-type xhtml header (not for iphones) if($this->m->isIPhone == true || $this->m->isAndroid == true) { header('Content-Type: text/html; charset='.LANG_CHARSET); } else { header('Content-Type: application/xhtml+xml; charset='.LANG_CHARSET); } // add categories to footer navigation? if($this->get_config('categories')) { $this->debugItems[] = 'Adding categories to footer navigation'; $this->assignCategories($serendipity); } $smallteaser = $this->get_config('smallteaser', true); $template_meta = new serendipity_template_meta($serendipity['template']); $template_supports_extended_articles = $template_meta->supports('ext_article'); $article_overview = count($eventData)>1; foreach($eventData AS $key=>$entry) { // get body and extended body $body = $this->cleanupMobileHtml($this->getFieldReference('body', $entry), $serendipity); $extended = $this->cleanupMobileHtml($this->getFieldReference('extended', $entry), $serendipity); if (!$article_overview && !$template_supports_extended_articles) { $body .= $extended; } if ($article_overview && $smallteaser) { if (preg_match('/^(.+?)<\/p>/', $body, $matches)) { $body = $matches[1] . "

"; } } // debugging $this->debug($serendipity); // check for caching again if($eventData[$key]['properties']['ep_cache_body']) { $eventData[$key]['properties']['ep_cache_body'] = $body; $eventData[$key]['properties']['ep_cache_extended'] = $extended; } elseif($eventData[$key]['ep_cache_body']) { $eventData[$key]['ep_cache_body'] = $body; $eventData[$key]['ep_cache_extended'] = $extended; } else { $eventData[$key]['body'] = $body; $eventData[$key]['extended'] = $extended; } //return true; // do all entries! } break; } } } function cleanupMobileHtml( &$textpart, &$serendipity ) { // parse HTML, remove comments and other unneeded elements and attributes and return DOM $this->debugItems[] = 'Parsing DOM'; $dom = $this->m->parseHTML($textpart, LANG_CHARSET, $this->get_config('remove_tags'), $this->get_config('remove_attributes'), $this->debugItems); // rewrite wikipedia links? if($this->get_config('rewrite_wikipedia')) { $this->debugItems[] = 'Rewriting wikipedia.org links to wikipedia.7val.com'; $this->m->rewriteWikipediaLinks($dom, $this->debugItems); } // remove images? if(!$this->get_config('images')) { $this->debugItems[] = 'Removing all images from DOM'; $dom = $this->m->removeImages($dom, $this->debugItems); } else { $this->debugItems[] = 'Removing all image dimensions from DOM'; $dom = $this->m->removeImagesDimensions($dom, $this->debugItems); } // scale images? if($this->get_config('images') && ($this->get_config('scale_image_width')>0 || $this->get_config('wurfl'))) { $this->scaleImages($dom, $serendipity); } // save valid XML as entry body $textpart = $this->m->cleanUp($dom, LANG_CHARSET, $this->debugItems); return $textpart; } function scaleImages(&$dom,&$serendipity) { if($this->get_config('wurfl')) { $this->debugItems[] = 'Trying to scale images with WURFL'; // already did a wurfl check for this device in our session? if($_SESSION['mobile_plugin']['ua']==$_SERVER['HTTP_USER_AGENT'] && $_SESSION['mobile_plugin']['wurfl']['width']) { // got the wurfl result stored in session $imageWidth = $_SESSION['mobile_plugin']['wurfl']['width']; $this->debugItems[] = 'We don\'t need to query WURFL again as the result was stored in our session'; } else { // load wurfl php require_once(dirname(__FILE__).'/wurfl/wurfl_config.php'); require_once(WURFL_CLASS_FILE); // create wurfl object $W = new wurfl_class(); $this->debugItems[] = 'WURFL object created'; // query wurfl $W->GetDeviceCapabilitiesFromAgent($_SERVER['HTTP_USER_AGENT']); // get maximum image width from wurfl $imageWidth = (int)$W->getDeviceCapability('max_image_width')-20; } if($imageWidth<0) { // fallback $dom = $this->m->scaleImages($dom, $serendipity, $this->get_config('scale_image_width'), S9Y_PEAR_PATH, $this->debugItems); $this->debugItems[] = 'Device not found in WURFL or screen to small. Using maximum image width as fallback'; } else { // found a device $_SESSION['mobile_plugin']['wurfl']['width'] = $imageWidth; $dom = $this->m->scaleImages($dom, $serendipity, $imageWidth, S9Y_PEAR_PATH, $this->debugItems); $this->debugItems[] = 'Device found in WURFL, images were scaled'; } } else if(serendipity_db_bool($this->get_config('wurfl')) && $this->m->isIPhone === true) { // fix image width for iphone if not found in wurfl $this->debugItems[] = 'Scaling images for iPhone device'; $dom = $this->m->scaleImages($dom, $serendipity, 300, S9Y_PEAR_PATH, $this->debugItems); $this->debugItems[] = 'Scaled all images'; } else { // don't use wurfl $dom = $this->m->scaleImages($dom, $serendipity, $this->get_config('scale_image_width'), S9Y_PEAR_PATH, $this->debugItems); $this->debugItems[] = 'Scaled all images'; } // store useragent in session to check if it has changed since the last request $_SESSION['mobile_plugin']['ua'] = $_SERVER['HTTP_USER_AGENT']; } function assignCategories(&$serendipity) { // add accesskey ids (1-9) $categories = serendipity_fetchCategories('all'); $plugin_categories_data = array(); $i = 1; foreach($categories AS $k=>$v) { $plugin_categories_data[] = array('access_key'=>$i++, 'category_name'=>$v['category_name'], 'categoryURL'=>serendipity_categoryURL($v, 'serendipityHTTPPath')); } $serendipity['smarty']->assign(array('categories'=>$plugin_categories_data)); } function debug(&$serendipity) { if($_GET['mpDebug'] == $this->get_config('debug_password')) $_SESSION['mobile_plugin']['debug'] = 1; if($_GET['mpDebug'] == 'off') unset($_SESSION['mobile_plugin']['debug']); if( $_SESSION['mobile_plugin']['debug']==1) { $debug = '
DEBUG:Disable debugging
'; $serendipity['smarty']->assign(array('debug'=>$debug)); } } function introspect_config_item($name, &$propbag) { switch($name) { case 'enable': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_EVENT_MOBILE_OUTPUT_ENABLE_PLUGIN_NAME); $propbag->add('description', PLUGIN_EVENT_MOBILE_OUTPUT_ENABLE_PLUGIN_DESC); $propbag->add('default', 'true'); break; case 'mobile_template': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_MOBILE_OUTPUT_MOBILE_TEMPLATE_NAME); $propbag->add('description', PLUGIN_EVENT_MOBILE_OUTPUT_MOBILE_TEMPLATE_DESC); $propbag->add('default', PLUGIN_EVENT_MOBILE_TPL_XHTML); $propbag->add('validate', '#^[0-9a-z\_\.\-]*$#i'); break; case 'iphone_template': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_MOBILE_OUTPUT_IPHONE_TEMPLATE_NAME); $propbag->add('description', PLUGIN_EVENT_MOBILE_OUTPUT_IPHONE_TEMPLATE_DESC); $propbag->add('default', PLUGIN_EVENT_MOBILE_TPL_IPHONE); $propbag->add('validate', '#^[0-9a-z\_\.\-]*$#i'); break; case 'android_template': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_MOBILE_OUTPUT_ANDROID_TEMPLATE_NAME); $propbag->add('description', PLUGIN_EVENT_MOBILE_OUTPUT_ANDROID_TEMPLATE_DESC); $propbag->add('default', PLUGIN_EVENT_MOBILE_TPL_ANDROID); $propbag->add('validate', '#^[0-9a-z\_\.\-]*$#i'); break; case 'images': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_EVENT_MOBILE_OUTPUT_IMAGES_NAME); $propbag->add('description', PLUGIN_EVENT_MOBILE_OUTPUT_IMAGES_DESC); $propbag->add('default', 'false'); break; case 'smallteaser': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_EVENT_MOBILE_OUTPUT_SMALLTEASER_NAME); $propbag->add('description', PLUGIN_EVENT_MOBILE_OUTPUT_SMALLTEASER_DESC); $propbag->add('default', 'true'); break; case 'scale_image_width': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_MOBILE_OUTPUT_SCALE_IMAGE_WIDTH_NAME); $propbag->add('description', PLUGIN_EVENT_MOBILE_OUTPUT_SCALE_IMAGE_WIDTH_DESC); $propbag->add('default', '60'); $propbag->add('validate', 'number'); break; case 'redirect': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_EVENT_MOBILE_OUTPUT_REDIRECT_NAME); $propbag->add('description', PLUGIN_EVENT_MOBILE_OUTPUT_REDIRECT_DESC); $propbag->add('default', 'false'); break; case 'redirect_url': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_MOBILE_OUTPUT_REDIRECT_URL_NAME); $propbag->add('description', PLUGIN_EVENT_MOBILE_OUTPUT_REDIRECT_URL_DESC); $propbag->add('default', 'm.yourblog.com'); $propbag->add('validate', '#^[0-9a-z\.\-_]*$#i'); break; case 'sticky_host': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_MOBILE_OUTPUT_STICKY_HOST_NAME); $propbag->add('description', PLUGIN_EVENT_MOBILE_OUTPUT_STICKY_HOST_DESC); $propbag->add('default', ''); $propbag->add('validate', '#^[0-9a-z\.\-_]*$#i'); break; case 'wurfl': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_EVENT_MOBILE_OUTPUT_WURFL_NAME); $propbag->add('description', PLUGIN_EVENT_MOBILE_OUTPUT_WURFL_DESC); $propbag->add('default', 'false'); break; case 'categories': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_EVENT_MOBILE_OUTPUT_CATEGORIES_NAME); $propbag->add('description', PLUGIN_EVENT_MOBILE_OUTPUT_CATEGORIES_DESC); $propbag->add('default', 'true'); break; case 'remove_tags': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_MOBILE_OUTPUT_REMOVE_TAGS_NAME); $propbag->add('description', PLUGIN_EVENT_MOBILE_OUTPUT_REMOVE_TAGS_DESC); $propbag->add('default', 'script,object,embed,iframe'); $propbag->add('validate', '#^[0-9a-z,]+$#i'); break; case 'remove_attributes': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_MOBILE_OUTPUT_REMOVE_ATTRIBUTES_NAME); $propbag->add('description', PLUGIN_EVENT_MOBILE_OUTPUT_REMOVE_ATTRIBUTES_DESC); $propbag->add('default', 'style,onload,onunload,onchange,onsubmit,onreset,onselect,onblur,onfocus,onkeydown,onkeypress,onkeyup,onclick,ondblclick,onmousedown,onmousemove,onmouseover,onmouseout,onmouseup'); $propbag->add('validate', '#^[0-9a-z,]+$#i'); break; case 'rewrite_wikipedia': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_EVENT_MOBILE_OUTPUT_REWRITE_WIKIPEDIA_NAME); $propbag->add('description', PLUGIN_EVENT_MOBILE_OUTPUT_REWRITE_WIKIPEDIA_DESC); $propbag->add('default', 'true'); break; case 'sitemap': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_EVENT_MOBILE_OUTPUT_SITEMAP_NAME); $propbag->add('description', PLUGIN_EVENT_MOBILE_OUTPUT_SITEMAP_DESC); $propbag->add('default', 'false'); break; case 'sitemap_pingback': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_EVENT_MOBILE_OUTPUT_SITEMAP_REPORT_NAME); $propbag->add('description', PLUGIN_EVENT_MOBILE_OUTPUT_SITEMAP_REPORT_DESC); $propbag->add('default', false); break; case 'sitemap_pingback_urls': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_MOBILE_OUTPUT_SITEMAP_URL_NAME); $propbag->add('description', PLUGIN_EVENT_MOBILE_OUTPUT_SITEMAP_URL_DESC); $propbag->add('default', 'http://www.google.com/webmasters/tools/ping?sitemap=%s'); break; case 'gzip_sitemap': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_EVENT_MOBILE_OUTPUT_SITEMAP_GZIP_NAME); $propbag->add('description', PLUGIN_EVENT_MOBILE_OUTPUT_SITEMAP_GZIP_DESC); $propbag->add('default', true); break; case 'debug_password': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_MOBILE_OUTPUT_DEBUG_PASSWORD_NAME); $propbag->add('description', PLUGIN_EVENT_MOBILE_OUTPUT_DEBUG_PASSWORD_DESC); $propbag->add('default', 'password'); break; } return true; } //////////////////////////////////////////////////////////////////// // SITEMAP - Code ripped off the sitemap plugin by boris. Thanks! //////////////////////////////////////////////////////////////////// // function to add an entry to the xml-string $str function addtoxml(&$str, $url, $lastmod = null, $priority = null, $changefreq = null) { /* Sitemap requires this. * I think that s9y does not include these specialchars, so this is just a precaution */ $url = (function_exists('serendipity_specialchars') ? serendipity_specialchars($url, ENT_QUOTES) : htmlspecialchars($url, ENT_QUOTES| ENT_COMPAT, LANG_CHARSET)); $str .= "\t\n"; $str .= "\t\t$url\n"; if ($lastmod!=null) { $str_lastmod = gmstrftime('%Y-%m-%dT%H:%M:%SZ', $lastmod); // 'Z' does mean UTC in W3C Date/Time $str .= "\t\t$str_lastmod\n"; } if ($priority!==null) { $str .= "\t\t".sprintf("%1.1f",$priority)."\n"; } if ($changefreq!=null) { $str .= "\t\t$changefreq\n"; } $str .= "\t\n"; } function send_ping($loc) { global $serendipity; if (function_exists('serendipity_request_url')) { $data = serendipity_request_url($loc); if ($serendipity['last_http_request']['responseCode'] == '200') { return true; } return false; } else { require_once (defined('S9Y_PEAR_PATH') ? S9Y_PEAR_PATH : S9Y_INCLUDE_PATH . 'bundled-libs/') . 'HTTP/Request.php'; $req = new HTTP_Request($loc); if (PEAR::isError($req->sendRequest()) || $req->getResponseCode() != '200') { print_r($req); return false; } else { return true; } } } function generateSitemap(&$bag) { global $serendipity; // decide which NULL-function to use switch($serendipity['dbType']) { case 'postgres': $sqlnullfunction = 'COALESCE'; break; case 'sqlite': case 'mysql': case 'mysqli': $sqlnullfunction = 'IFNULL'; break; default: $sqlnullfunction=''; } $hooks = &$bag->get('event_hooks'); $do_pingback = serendipity_db_bool($this->get_config('sitemap_pingback', false)); $pingback_url = $this->get_config('sitemap_pingback_urls', false); // start the xml $sitemap_xml = ''."\n"; $sitemap_xml .= "\n"; // add link to the main page $this->addtoxml($sitemap_xml, $serendipity['baseURL'], time(), 0.6); // fetch all entries from the db (tested with: mysql, sqlite, postgres) $entries = serendipity_db_query( 'SELECT entries.id AS id, entries.title AS title, '.$sqlnullfunction.'(entries.last_modified,0) AS timestamp_1, '.$sqlnullfunction.'(MAX(comments.timestamp),0) AS timestamp_2 FROM '.$serendipity['dbPrefix'].'entries entries LEFT JOIN '.$serendipity['dbPrefix'].'comments comments ON entries.id = comments.entry_id WHERE entries.isdraft = \'false\' GROUP BY entries.id, entries.title, entries.last_modified ORDER BY entries.id', false, 'assoc'); if(is_array($entries)) { // add entries foreach($entries as $entry) { $max = max($entry['timestamp_1']+0, $entry['timestamp_2']+0); $url = serendipity_archiveURL($entry['id'], $entry['title']); $this->addtoxml($sitemap_xml, $url, $max, 0.7); } } // add possible perm links $permlink = serendipity_db_query( 'SELECT entryid, timestamp, value FROM '.$serendipity['dbPrefix'].'entryproperties AS entryproperties, '.$serendipity['dbPrefix'].'entries AS entries WHERE entryproperties.property = \'permalink\' AND entries.id=entryproperties.entryid', false, 'assoc'); if(is_array($permlink)) { foreach($permlink as $cur) { $path_quoted = preg_quote($serendipity['serendipityHTTPPath'], '#'); $url = $serendipity['baseURL'] . preg_replace("#$path_quoted#", '', $cur['value'],1); $cur_time = ($cur['timestamp']==0)? null : (int)$cur['timestamp']; $this->addtoxml($sitemap_xml, $url, $cur_time, 0.8); } // check for the right order of plugins $order = serendipity_db_query( 'SELECT name, sort_order FROM '.$serendipity['dbPrefix'].'plugins plugins WHERE plugins.name LIKE \'%serendipity_event_mobile_output%\' OR plugins.name LIKE \'%serendipity_event_custom_permalinks%\' ORDER BY plugins.sort_order', false, 'assoc'); if(is_array($order)) { if( strpos($order[0]['name'], 'serendipity_event_custom_permalinks')===FALSE) { echo '
'.PLUGIN_EVENT_MOBILE_OUTPUT_SITEMAP_PERMALINK_WARNING.'
'; } } } // fetch categories and their last entry date (tested with: mysql, sqlite, postgres) $q = 'SELECT category.categoryid AS id, category_name, category_description, MAX(entries.last_modified) AS last_mod FROM '.$serendipity['dbPrefix'].'category category, '.$serendipity['dbPrefix'].'entrycat entrycat, '.$serendipity['dbPrefix'].'entries entries WHERE category.categoryid = entrycat.categoryid AND entrycat.entryid = entries.id GROUP BY category.categoryid, category.category_name, category.category_description ORDER BY category.categoryid'; $categories = serendipity_db_query($q, false, 'assoc'); // add categories if(is_array($categories)) { foreach($categories as $category) { $max = 0+$category['last_mod']; /* v0.9 */ if(version_compare((float)$serendipity['version'], '0.9', '>=')) { $data = array( 'categoryid' => $category['id'], 'category_name' => $category['category_name'], 'category_description' => $category['category_description']); $url = serendipity_categoryURL($data); } else { $url = serendipity_rewriteURL(PATH_CATEGORIES . '/' . serendipity_makePermalink(PERM_CATEGORIES, array('id' => $category['id'], 'title' => $category['category_name']))); } $this->addtoxml($sitemap_xml, $url, $max, 0.4); } } else { $categories = array(); } // finish the xml $sitemap_xml .= "
\n"; $do_gzip = serendipity_db_bool($this->get_config('gzip_sitemap', true)); // decide whether to use gzip-output or not if($do_gzip && function_exists('gzencode')) { $filename = '/mobile_sitemap.xml.gz'; $temp = gzencode($sitemap_xml); // only use the compressed data and filename if no error occured if( !($temp === FALSE) ) { $sitemap_xml = $temp; } else { $filename = '/mobile_sitemap.xml'; } } else { $filename = '/mobile_sitemap.xml'; } // write result to file $outfile = fopen($serendipity['serendipityPath'] . $filename, 'w'); if($outfile === false) { echo ''.PLUGIN_EVENT_MOBILE_OUTPUT_SITEMAP_FAILEDOPEN.''; return false; } flock($outfile, LOCK_EX); fputs($outfile, $sitemap_xml); flock($outfile, LOCK_UN); fclose($outfile); // Walk through the list of pingback-URLs foreach(explode(';', $pingback_url) as $cur_pingback_url) { $pingback_name = PLUGIN_EVENT_MOBILE_OUTPUT_SITEMAP_UNKNOWN_HOST; $cur_url = sprintf($cur_pingback_url, rawurlencode($serendipity['baseURL'].$filename)); // extract domain-portion from URL if(preg_match('@^https?://([^/]+)@', $cur_pingback_url, $matches)>0) { $pingback_name = $matches[1]; } if(!serendipity_db_bool($eventData['isdraft']) && $do_pingback && $cur_url) { $answer = $this->send_ping($cur_url); if($answer) { printf(PLUGIN_EVENT_MOBILE_OUTPUT_SITEMAP_REPORT_OK, $pingback_name); } else { printf(PLUGIN_EVENT_MOBILE_OUTPUT_SITEMAP_REPORT_ERROR, $pingback_name, $cur_url); } } else { printf(PLUGIN_EVENT_MOBILE_OUTPUT_SITEMAP_REPORT_MANUAL, $pingback_name, $cur_url); } } return true; } function recurse_dircopy($src,$dst) { $dir = opendir($src); if (!file_exists($dst)) { if (!@mkdir($dst)) return false; // Creating dir failed! } while(false !== ( $file = readdir($dir)) ) { if (( $file != '.' ) && ( $file != '..' )) { if ( is_dir($src . '/' . $file) ) { $this->recurse_dircopy($src . '/' . $file,$dst . '/' . $file); } else { copy($src . '/' . $file,$dst . '/' . $file); } } } closedir($dir); return true; } };