From 2f08309e79b79621750f9c0acfbdf51291ad9221 Mon Sep 17 00:00:00 2001 From: garvinhicking Date: Fri, 8 Jul 2005 13:29:03 +0000 Subject: [PATCH] Larger rework of spartacus plugin to support mirrors and categories --- .../serendipity_event_spartacus.php | 400 +++++++++++++++--- 1 file changed, 343 insertions(+), 57 deletions(-) diff --git a/plugins/serendipity_event_spartacus/serendipity_event_spartacus.php b/plugins/serendipity_event_spartacus/serendipity_event_spartacus.php index b9bd09e..407d135 100644 --- a/plugins/serendipity_event_spartacus/serendipity_event_spartacus.php +++ b/plugins/serendipity_event_spartacus/serendipity_event_spartacus.php @@ -24,6 +24,9 @@ switch ($serendipity['lang']) { @define('PLUGIN_EVENT_SPARTACUS_FETCHED_BYTES_URL', '%s bytes von obiger URL geladen. Speichere Inhalt als %s...'); @define('PLUGIN_EVENT_SPARTACUS_FETCHED_BYTES_CACHE', '%s bytes von bereits bestehender Datei geladen. Speichere Inhalt als %s...'); @define('PLUGIN_EVENT_SPARTACUS_FETCHED_DONE', 'Daten erfolgreich geladen.'); + @define('PLUGIN_EVENT_SPARTACUS_MIRROR_XML', 'Datei/Mirror Speicherort (XML-Metadaten)'); + @define('PLUGIN_EVENT_SPARTACUS_MIRROR_FILES', 'Datei/Mirror Speicherort (Downloads)'); + @define('PLUGIN_EVENT_SPARTACUS_MIRROR_DESC', 'Wählen Sie den Download-Server. Ändern Sie diesen Wert nur, wenn Sie wissen, was Sie tun und ein Server nicht mehr reagiert. Diese Option ist hauptsächlich für zukünftige Server reserviert.'); break; case 'en': @@ -36,12 +39,21 @@ switch ($serendipity['lang']) { @define('PLUGIN_EVENT_SPARTACUS_FETCHED_BYTES_URL', 'Fetched %s bytes from the URL above. Saving file as %s...'); @define('PLUGIN_EVENT_SPARTACUS_FETCHED_BYTES_CACHE', 'Fetched %s bytes from already existing file on your server. Saving file as %s...'); @define('PLUGIN_EVENT_SPARTACUS_FETCHED_DONE', 'Data successfully fetched.'); + @define('PLUGIN_EVENT_SPARTACUS_MIRROR_XML', 'File/Mirror location (XML metadata)'); + @define('PLUGIN_EVENT_SPARTACUS_MIRROR_FILES', 'File/Mirror location (files)'); + @define('PLUGIN_EVENT_SPARTACUS_MIRROR_DESC', 'Choose a download location. Do NOT change this value unless you know what you are doing and if servers get oudated. This option is available mainly for forward compatibility.'); break; } class serendipity_event_spartacus extends serendipity_event { var $title = PLUGIN_EVENT_SPARTACUS_NAME; + var $purgeCache = false; + + function microtime_float() { + list($usec, $sec) = explode(" ", microtime()); + return ((float)$usec + (float)$sec); + } function introspect(&$propbag) { @@ -51,25 +63,103 @@ class serendipity_event_spartacus extends serendipity_event $propbag->add('description', PLUGIN_EVENT_SPARTACUS_DESC); $propbag->add('stackable', false); $propbag->add('author', 'Garvin Hicking'); - $propbag->add('version', '1.2'); + $propbag->add('version', '2.0'); $propbag->add('requirements', array( - 'serendipity' => '0.8', + 'serendipity' => '0.9', 'smarty' => '2.6.7', 'php' => '4.1.0' )); $propbag->add('event_hooks', array( - 'backend_plugins_sidebar_header' => true, - 'backend_plugins_event_header' => true, + 'backend_plugins_fetchlist' => true, + 'backend_plugins_fetchplugin' => true, - 'backend_plugins_fetchlist' => true, - 'backend_plugins_fetchplugin' => true + 'backend_templates_fetchlist' => true, + 'backend_templates_fetchtemplate' => true )); + $propbag->add('groups', array('BACKEND_FEATURES')); + $propbag->add('configuration', array('mirror_xml', 'mirror_files')); } function generate_content(&$title) { $title = $this->title; } + function cleanup() { + // Purge cached XML files. + $files = serendipity_traversePath($serendipity['serendipityPath'] . PATH_SMARTY_COMPILE, '', false, '/package_.+\.xml$/'); + + if (!is_array($files)) { + return false; + } + + foreach ($files as $file) { + printf(DELETING_FILE . '
', $file['name']); + @unlink($serendipity['serendipityPath'] . PATH_SMARTY_COMPILE . '/' . $file['name']); + } + } + + function &getMirrors($type = 'xml', $loc = false) { + static $mirror = array( + 'xml' => array( + 'Netmirror.org', + 's9y.org' + ), + + 'files' => array( + 'SourceForge.net', + 'Netmirror.org', + 's9y.org', + 'BerliOS.de' + ) + ); + + static $http = array( + 'xml' => array( + 'http://netmirror.org/mirror/serendipity/', + 'http://s9y.org/mirror/' + ), + + 'files' => array( + 'http://cvs.sourceforge.net/viewcvs.py/*checkout*/php-blog/', + 'http://netmirror.org/mirror/serendipity/', + 'http://s9y.org/mirror/', + 'http://svn.berlios.de/viewcvs/serendipity/' + ) + ); + + if ($loc) { + return $http[$type]; + } else { + return $mirror[$type]; + } + } + + function introspect_config_item($name, &$propbag) { + global $serendipity; + + switch($name) { + case 'mirror_xml': + $propbag->add('type', 'select'); + $propbag->add('name', PLUGIN_EVENT_SPARTACUS_MIRROR_XML); + $propbag->add('description', PLUGIN_EVENT_SPARTACUS_MIRROR_DESC); + $propbag->add('select_values', $this->getMirrors('xml')); + $propbag->add('default', 0); + break; + + case 'mirror_files': + $propbag->add('type', 'select'); + $propbag->add('name', PLUGIN_EVENT_SPARTACUS_MIRROR_FILES); + $propbag->add('description', PLUGIN_EVENT_SPARTACUS_MIRROR_DESC); + $propbag->add('select_values', $this->getMirrors('files')); + $propbag->add('default', 0); + break; + + default: + return false; + } + return true; + } + function GetChildren(&$vals, &$i) { $children = array(); $cnt = sizeof($vals); @@ -104,10 +194,10 @@ class serendipity_event_spartacus extends serendipity_event } // Create recursive directories; begins at serendipity plugin root folder level - function rmkdir($dir) { + function rmkdir($dir, $sub = 'plugins') { global $serendipity; - $spaths = explode('/', $serendipity['serendipityPath'] . 'plugins/'); + $spaths = explode('/', $serendipity['serendipityPath'] . $sub . '/'); $paths = explode('/', $dir); $stack = ''; @@ -126,7 +216,7 @@ class serendipity_event_spartacus extends serendipity_event return true; } - function &fetchfile($url, $target, $cacheTimeout = 0) { + function &fetchfile($url, $target, $cacheTimeout = 0, $decode_utf8 = false, $sub = 'plugins') { printf(PLUGIN_EVENT_SPARTACUS_FETCHING, '' . basename($url) . ''); echo '
'; @@ -152,7 +242,7 @@ class serendipity_event_spartacus extends serendipity_event printf(PLUGIN_EVENT_SPARTACUS_FETCHED_BYTES_URL, strlen($data), $target); echo '
'; $tdir = dirname($target); - if (!is_dir($tdir) && !$this->rmkdir($tdir)) { + if (!is_dir($tdir) && !$this->rmkdir($tdir, $sub)) { printf(FILE_WRITE_ERROR, $tdir); echo '
'; return false; @@ -165,38 +255,90 @@ class serendipity_event_spartacus extends serendipity_event echo '
'; return false; } + + if ($decode_utf8) { + $this->decode($data); + } fwrite($fp, $data); fclose($fp); echo PLUGIN_EVENT_SPARTACUS_FETCHED_DONE; echo '
'; + $this->purgeCache = true; } } return $data; } - function &fetchOnline($type) { + function decode(&$data) { + switch (strtolower(LANG_CHARSET)) { + case 'utf-8': + // The XML file is UTF-8 format. No changes needed. + break; + + case 'iso-8859-1': + $data = utf8_decode($data); + break; + + default: + if (function_exists('iconv')) { + $data = iconv('UTF-8', LANG_CHARSET, $data); + } elseif (function_exists('recode')) { + $data = recode('utf-8..' . LANG_CHARSET, $data); + } + break; + } + } + + function &fetchOnline($type, $no_cache = false) { + global $serendipity; + switch($type) { // Sanitize to not fetch other URLs default: case 'event': $url_type = 'event'; + $i18n = true; break; case 'sidebar': $url_type = 'sidebar'; + $i18n = true; break; + + case 'template': + $url_type = 'template'; + $i18n = false; + break; + } + + if (!$i18n) { + $lang = ''; + } elseif (isset($serendipity['languages'][$serendipity['lang']])) { + $lang = '_' . $serendipity['lang']; + } else { + $lang = '_en'; } - $url = 'http://netmirror.org/mirror/serendipity/package_' . $url_type . '.xml'; + $mirrors = $this->getMirrors('xml', true); + $mirror = $mirrors[$this->get_config('mirror_xml', 0)]; + + $url = $mirror . '/package_' . $url_type . $lang . '.xml'; $cacheTimeout = 60*60*12; // XML file is cached for half a day - $target = $serendipity['serendipityPath'] . 'templates_c/package_' . $url_type . '.xml'; + $target = $serendipity['serendipityPath'] . PATH_SMARTY_COMPILE . '/package_' . $url_type . $lang . '.xml'; - $xml = $this->fetchfile($url, $target, $cacheTimeout); + $xml = $this->fetchfile($url, $target, $cacheTimeout, true); echo '

'; + $new_crc = md5($xml); + $last_crc = $this->get_config('last_crc_' . $url_type); + + if (!$no_cache && !$this->purgeCache && $last_crc == $new_crc) { + return 'cached'; + } + // XML functions $p = xml_parser_create(); xml_parser_set_option($p, XML_OPTION_CASE_FOLDING, 0); @@ -212,14 +354,80 @@ class serendipity_event_spartacus extends serendipity_event 'children' => $this->GetChildren($vals, $i) ); + $this->set_config('last_crc_' . $url_type, $new_crc); + return $tree; } + function &getCachedPlugins(&$plugins, $type) { + global $serendipity; + static $pluginlist = null; + + if ($pluginlist === null) { + $data = serendipity_db_query("SELECT p.*, + pc.category + FROM {$serendipity['dbPrefix']}pluginlist AS p + LEFT OUTER JOIN {$serendipity['dbPrefix']}plugincategories AS pc + ON pc.class_name = p.class_name + WHERE p.pluginlocation = 'Spartacus' AND + p.plugintype = '" . serendipity_db_escape_string($type) . "'"); + + if (is_array($data)) { + foreach($data AS $p) { + $p['stackable'] = serendipity_db_bool($p['stackable']); + $p['requirements'] = unserialize($p['requirements']); + $this->checkPlugin($p, $plugins, $p['pluginlocation']); + + if (!isset($pluginlist[$p['plugin_file']])) { + $pluginlist[$p['plugin_file']] = $p; + } + + $pluginlist[$p['plugin_file']]['groups'][] = $p['category']; + } + } + } + + return $pluginlist; + } + + function checkPlugin(&$data, &$plugins, $type) { + $installable = true; + $upgradeLink = ''; + if (in_array($data['class_name'], $plugins)) { + $infoplugin =& serendipity_plugin_api::load_plugin($data['class_name']); + if (is_object($infoplugin)) { + $bag = new serendipity_property_bag; + $infoplugin->introspect($bag); + if ($bag->get('version') == $data['version']) { + $installable = false; + } elseif (version_compare($bag->get('version'), $data['version'], '<')) { + $data['upgradable'] = true; + $data['upgrade_version'] = $pluginstack[$i]['version']; + $data['version'] = $bag->get('version'); + $upgradeLink = '&serendipity[spartacus_upgrade]=true'; + } + } + } + + $data['installable'] = $installable; + $data['pluginPath'] = 'online_repository'; + $data['pluginlocation'] = 'Spartacus'; + $data['plugintype'] = $type; + $data['customURI'] = '&serendipity[spartacus_fetch]=' . $type . $upgradeLink; + + return true; + } + function &buildList(&$tree, $type) { $plugins = serendipity_plugin_api::get_installed_plugins(); + + if ($tree === 'cached') { + return $this->getCachedPlugins($plugins, $type); + } + $pluginstack = array(); $i = 0; - + foreach($tree[0]['children'] AS $idx => $subtree) { if ($subtree['tag'] == 'package') { $i++; @@ -227,16 +435,22 @@ class serendipity_event_spartacus extends serendipity_event foreach($subtree['children'] AS $child => $childtree) { switch($childtree['tag']) { case 'name': - $pluginstack[$i]['plugin_class'] = $childtree['value']; - $pluginstack[$i]['class_name'] = $childtree['value']; + $pluginstack[$i]['plugin_class'] = + $pluginstack[$i]['plugin_file'] = + $pluginstack[$i]['class_name'] = + $pluginstack[$i]['true_name'] = $childtree['value']; break; case 'summary': $pluginstack[$i]['name'] = $childtree['value']; break; + case 'groups': + $pluginstack[$i]['groups'] = explode(',', $childtree['value']); + break; + case 'description': - $pluginstack[$i]['desc'] = $childtree['value']; + $pluginstack[$i]['description'] = $childtree['value']; break; case 'release': @@ -260,38 +474,107 @@ class serendipity_event_spartacus extends serendipity_event break; } } + + $this->checkPlugin($pluginstack[$i], $plugins, $type); + + serendipity_plugin_api::setPluginInfo($pluginstack[$i], $pluginstack[$i]['plugin_file'], $i, $i, 'Spartacus'); + // Remove the temporary $i reference, as the array should be associative + $plugname = $pluginstack[$i]['true_name']; + $pluginstack[$plugname] = $pluginstack[$i]; + unset($pluginstack[$i]); + } + } - $installable = true; - $upgradeLink = ''; - if (in_array($pluginstack[$i]['class_name'], $plugins)) { - $infoplugin =& serendipity_plugin_api::load_plugin($pluginstack[$i]['class_name']); - if (is_object($infoplugin)) { - $bag = new serendipity_property_bag; - $infoplugin->introspect($bag); - if ($bag->get('version') == $pluginstack[$i]['version']) { - $installable = false; - } elseif (version_compare($bag->get('version'), $pluginstack[$i]['version'], '<')) { - $pluginstack[$i]['upgradable'] = true; - $pluginstack[$i]['upgrade_version'] = $pluginstack[$i]['version']; - $pluginstack[$i]['version'] = $bag->get('version'); - $upgradeLink = '&serendipity[spartacus_upgrade]=true'; - } + return $pluginstack; + } + + function &buildTemplateList(&$tree) { + $pluginstack = array(); + $i = 0; + + $mirrors = $this->getMirrors('files', true); + $mirror = $mirrors[$this->get_config('mirror_files', 0)]; + + foreach($tree[0]['children'] AS $idx => $subtree) { + if ($subtree['tag'] == 'package') { + $i++; + + foreach($subtree['children'] AS $child => $childtree) { + switch($childtree['tag']) { + case 'name': + $pluginstack[$i]['name'] = $childtree['value']; + break; + + case 'summary': + $pluginstack[$i]['summary'] = $childtree['value']; + break; + + case 'template': + $pluginstack[$i]['template'] = $childtree['value']; + break; + + case 'description': + $pluginstack[$i]['description'] = $childtree['value']; + break; + + case 'release': + $pluginstack[$i]['version'] = $childtree['children'][0]['value']; + + $pluginstack[$i]['requirements'] = array( + 'serendipity' => '', + 'php' => '', + 'smarty' => '' + ); + + foreach($childtree['children'] AS $relInfo) { + if ($relInfo['tag'] == 'requirements:s9yVersion') { + $pluginstack[$i]['requirements']['serendipity'] = $relInfo['value']; + } + + if ($relInfo['tag'] == 'date') { + $pluginstack[$i]['date'] = $relInfo['value']; + } + + } + + $pluginstack[$i]['require serendipity'] = $pluginstack[$i]['requirements']['serendipity']; + break; + + case 'maintainers': + $pluginstack[$i]['author'] = $childtree['children'][0]['children'][0]['value']; // I dig my PHP arrays ;-) + break; } } - $pluginstack[$i]['installable'] = $installable; - $pluginstack[$i]['pluginPath'] = 'online_repository'; - $pluginstack[$i]['customURI'] = '&serendipity[spartacus_fetch]=' . $type . $upgradeLink; + $plugname = $pluginstack[$i]['template']; + $pluginstack[$i]['previewURL'] = $mirror . '/additional_themes/' . $plugname . '/preview.png?rev=1.9999'; + $pluginstack[$i]['customURI'] = '&serendipity[spartacus_fetch]=' . $plugname; + $pluginstack[$i]['customIcon'] = '_spartacus'; + + // Remove the temporary $i reference, as the array should be associative + $pluginstack[$plugname] = $pluginstack[$i]; + unset($pluginstack[$i]); } } return $pluginstack; } - function download(&$tree, $plugin_to_install) { + function download(&$tree, $plugin_to_install, $sub = 'plugins') { global $serendipity; - $pdir = $serendipity['serendipityPath'] . '/plugins/'; + switch($sub) { + case 'plugins': + default: + $sfloc = 'additional_plugins'; + break; + + case 'templates': + $sfloc = 'additional_themes'; + break; + } + + $pdir = $serendipity['serendipityPath'] . '/' . $sub . '/'; if (!is_writable($pdir)) { printf(DIRECTORY_WRITE_ERROR, $pdir); echo '
'; @@ -306,7 +589,7 @@ class serendipity_event_spartacus extends serendipity_event } foreach($subtree['children'] AS $child => $childtree) { - if ($childtree['tag'] == 'name' && $childtree['value'] == $plugin_to_install) { + if ($childtree['tag'] == 'template' && $childtree['value'] == $plugin_to_install) { $found = true; } @@ -330,8 +613,11 @@ class serendipity_event_spartacus extends serendipity_event } } + $mirrors = $this->getMirrors('files', true); + $mirror = $mirrors[$this->get_config('mirror_files', 0)]; + foreach($files AS $file) { - $url = 'http://cvs.sourceforge.net/viewcvs.py/*checkout*/php-blog/additional_plugins/' . $file . '?rev=1.9999'; + $url = $mirror . '/' . $sfloc . '/' . $file . '?rev=1.9999'; $target = $pdir . $file; @mkdir($pdir . $plugin_to_install); $this->fetchfile($url, $target); @@ -353,30 +639,30 @@ class serendipity_event_spartacus extends serendipity_event if (isset($hooks[$event])) { switch($event) { - case 'backend_plugins_sidebar_header': -?> -
-buildTemplateList($this->fetchOnline('template', true), 'template'); - case 'backend_plugins_event_header': -?> -
-download( + $this->fetchOnline('template', true), + $eventData['GET']['theme'], + 'templates' + ); } + return false; + break; + + case 'backend_plugins_fetchlist': $type = (isset($serendipity['GET']['type']) ? $serendipity['GET']['type'] : 'sidebar'); $eventData = array( - 'pluginstack' => $this->buildList($this->fetchOnline($type), $type), - 'errorstack' => array() + 'pluginstack' => $this->buildList($this->fetchOnline($type), $type), + 'errorstack' => array() ); return true; @@ -384,7 +670,7 @@ class serendipity_event_spartacus extends serendipity_event case 'backend_plugins_fetchplugin': if (!empty($eventData['GET']['spartacus_fetch'])) { - $baseDir = $this->download($this->fetchOnline($eventData['GET']['spartacus_fetch']), $eventData['GET']['install_plugin']); + $baseDir = $this->download($this->fetchOnline($eventData['GET']['spartacus_fetch'], true), $eventData['GET']['install_plugin']); if (!empty($baseDir)) { $eventData['GET']['pluginPath'] = $baseDir; } else { @@ -410,4 +696,4 @@ class serendipity_event_spartacus extends serendipity_event } /* vim: set sts=4 ts=4 expandtab : */ -?> +?> \ No newline at end of file -- 2.39.5