00001 <?php 00002 /* 00003 * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 00004 * Copyright (C) 2002-2007 The Nucleus Group 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU General Public License 00008 * as published by the Free Software Foundation; either version 2 00009 * of the License, or (at your option) any later version. 00010 * (see nucleus/documentation/index.html#license for more info) 00011 */ 00023 class NucleusPlugin { 00024 00025 // these functions _have_ to be redefined in your plugin 00026 00027 function getName() { return 'Undefined'; } 00028 function getAuthor() { return 'Undefined'; } 00029 function getURL() { return 'Undefined'; } 00030 function getVersion() { return '0.0'; } 00031 function getDescription() { return 'Undefined';} 00032 00033 // these function _may_ be redefined in your plugin 00034 00035 function getMinNucleusVersion() { return 150; } 00036 function getMinNucleusPatchLevel() { return 0; } 00037 function getEventList() { return array(); } 00038 function getTableList() { return array(); } 00039 function hasAdminArea() { return 0; } 00040 00041 function install() {} 00042 function unInstall() {} 00043 00044 function init() {} 00045 00046 function doSkinVar($skinType) {} 00047 function doTemplateVar(&$item) { 00048 $args = func_get_args(); 00049 array_shift($args); 00050 array_unshift($args, 'template'); 00051 call_user_func_array(array(&$this,'doSkinVar'),$args); 00052 } 00053 function doTemplateCommentsVar(&$item, &$comment) { 00054 $args = func_get_args(); 00055 array_shift($args); 00056 array_shift($args); 00057 array_unshift($args, 'template'); 00058 call_user_func_array(array(&$this,'doSkinVar'),$args); 00059 } 00060 function doAction($type) { return 'No Such Action'; } 00061 function doIf($key,$value) { return false; } 00062 function doItemVar () {} 00063 00073 function supportsFeature($feature) { 00074 return 0; 00075 } 00076 00082 function getPluginDep() { return array(); } 00083 00084 // these helper functions should not be redefined in your plugin 00085 00099 function createOption($name, $desc, $type, $defValue = '', $typeExtras = '') { 00100 return $this->_createOption('global', $name, $desc, $type, $defValue, $typeExtras); 00101 } 00102 function createBlogOption($name, $desc, $type, $defValue = '', $typeExtras = '') { 00103 return $this->_createOption('blog', $name, $desc, $type, $defValue, $typeExtras); 00104 } 00105 function createMemberOption($name, $desc, $type, $defValue = '', $typeExtras = '') { 00106 return $this->_createOption('member', $name, $desc, $type, $defValue, $typeExtras); 00107 } 00108 function createCategoryOption($name, $desc, $type, $defValue = '', $typeExtras = '') { 00109 return $this->_createOption('category', $name, $desc, $type, $defValue, $typeExtras); 00110 } 00111 function createItemOption($name, $desc, $type, $defValue = '', $typeExtras = '') { 00112 return $this->_createOption('item', $name, $desc, $type, $defValue, $typeExtras); 00113 } 00114 00120 function deleteOption($name) { 00121 return $this->_deleteOption('global', $name); 00122 } 00123 function deleteBlogOption($name) { 00124 return $this->_deleteOption('blog', $name); 00125 } 00126 function deleteMemberOption($name) { 00127 return $this->_deleteOption('member', $name); 00128 } 00129 function deleteCategoryOption($name) { 00130 return $this->_deleteOption('category', $name); 00131 } 00132 function deleteItemOption($name) { 00133 return $this->_deleteOption('item', $name); 00134 } 00135 00139 function setOption($name, $value) { 00140 return $this->_setOption('global', 0, $name, $value); 00141 } 00142 function setBlogOption($blogid, $name, $value) { 00143 return $this->_setOption('blog', $blogid, $name, $value); 00144 } 00145 function setMemberOption($memberid, $name, $value) { 00146 return $this->_setOption('member', $memberid, $name, $value); 00147 } 00148 function setCategoryOption($catid, $name, $value) { 00149 return $this->_setOption('category', $catid, $name, $value); 00150 } 00151 function setItemOption($itemid, $name, $value) { 00152 return $this->_setOption('item', $itemid, $name, $value); 00153 } 00154 00158 function getOption($name) 00159 { 00160 // only request the options the very first time. On subsequent requests 00161 // the static collection is used to save SQL queries. 00162 if ($this->plugin_options == 0) 00163 { 00164 $this->plugin_options = array(); 00165 $query = sql_query( 00166 'SELECT d.oname as name, o.ovalue as value '. 00167 'FROM '. 00168 sql_table('plugin_option').' o, '. 00169 sql_table('plugin_option_desc').' d '. 00170 'WHERE d.opid='. intval($this->getID()).' AND d.oid=o.oid' 00171 ); 00172 while ($row = mysql_fetch_object($query)) 00173 $this->plugin_options[strtolower($row->name)] = $row->value; 00174 } 00175 if (isset($this->plugin_options[strtolower($name)])) 00176 return $this->plugin_options[strtolower($name)]; 00177 else 00178 return $this->_getOption('global', 0, $name); 00179 } 00180 00181 function getBlogOption($blogid, $name) { 00182 return $this->_getOption('blog', $blogid, $name); 00183 } 00184 function getMemberOption($memberid, $name) { 00185 return $this->_getOption('member', $memberid, $name); 00186 } 00187 function getCategoryOption($catid, $name) { 00188 return $this->_getOption('category', $catid, $name); 00189 } 00190 function getItemOption($itemid, $name) { 00191 return $this->_getOption('item', $itemid, $name); 00192 } 00193 00198 function getAllBlogOptions($name) { 00199 return $this->_getAllOptions('blog', $name); 00200 } 00201 function getAllMemberOptions($name) { 00202 return $this->_getAllOptions('member', $name); 00203 } 00204 function getAllCategoryOptions($name) { 00205 return $this->_getAllOptions('category', $name); 00206 } 00207 function getAllItemOptions($name) { 00208 return $this->_getAllOptions('item', $name); 00209 } 00210 00215 function getBlogOptionTop($name, $amount = 10, $sort = 'desc') { 00216 return $this->_getOptionTop('blog', $name, $amount, $sort); 00217 } 00218 function getMemberOptionTop($name, $amount = 10, $sort = 'desc') { 00219 return $this->_getOptionTop('member', $name, $amount, $sort); 00220 } 00221 function getCategoryOptionTop($name, $amount = 10, $sort = 'desc') { 00222 return $this->_getOptionTop('category', $name, $amount, $sort); 00223 } 00224 function getItemOptionTop($name, $amount = 10, $sort = 'desc') { 00225 return $this->_getOptionTop('item', $name, $amount, $sort); 00226 } 00227 00238 function _getOptionTop($context, $name, $amount = 10, $sort = 'desc') { 00239 if (($sort != 'desc') && ($sort != 'asc')) { 00240 $sort= 'desc'; 00241 } 00242 00243 $oid = $this->_getOID($context, $name); 00244 00245 // retrieve the data and return 00246 $q = 'SELECT otype, oextra FROM '.sql_table('plugin_option_desc').' WHERE oid = '.$oid; 00247 $query = sql_query($q); 00248 00249 $o = mysql_fetch_array($query); 00250 00251 if (($this->optionCanBeNumeric($o['otype'])) && ($o['oextra'] == 'number' )) { 00252 $orderby = 'CAST(ovalue AS SIGNED)'; 00253 } else { 00254 $orderby = 'ovalue'; 00255 } 00256 $q = 'SELECT ovalue value, ocontextid id FROM '.sql_table('plugin_option').' WHERE oid = '.$oid.' ORDER BY '.$orderby.' '.$sort.' LIMIT 0,'.intval($amount); 00257 $query = sql_query($q); 00258 00259 // create the array 00260 $i = 0; 00261 $top = array(); 00262 while($row = mysql_fetch_array($query)) { 00263 $top[$i++] = $row; 00264 } 00265 00266 // return the array (duh!) 00267 return $top; 00268 } 00269 00273 function getID() { 00274 return $this->plugid; 00275 } 00276 00281 function getAdminURL() { 00282 global $CONF; 00283 return $CONF['PluginURL'] . $this->getShortName() . '/'; 00284 } 00285 00290 function getDirectory() { 00291 global $DIR_PLUGINS; 00292 return $DIR_PLUGINS . $this->getShortName() . '/'; 00293 } 00294 00298 function getShortName() { 00299 return str_replace('np_','',strtolower(get_class($this))); 00300 } 00301 00302 var $_aOptionValues; // oid_contextid => value 00303 var $_aOptionToInfo; // context_name => array('oid' => ..., 'default' => ...) 00304 var $plugin_options; // see getOption() 00305 var $plugid; // plugin id 00306 00307 00308 // constructor. Initializes some internal data 00309 function NucleusPlugin() { 00310 $this->_aOptionValues = array(); // oid_contextid => value 00311 $this->_aOptionToInfo = array(); // context_name => array('oid' => ..., 'default' => ...) 00312 $this->plugin_options = 0; 00313 } 00314 00315 function clearOptionValueCache(){ 00316 $this->_aOptionValues = array(); 00317 } 00318 00319 // private 00320 function _createOption($context, $name, $desc, $type, $defValue, $typeExtras = '') { 00321 // create in plugin_option_desc 00322 $query = 'INSERT INTO ' . sql_table('plugin_option_desc') 00323 .' (opid, oname, ocontext, odesc, otype, odef, oextra)' 00324 .' VALUES ('.intval($this->plugid) 00325 .', \''.addslashes($name).'\'' 00326 .', \''.addslashes($context).'\'' 00327 .', \''.addslashes($desc).'\'' 00328 .', \''.addslashes($type).'\'' 00329 .', \''.addslashes($defValue).'\'' 00330 .', \''.addslashes($typeExtras).'\')'; 00331 sql_query($query); 00332 $oid = mysql_insert_id(); 00333 00334 $key = $context . '_' . $name; 00335 $this->_aOptionToInfo[$key] = array('oid' => $oid, 'default' => $defValue); 00336 return 1; 00337 } 00338 00339 00340 // private 00341 function _deleteOption($context, $name) { 00342 $oid = $this->_getOID($context, $name); 00343 if (!$oid) return 0; // no such option 00344 00345 // delete all things from plugin_option 00346 sql_query('DELETE FROM ' . sql_table('plugin_option') . ' WHERE oid=' . $oid); 00347 00348 // delete entry from plugin_option_desc 00349 sql_query('DELETE FROM ' . sql_table('plugin_option_desc') . ' WHERE oid=' . $oid); 00350 00351 // clear from cache 00352 unset($this->_aOptionToInfo[$context . '_' . $name]); 00353 $this->_aOptionValues = array(); 00354 return 1; 00355 } 00356 00361 function _setOption($context, $contextid, $name, $value) { 00362 global $manager; 00363 00364 $oid = $this->_getOID($context, $name); 00365 if (!$oid) return 0; 00366 00367 // check if context id exists 00368 switch ($context) { 00369 case 'member': 00370 if (!MEMBER::existsID($contextid)) return 0; 00371 break; 00372 case 'blog': 00373 if (!$manager->existsBlogID($contextid)) return 0; 00374 break; 00375 case 'category': 00376 if (!$manager->existsCategory($contextid)) return 0; 00377 break; 00378 case 'item': 00379 if (!$manager->existsItem($contextid, true, true)) return 0; 00380 break; 00381 case 'global': 00382 if ($contextid != 0) return 0; 00383 break; 00384 } 00385 00386 00387 // update plugin_option 00388 sql_query('DELETE FROM ' . sql_table('plugin_option') . ' WHERE oid='.intval($oid) . ' and ocontextid='. intval($contextid)); 00389 sql_query('INSERT INTO ' . sql_table('plugin_option') . ' (ovalue, oid, ocontextid) VALUES (\''.addslashes($value).'\', '. intval($oid) . ', ' . intval($contextid) . ')'); 00390 00391 // update cache 00392 $this->_aOptionValues[$oid . '_' . $contextid] = $value; 00393 00394 return 1; 00395 } 00396 00397 // private 00398 function _getOption($context, $contextid, $name) { 00399 $oid = $this->_getOID($context, $name); 00400 if (!$oid) return ''; 00401 00402 00403 $key = $oid . '_' . $contextid; 00404 00405 if (isset($this->_aOptionValues[$key])) 00406 return $this->_aOptionValues[$key]; 00407 00408 // get from DB 00409 $res = sql_query('SELECT ovalue FROM ' . sql_table('plugin_option') . ' WHERE oid='.intval($oid).' and ocontextid=' . intval($contextid)); 00410 00411 if (!$res || (mysql_num_rows($res) == 0)) { 00412 $defVal = $this->_getDefVal($context, $name); 00413 $this->_aOptionValues[$key] = $defVal; 00414 00415 // fill DB with default value 00416 $query = 'INSERT INTO ' . sql_table('plugin_option') . ' (oid,ocontextid,ovalue)' 00417 .' VALUES ('.intval($oid).', '.intval($contextid).', \''.addslashes($defVal).'\')'; 00418 sql_query($query); 00419 } 00420 else { 00421 $o = mysql_fetch_object($res); 00422 $this->_aOptionValues[$key] = $o->ovalue; 00423 } 00424 00425 return $this->_aOptionValues[$key]; 00426 } 00427 00432 function _getAllOptions($context, $name) { 00433 $oid = $this->_getOID($context, $name); 00434 if (!$oid) return array(); 00435 $defVal = $this->_getDefVal($context, $name); 00436 00437 $aOptions = array(); 00438 switch ($context) { 00439 case 'blog': 00440 $r = sql_query('SELECT bnumber as contextid FROM ' . sql_table('blog')); 00441 break; 00442 case 'category': 00443 $r = sql_query('SELECT catid as contextid FROM ' . sql_table('category')); 00444 break; 00445 case 'member': 00446 $r = sql_query('SELECT mnumber as contextid FROM ' . sql_table('member')); 00447 break; 00448 case 'item': 00449 $r = sql_query('SELECT inumber as contextid FROM ' . sql_table('item')); 00450 break; 00451 } 00452 if ($r) { 00453 while ($o = mysql_fetch_object($r)) 00454 $aOptions[$o->contextid] = $defVal; 00455 } 00456 00457 $res = sql_query('SELECT ocontextid, ovalue FROM ' . sql_table('plugin_option') . ' WHERE oid=' . $oid); 00458 while ($o = mysql_fetch_object($res)) 00459 $aOptions[$o->ocontextid] = $o->ovalue; 00460 00461 return $aOptions; 00462 } 00463 00469 function _getOID($context, $name) { 00470 $key = $context . '_' . $name; 00471 $info = @$this->_aOptionToInfo[$key]; 00472 if (is_array($info)) return $info['oid']; 00473 00474 // load all OIDs for this plugin from the database 00475 $this->_aOptionToInfo = array(); 00476 $query = 'SELECT oid, oname, ocontext, odef FROM ' . sql_table('plugin_option_desc') . ' WHERE opid=' . intval($this->plugid); 00477 $res = sql_query($query); 00478 while ($o = mysql_fetch_object($res)) { 00479 $k = $o->ocontext . '_' . $o->oname; 00480 $this->_aOptionToInfo[$k] = array('oid' => $o->oid, 'default' => $o->odef); 00481 } 00482 mysql_free_result($res); 00483 00484 return @$this->_aOptionToInfo[$key]['oid']; 00485 } 00486 function _getDefVal($context, $name) { 00487 $key = $context . '_' . $name; 00488 $info = $this->_aOptionToInfo[$key]; 00489 if (is_array($info)) return $info['default']; 00490 } 00491 00492 00499 function _deleteOptionValues($context, $contextid) { 00500 // delete all associated plugin options 00501 $aOIDs = array(); 00502 // find ids 00503 $query = 'SELECT oid FROM '.sql_table('plugin_option_desc') . ' WHERE ocontext=\''.addslashes($context).'\''; 00504 $res = sql_query($query); 00505 while ($o = mysql_fetch_object($res)) 00506 array_push($aOIDs, $o->oid); 00507 mysql_free_result($res); 00508 // delete those options. go go go 00509 if (count($aOIDs) > 0) { 00510 $query = 'DELETE FROM ' . sql_table('plugin_option') . ' WHERE oid in ('.implode(',',$aOIDs).') and ocontextid=' . intval($contextid); 00511 sql_query($query); 00512 } 00513 } 00514 00522 function getOptionMeta($typeExtra) { 00523 $tmpMeta = explode(';', $typeExtra); 00524 $meta = array(); 00525 for ($i = 0; $i < count($tmpMeta); $i++) { 00526 if (($i == 0) && (!strstr($tmpMeta[0], '='))) { 00527 // we have the select-list 00528 $meta['select'] = $tmpMeta[0]; 00529 } else { 00530 $tmp = explode('=', $tmpMeta[$i]); 00531 $meta[$tmp[0]] = $tmp[1]; 00532 } 00533 } 00534 return $meta; 00535 } 00536 00543 function getOptionSelectValues($typeExtra) { 00544 $meta = NucleusPlugin::getOptionMeta($typeExtra); 00545 //the select list must always be the first part 00546 return $meta['select']; 00547 } 00548 00554 function subscribtionListIsUptodate() { 00555 $res = sql_query('SELECT event FROM '.sql_table('plugin_event').' WHERE pid = '.$this->getID()); 00556 $ev = array(); 00557 while($a = mysql_fetch_array($res)) { 00558 array_push($ev, $a['event']); 00559 } 00560 if (count($ev) != count($this->getEventList())) { 00561 return false; 00562 } 00563 $d = array_diff($ev, $this->getEventList()); 00564 if (count($d) > 0) { 00565 // there are differences so the db is not up-to-date 00566 return false; 00567 } 00568 return true; 00569 } 00570 00579 function _applyPluginOptions(&$aOptions, $newContextid = 0) { 00580 global $manager; 00581 if (!is_array($aOptions)) return; 00582 00583 foreach ($aOptions as $oid => $values) { 00584 00585 // get option type info 00586 $query = 'SELECT opid, oname, ocontext, otype, oextra, odef FROM ' . sql_table('plugin_option_desc') . ' WHERE oid=' . intval($oid); 00587 $res = sql_query($query); 00588 if ($o = mysql_fetch_object($res)) 00589 { 00590 foreach ($values as $key => $value) { 00591 // avoid overriding the key used by foreach statement 00592 $contextid=$key; 00593 00594 // retreive any metadata 00595 $meta = NucleusPlugin::getOptionMeta($o->oextra); 00596 00597 // if the option is readonly or hidden it may not be saved 00598 if ((@$meta['access'] != 'readonly') && (@$meta['access'] != 'hidden')) { 00599 00600 $value = undoMagic($value); // value comes from request 00601 00602 switch($o->otype) { 00603 case 'yesno': 00604 if (($value != 'yes') && ($value != 'no')) $value = 'no'; 00605 break; 00606 default: 00607 break; 00608 } 00609 00610 // check the validity of numerical options 00611 if ((@$meta['datatype'] == 'numerical') && (!is_numeric($value))) { 00612 //the option must be numeric, but the it isn't 00613 //use the default for this option 00614 $value = $o->odef; 00615 } 00616 00617 // decide wether we are using the contextid of newContextid 00618 if ($newContextid != 0) { 00619 $contextid = $newContextid; 00620 } 00621 00622 //trigger event PrePluginOptionsUpdate to give the plugin the 00623 //possibility to change/validate the new value for the option 00624 $manager->notify('PrePluginOptionsUpdate',array('context' => $o->ocontext, 'plugid' => $o->opid, 'optionname' => $o->oname, 'contextid' => $contextid, 'value' => &$value)); 00625 00626 // delete the old value for the option 00627 sql_query('DELETE FROM '.sql_table('plugin_option').' WHERE oid='.intval($oid).' AND ocontextid='.intval($contextid)); 00628 sql_query('INSERT INTO '.sql_table('plugin_option')." (oid, ocontextid, ovalue) VALUES (".intval($oid).",".intval($contextid).",'" . addslashes($value) . "')"); 00629 } 00630 } 00631 } 00632 // clear option value cache if the plugin object is already loaded 00633 if (is_object($o)) { 00634 $plugin=& $manager->pidLoaded($o->opid); 00635 if ($plugin) $plugin->clearOptionValueCache(); 00636 } 00637 } 00638 } 00639 } 00640 ?>