= USERLEVEL_ADMIN) { return false; } // do we already have it? if (!$this->forceZipInstall && is_dir($this->cke_dir) && is_file($this->cke_dir . '/ckeditor.js')) { // this is running while getting a new Plugin version if ($this->checkUpdate()) { $this->set_config('installer', '4-'.date('Ymd-H:i:s')); // this is a faked debug notice, since falldown is extract true with case 0, 1 or 2 // continue } else { $this->set_config('installer', '3-'.date('Ymd-H:i:s')); // this will happen, if no further extract is necessary in case of an update - follow install or upgrade routines return false; } } if (!extension_loaded('zip')) { trigger_error(' ZIP extension has not been compiled or loaded in PHP.', E_USER_WARNING); return; } if (is_writable($this->cke_path)) { $zip = new ZipArchive; if ($zip->open($this->cke_path . '/' . $this->cke_zipfile) === true) { $zip->extractTo($this->cke_path); $zip->close(); $this->set_config('installer', '2-'.date('Ymd-H:i:s')); // returned by string[0], which is better than substr in this case // Check to remove every old ckeditor_(*)-plus.zip files - checked by partial string "-plus" foreach (glob($this->cke_path . '/*.zip') AS $filename) { if ($this->cke_path . '/' . $this->cke_zipfile != $filename && (false !== strpos($filename, '-plus')) ) { @unlink($filename); $is_update = true; } } if ($is_update) { // purge removed files for upgraders to ckeditor v. 4.2 only @unlink($this->cke_path . '/ckeditor/build_config.js'); @unlink($this->cke_path . '/ckeditor/skins/moono/images/mini.png'); // purge removed files for upgraders to ckeditor >= v. 4.4.4 only @unlink($this->cke_path . '/UTF-8/documentation_cz.html'); @unlink($this->cke_path . '/UTF-8/lang_en.inc.php'); @unlink($this->cke_path . '/UTF-8/documentation_cs.html'); // purge accidently added Thumbs.db file with 4.5.8.0/1 throwing errors on unzip @unlink($this->cke_path . '/ckeditor/plugins/codesnippet/icons/hidpi/Thumbs.db'); @unlink($this->cke_path . '/ckeditor/plugins/procurator/images/Thumbs.db'); } // remove widget/dev samples directory if (is_file(dirname(__FILE__) . '/ckeditor/plugins/widget/dev/console.js')) { $this->empty_dir(dirname(__FILE__) . '/ckeditor/widget/dev'); @rmdir(dirname(__FILE__) . '/ckeditor/widget/dev'); } // remove lineutils/dev samples directory if (is_file(dirname(__FILE__) . '/ckeditor/plugins/lineutils/dev/dnd.html')) { $this->empty_dir(dirname(__FILE__) . '/ckeditor/lineutils/dev'); @rmdir(dirname(__FILE__) . '/ckeditor/lineutils/dev'); } // remove usused placeholder plugin if (is_file(dirname(__FILE__) . '/ckeditor/plugins/placeholder/plugin.js')) { $this->empty_dir(dirname(__FILE__) . '/ckeditor/plugins/placeholder'); @rmdir(dirname(__FILE__) . '/ckeditor/plugins/placeholder'); } // remove code button plugin pbckcode if (is_file(dirname(__FILE__) . '/ckeditor/plugins/pbckcode/plugin.js')) { $this->empty_dir(dirname(__FILE__) . '/ckeditor/plugins/pbckcode'); @rmdir(dirname(__FILE__) . '/ckeditor/plugins/pbckcode'); } // remove kcfinder instance if (is_file(dirname(__FILE__) . '/kcfinder/config.php')) { $this->empty_dir(dirname(__FILE__) . '/kcfinder'); @rmdir(dirname(__FILE__) . '/kcfinder'); unset($_COOKIE['KCFINDER_uploadurl']); unset($_COOKIE['KCFINDER_displaySettings']); unset($_COOKIE['KCFINDER_showname']); unset($_COOKIE['KCFINDER_showsize']); unset($_COOKIE['KCFINDER_showtime']); unset($_COOKIE['KCFINDER_order']); unset($_COOKIE['KCFINDER_orderDesc']); unset($_COOKIE['KCFINDER_view']); } // extracted, continue to set this version into config } else { $this->set_config('installer', '1-'.date('Ymd-H:i:s')); return false; } } else { $this->set_config('installer', '0-'.date('Ymd-H:i:s')); // do it again, Sam return false; } // Extraction found true, add the new version string to configs last_ckeditor_version $this->updateConfig(); return true; } function uninstall(&$propbag) { // todo? uninstall old instances which may be in there, caused by a duplicating bug using installer fallback without right instance, in 2.3.2 (was for one day online only) } function introspect(&$propbag) { global $serendipity; $propbag->add('name', PLUGIN_EVENT_CKEDITOR_NAME); $propbag->add('description', PLUGIN_EVENT_CKEDITOR_DESC); $propbag->add('stackable', false); $propbag->add('author', 'Rustam Abdullaev, Ian'); $propbag->add('version', '4.5.10.6'); // is CKEDITOR Series 4.5.10 - and appended plugin revision .5 $propbag->add('copyright', 'GPL or LGPL License'); $propbag->add('requirements', array( 'serendipity' => '1.7', 'smarty' => '3.1.13', 'php' => '5.2.6' )); $propbag->add('event_hooks', array( 'frontend_header' => true, 'frontend_footer' => true, 'backend_header' => true, 'css' => true, 'css_backend' => true, 'external_plugin' => true, 'backend_plugins_update' => true, 'backend_media_path_exclude_directories' => true, 'backend_wysiwyg' => true, 'backend_wysiwyg_finish' => true )); $propbag->add('configuration', array('path', 'plugpath', 'codebutton', 'prettify', 'acf_off', 'toolbar', 'ibn_off', 'toolbar_break', 'force_install', 'timestamp')); $propbag->add('groups', array('BACKEND_EDITOR')); } function introspect_config_item($name, &$propbag) { global $serendipity; switch($name) { case 'path': $propbag->add('type', 'string'); $propbag->add('name', INSTALL_RELPATH); $propbag->add('description', PLUGIN_EVENT_CKEDITOR_OPTION_DESC . '"plugins/serendipity_event_ckeditor/ckeditor/"'); $propbag->add('default', 'plugins/serendipity_event_ckeditor/ckeditor/'); break; case 'plugpath': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_CKEDITOR_INSTALL_PLUGPATH); $propbag->add('description', PLUGIN_EVENT_CKEDITOR_OPTION_DESC . '"' . $serendipity['serendipityHTTPPath'] . 'plugins/"'); $propbag->add('default', $serendipity['serendipityHTTPPath'] . 'plugins/'); break; case 'codebutton': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_EVENT_CKEDITOR_CODEBUTTON_OPTION); $propbag->add('description', ''); $propbag->add('default', 'false'); break; case 'prettify': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_EVENT_CKEDITOR_PRETTIFY_OPTION); $propbag->add('description', PLUGIN_EVENT_CKEDITOR_PRETTIFY_OPTION_DESC); $propbag->add('default', 'false'); break; case 'acf_off': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_EVENT_CKEDITOR_CKEACF_OPTION); $propbag->add('description', PLUGIN_EVENT_CKEDITOR_CKEACF_OPTION_DESC); $propbag->add('default', 'false'); break; case 'toolbar': $select = array(); $select["Standard"] = 'STANDARD'; $select["Basic"] = 'BASIC'; $select["Full"] = 'FULL'; $propbag->add('type', 'select'); $propbag->add('name', PLUGIN_EVENT_CKEDITOR_SETTOOLBAR_OPTION); $propbag->add('description', ''); $propbag->add('select_values', $select); $propbag->add('default', 'Standard'); break; case 'ibn_off': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_EVENT_CKEDITOR_CKEIBN_OPTION); $propbag->add('description', PLUGIN_EVENT_CKEDITOR_CKEIBN_OPTION_DESC); $propbag->add('default', 'true'); break; case 'toolbar_break': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_EVENT_CKEDITOR_TOOLBAR_OPTION); $propbag->add('description', ''); $propbag->add('default', 'true'); break; case 'force_install': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_EVENT_CKEDITOR_FORCEINSTALL_OPTION); $propbag->add('description', PLUGIN_EVENT_CKEDITOR_FORCEINSTALL_OPTION_DESC . $this->cke_zipfile); $propbag->add('default', 'false'); break; case 'timestamp': $propbag->add('type', 'hidden'); $propbag->add('value', time()); break; default: return false; } return true; } function generate_content(&$title) { $title = $this->title; } function example() { $s = ''; if (serendipity_db_bool($this->get_config('force_install'))) { $this->forceZipInstall = true; $this->install(); $this->forceZipInstall = false; $this->set_config('force_install', 'false'); // forceZipInstall forces to surround the checkUpdate function, thus we set config database table to keep track $this->updateConfig(); $s .= '

Force deflate done: Please reload this page here!

'; } $installer = $this->get_config('installer'); // Can't use method return value in write context in '' with substr(), get_config() and isset() $parts = explode(':', $this->checkUpdateVersion[0]); // this is ckeditor only $s .= PLUGIN_EVENT_CKEDITOR_REVISION_TITLE; $s .= "\n\n\n"; if (!empty($installer)) { switch ($installer[0]) { case '4': // this won't happen, since case 2 is true - just a fake $s .= '

Check Plugin Update Message: NO CONFIG SET OR NO MATCH -> config_set: "last_'.$parts[0].'_version:'. $parts[1].'"

'; break; case '3': $s .= '

Installer Update Message: Check Update found false, no unpack needed. Plugin upgrade successfully done or has been triggered to be checked by an other Spartacus Plugin update!

'; break; case '2': $s .= '

Installer Message: Extracting the zip to ' . $this->cke_path . ' directory done!

'; break; case '1': $s .= '

Installer Error[1]: Extracting the zip to ' . $this->cke_path . ' directory failed!
Please extract ' . $this->cke_zipfile . ' by hand.

'; break; case '0': $s .= '

Installer Error[0]: Due to a writing permission error, extracting the zip to ' . $this->cke_path . ' directory failed!
Please set "/plugins" or "/plugins/serendipity_event_ckeditor" directory and files correct writing permissions and extract ' . $this->cke_zipfile . ' by hand or try again and remove(!) this plugin from your plugin list and install it again.

'; break; } $this->set_config('installer', ''); // can't use serendipity_plugin_api::remove_plugin_value($this->instance, array('installer')); here, since it delivers the wrong instance } #echo $installer[0] . ' - ' . $this->instance; // this debug message on the other hand will do well, if all went through w/o install() returning false $s .= PLUGIN_EVENT_CKEDITOR_INSTALL; $s .= PLUGIN_EVENT_CKEDITOR_CONFIG; $s .= PLUGIN_EVENT_CKEDITOR_SCAYT; return $s; } /** * Downgrade of version to keep plugin version track with CKE versioning for upcoming next major upgrades! * This method is temporary only! * @see updateConfig() * @see checkUpdate() */ private function temporaryDowngrade($newVersion, $oldVersion) { global $serendipity; $thisclass = serendipity_db_escape_string('serendipity_event_ckeditor'); $row = serendipity_db_query("SELECT version FROM {$serendipity['dbPrefix']}pluginlist WHERE plugin_class = '" . $thisclass . "' AND pluginlocation = 'local' LIMIT 1", true, 'assoc'); $versions = array($oldVersion, $newVersion); // keep prior and current versions false check if (in_array($row['version'], $versions)) { return false; } serendipity_db_query("UPDATE {$serendipity['dbPrefix']}pluginlist SET version = '" . serendipity_db_escape_string($oldVersion) . "' WHERE plugin_class = '" . $thisclass . "' AND pluginlocation = 'local'"); serendipity_db_query("UPDATE {$serendipity['dbPrefix']}pluginlist SET upgrade_version = '" . serendipity_db_escape_string($newVersion) . "' WHERE plugin_class = '" . $thisclass . "' AND pluginlocation = 'local'"); } /** * Set config database table to keep track to zip update versions * @access private */ private function updateConfig() { #$this->temporaryDowngrade('4.5.10.3', '4.5.10.2'); // was temporary used for the harmonization of plugin and lib versions foreach(array_values($this->checkUpdateVersion) AS $package) { $match = explode(':', $package); $this->set_config('last_'.$match[0].'_version', $match[1]); } } /** * Check update versions to perform unzip and create config values * @access private * @return boolean */ private function checkUpdate() { #$this->temporaryDowngrade('4.5.10.3', '4.5.10.2'); // was temporary used for the harmonization of plugin and lib versions $doupdate = false; foreach(array_values($this->checkUpdateVersion) AS $package) { $match = explode(':', $package); // always set and extract if not match if ($this->get_config('last_'.$match[0].'_version') == $match[1]) { $doupdate = false; } else { $doupdate = true; break; // this is probably needed to force install upgrade routines } } return $doupdate; } /** * empty a directory using the Standard PHP Library (SPL) iterator * @access private * @param string directory */ private function empty_dir($dir) { if (!is_dir($dir)) return; try { $_dir = new RecursiveDirectoryIterator($dir); // NOTE: UnexpectedValueException thrown for PHP >= 5.3 } catch (Exception $e) { return; } $iterator = new RecursiveIteratorIterator($_dir, RecursiveIteratorIterator::CHILD_FIRST); foreach ($iterator AS $file) { if ($file->isFile()) { @unlink($file->__toString()); } else { @rmdir($file->__toString()); } } @rmdir(dir); } function event_hook($event, &$bag, &$eventData, $addData = null) { global $serendipity; $hooks = &$bag->get('event_hooks'); if (isset($hooks[$event])) { switch($event) { case 'frontend_header': $headcss = true; case 'frontend_footer': // set prettify.css and prettify.js in frontend footer by plugin option (too much overhead to split this into head css and food js!) if (serendipity_db_bool($this->get_config('codebutton', false))) { $plugingpath = function_exists('serendipity_specialchars') ? serendipity_specialchars($this->get_config('plugpath')) : htmlspecialchars($this->get_config('plugpath'), ENT_COMPAT, LANG_CHARSET); if ($headcss) { ?> get_config('prettify', false))) { if ($headcss) { ?> get_config('path')) : htmlspecialchars($this->get_config('path'), ENT_COMPAT, LANG_CHARSET); $plgpath = function_exists('serendipity_specialchars') ? serendipity_specialchars($this->get_config('plugpath')) : htmlspecialchars($this->get_config('plugpath'), ENT_COMPAT, LANG_CHARSET); $acf_off = serendipity_db_bool($this->get_config('acf_off', 'false')) ? 'true' : 'false'; // need this, to be passed correctly as boolean true/false to custom cke_config.js $code_on = serendipity_db_bool($this->get_config('codebutton', 'false')) ? 'true' : 'false'; // same here for cke_plugins.js $uats_on = $serendipity['use_autosave'] ? 'true' : 'false'; // dito $toolbar = $this->get_config('toolbar', 'Standard'); $time = $this->get_config('timestamp', time()); $slang = (isset($flocale) && !empty($flocale[0]) ? $flocale[0] : WYSIWYG_LANG); // set scayt locales 4-letter POSIX lang or fall back $lang = $slang ? $slang : 'en_US'; // use new WYSIWYG_LANG, or the workaround locale, or fall back to default $lang = str_replace('_', '-', $lang); // change to IETF standard unicode language tag, using a dash /* Define some global CKEDITOR plugin startup vars Include the ckeditor Build dynamic plugins and set the custom config (cke_config.js) Sadly this can not hook into js_backend hook in 2.0, since that is cached to lazyload */ ?> get_config('ibn_off', 'true')) ) { ?> get_config('codebutton', false))) { /* moved to highlight.css to prepend streamed css first (keep note!) CKEDITOR CODESNIPPET PLUGIN pre { word-wrap: inherit; fixes chrome issue } pre code { white-space: pre; overflow-x: auto; } .hljs { border-left: 5px solid #DDD; } */ if (serendipity_db_bool($this->get_config('prettify', false))) { ob_start(); ?> /* CKEDITOR PLUGIN PBCKCODE PRETTY PRINT */ .prettyprint { padding: 8px; background-color: #f7f7f9; border: 1px solid #e1e1e8; } .prettyprint.linenums { -webkit-box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0; -moz-box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0; box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0; } .content ol { margin: 0px 0px 1em 2em; } .serendipity_entry ol.linenums { padding-left: 40px; } ol.linenums li { padding-left: 1em; color: #bebec5; line-height: 1.6; text-shadow: 0 1px 0 #fff; } install()) { header('Location: ' . $serendipity['baseURL'] . 'serendipity_admin.php?serendipity[adminModule]=plugins&serendipity[plugin_to_conf]='.urlencode($this->instance)); } else { header('Location: ' . $serendipity['baseURL'] . 'serendipity_admin.php?serendipity[adminModule]=plugins&serendipity[plugin_to_conf]='.urlencode($this->instance)); } } break; case 'backend_plugins_update': if ($eventData == 'serendipity_event_ckeditor' && !$serendipity['ajax']) { // @TODO: This is is really messed up. Probably much better to perform a HTTP_Request to perform an action. Text below needs to be reworked, that all makes no sense to me. // Make sure a Spartacus update really falls down into this plugins config. // In case of using the UPDATE ALL 1-click ajax-upgrader, this redirection is disabled and you have to force the extraction yourself in the config. // This needs a *REAL* new HTTP request! Using plugin_to_conf:instance (see above) would not do here!! // A request to ...&serendipity[install_plugin]=serendipity_event_ckeditor would force a deflate, but would install another plugin instance! header('Location: ' . $serendipity['baseURL'] . ($serendipity['rewrite'] == 'none' ? $serendipity['indexFile'] . '?/' : '') . 'plugin/triggerckeinstall'); // This runtime breakage will reset all other plugins waiting to UPGRADE back to their current version in table pluginlist. // After this, the updater has to wait for a new read of the xml file(s) and to set pending plugins with setPluginInfo() method for versions and timestamp again. // This is not what we want here! So we nuke the blog-servers xml file in templates_c to later on continue with pending plugin updates. // Spartacus has to be prepared to set this global var. All other users probably have to wait up to 12h+. //#@unlink($serendipity['spartacus_cachedXMLfile']); //#die(); // now exit the runtime UPGRADE task executor, which forces to really halt into this->install() check redirector! } break; case 'backend_media_path_exclude_directories': $eventData[".thumbs"] = true; break; case 'backend_wysiwyg': $eventData['skip'] = true; // this skips htmlarea drop-in if (preg_match('@^nugget@i', $eventData['item'])) { // switch to finisher, in case of nuggets $this->event_hook('backend_wysiwyg_finish', $bag, $eventData); } else { if (serendipity_db_bool($this->get_config('codebutton'))) { // for case using customized toolbars, else it falls back to toolbar Group where 'others' is automatically added $bid = array(); if (isset($eventData['buttons']) && (is_array($eventData['buttons']) && !empty($eventData['buttons']))) foreach ($eventData['buttons'] AS $bt) { $bid[] = $bt['id']; } $addB = implode(",", $bid); $addB = str_replace(',','","',$addB); } // this builds both textareas of entry forms only if (isset($eventData['item']) && !empty($eventData['item'])) { $jebtnarr = (isset($eventData['buttons']) && (is_array($eventData['buttons']) && !empty($eventData['buttons']))) ? json_encode($eventData['buttons']) : 'null'; ?>