Source for file pnMod.php
Documentation is available at pnMod.php
* Zikula Application Framework
* @copyright (c) 2001, Zikula Development Team
* @link http://www.zikula.org
* @version $Id: pnMod.php 24342 2008-06-06 12:03:14Z markwest $
* @license GNU/GPL - http://www.gnu.org/copyleft/gpl.html
* preloads module vars for a number of key modules to reduce sql statements
function pnModInitCoreVars()
// don't init vars during the installer
// if we haven't got vars for this module yet then lets get them
$col = $pntables['module_vars_column'];
$where = "$col[modname]='". PN_CONFIG_MODULE . "' OR $col[modname]='pnRender' OR $col[modname]='Theme' OR $col[modname]='Blocks' OR $col[modname]='Users' OR $col[modname]='Settings' OR $col[modname]='Profile'";
foreach ($pnmodvars as $var) {
$pnmodvar[$var['modname']][$var['name']] = @unserialize($var['value']);
* pnModVarExists - check to see if a module variable is set
* @param 'modname' the name of the module
* @param 'name' the name of the variable
* @return true if the variable exists in the database, false if not
// define input, all numbers and booleans to strings
$modname = isset ($modname) ? ((string) $modname) : '';
$name = isset ($name) ? ((string) $name) : '';
// make sure we have the necessary parameters
// get all module vars for this module
// return boolean indicator
// bp 2008-03-01 checking with isset() will prevent variables with Null values to be found!
// bp 2008-03-03 we revert to the old logic because some other code can't handle Null variables
return isset ($modvars[$name]);
// if (is_null($modvars[$name]) || isset($modvars[$name])) {
* pnModGetVar - get a module variable
* if the name parameter is included then function returns the
* if the name parameter is ommitted then function returns a multi
* dimentional array of the keys and values for the module vars.
* @author Jim McDonald <jim@mcdee.net>
* @param 'modname' the name of the module
* @param 'name' the name of the variable
* @param 'default' the value to return if the requested modvar is not set
* @return if the name parameter is included then function returns
* string - module variable value
* if the name parameter is ommitted then function returns
* array - multi dimentional array of the keys
* and values for the module vars.
function pnModGetVar($modname, $name= '', $default= false)
// if we don't know the modname then lets assume it is the current
// if we haven't got vars for this module yet then lets get them
if (!isset ($pnmodvar[$modname])) {
$col = $pntables['module_vars_column'];
$sort = ' '; // this is not a mistake, it disables the default sort for DBUtil::selectFieldArray()
foreach($results as $k => $v) {
// Be carefull to allow check for unserialize of empty values and boolean false
if ($pnmodvar[$modname][$k] === false && $v != 'b:0;') {
// backwards compatibility for non-serialized vars
$pnmodvar[$modname][$k] = $v;
// if they didn't pass a variable name then return every variable
// for the specified module as an associative array.
// array('var1'=>value1, 'var2'=>value2)
if (empty($name) && isset ($pnmodvar[$modname])) {
return $pnmodvar[$modname];
// since they passed a variable name then only return the value for
// bp 2008-03-01 just checking with isset() will prevent Null values to be returned! (bug #15857)
// bp 2008-03-03 we revert to the old logic because some other code can't handle Null variables
if (isset ($pnmodvar[$modname][$name])) {
// if (is_null($pnmodvar[$modname][$name]) || isset($pnmodvar[$modname][$name])) {
return $pnmodvar[$modname][$name];
// we don't know the required module var but we established all known
// module vars for this module so the requested one can't exist.
// we return the default (which itself defaults to false)
* pnModSetVar - set a module variable
* @author Jim McDonald <jim@mcdee.net>
* @link http://www.mcdee.net
* @param 'modname' the name of the module
* @param 'name' the name of the variable
* @param 'value' the value of the variable
* @return bool true if successful, false otherwise
// define input, all numbers and booleans to strings
$modname = isset ($modname) ? ((string) $modname) : '';
// bp 2008-03-03 - workaround for bug bug #15857
// code removed to fix bugs #15939 and #15968
/*if (isset($name) && is_null($value)) {
return LogUtil::registerError (pnML('_ERROR_NONULLVALUEALLOWED', array('modname' => $modname, 'varname' => $name)));
// This test can be removed after a future 0.8 release - drak
$cols = $pntable['module_vars_column'];
$obj['modname'] = $modname;
$pnmodvar[$modname][$name] = $value;
* pnModSetVars - set multiple module variables
* @param 'modname' the name of the module
* @param 'vars' an associative array of varnames/varvalues.
* @return bool true if successful, false otherwise
foreach ($vars as $var => $value)
* Delete a module variables. If the optional name parameter is not supplied all variables
* for the module 'modname' are deleted
* @author Jim McDonald <jim@mcdee.net>
* @link http://www.mcdee.net
* @param 'modname' the name of the module
* @param 'name' the name of the variable (optional)
* @return bool true if successful, false otherwise
// define input, all numbers and booleans to strings
$modname = isset ($modname) ? ((string) $modname) : '';
if (isset ($pnmodvar[$modname])) {
unset ($pnmodvar[$modname]);
if (isset ($pnmodvar[$modname][$name])) {
$val = $pnmodvar[$modname][$name];
unset ($pnmodvar[$modname][$name]);
$cols = $pntable['module_vars_column'];
// check if we're deleting one module var or all module vars
$specificvar = " AND $cols[name] = '$name'";
$where = "WHERE $cols[modname] = '$modname' $specificvar";
return ($val ? $val : $res);
* pnModGetIDFromName - get module ID given its name
* @author Jim McDonald <jim@mcdee.net>
* @link http://www.mcdee.net
* @param 'module' the name of the module
// define input, all numbers and booleans to strings
$module = (isset ($module) ? strtolower((string) $module) : '');
if (substr($module,0,3) == 'ns-') {
$modules = pnModGetModsTable();
if ($modules === false) {
foreach ($modules as $mod) {
$modid[$mName] = $mod['id'];
if (isset ($mod['displayname']) && $mod['displayname'])
$modid[$mdName] = $mod['id'];
if (!isset ($modid[$module])) {
if (isset ($modid[$module])) {
* get information on module
* return array of module information or false if core ( id = 0 )
* @author Jim McDonald <jim@mcdee.net>
* @link http://www.mcdee.net
* @return mixed module information array or false
// a $modid of 0 is associated with core ( pn_blocks.mid, ... ).
$modinfo = pnModGetModsTable();
if (!isset ($modinfo[$modid])) {
$modinfo[$modid] = false;
if (isset ($modinfo[$modid])) {
* get list of user modules
* @author Jim McDonald <jim@mcdee.net>
* @link http://www.mcdee.net
* @return array array of module information arrays
* get list of administration modules
* @author Jim McDonald <jim@mcdee.net>
* @link http://www.mcdee.net
* @return array array of module information arrays
* get list of modules by module type
* @author Jim McDonald <jim@mcdee.net>
* @param 'type' the module type to get (either 'user' or 'admin') (optional) (default='user')
* @return array array of module information arrays
if ($type != 'user' && $type != 'admin')
static $modcache = array();
if (!isset ($modcache[$type]) || !$modcache[$type])
$modcache[$type] = array();
$cap = $type . '_capable';
$mods = pnModGetAllMods();
$ak = array_keys ($mods);
$modcache[$type][] = $mods[$k];
* get list of all modules
* @author Mark West <mark@markwest.me.uk>
* @link http://www.markwest.me.uk
* @return array array of module information arrays
static $modsarray = array();
$pntable = pnDBGetTables();
$modulescolumn = $pntable['modules_column'];
$where = "WHERE $modulescolumn[state] = " . PNMODULE_STATE_ACTIVE . "
OR $modulescolumn[name] = 'Modules'";
$orderBy = "ORDER BY $modulescolumn[displayname]";
$modsarray = DBUtil::selectObjectArray('modules', $where, $orderBy);
if ($modsarray === false) {
* load datbase definition for a module
* @author Jim McDonald <jim@mcdee.net>
* @link http://www.mcdee.net
* @param 'name' the name of the module to load database definition for
* @param 'directory' directory that module is in (if known)
* @param 'force' force table information to be reloaded
* @return bool true if successful, false otherwise
// define input, all numbers and booleans to strings
$modname = (isset ($modname) ? strtolower((string) $modname) : '');
static $loaded = array();
// Check to ensure we aren't doing this twice
if (isset ($loaded[$modname]) && !$force) {
// Get the directory if we don't already have it
$directory = $modinfo['directory'];
// not required since it's done elsewhere
//$osDirectory = DataUtil::formatForOS($directory);
// Load the database definition if required
$files[] = "config/functions/$directory/pntables.php";
$files[] = "system/$directory/pntables.php";
$files[] = "modules/$directory/pntables.php";
$tablefunc = $modname . '_pntables';
// V4B RNG: added casts to ensure proper behaviour under PHP5
$GLOBALS['pntables'] = array_merge((array) $GLOBALS['pntables'], (array) $data);
$loaded[$modname] = true;
// V4B RNG: return data so we know which tables were loaded by this module
* @param 'name' the name of the module
* @param 'type' the type of functions to load
* @param 'force' determines to load Module even if module isn't active
* @return string name of module loaded, or false on failure
function pnModLoad($modname, $type= 'user', $force= false)
return pnModLoadGeneric ($modname, $type, $force);
* @param 'name' the name of the module
* @param 'type' the type of functions to load
* @param 'force' determines to load Module even if module isn't active
* @return string name of module loaded, or false on failure
return pnModLoadGeneric ($modname, $type, $force, true);
* @author Jim McDonald <jim@mcdee.net>
* @param 'name' the name of the module
* @param 'type' the type of functions to load
* @param 'force' determines to load Module even if module isn't active
* @param 'api' whether or not to load an API (or regular) module
* @return string name of module loaded, or false on failure
function pnModLoadGeneric($modname, $type= 'user', $force= false, $api= false)
// define input, all numbers and booleans to strings
$osapi = ($api ? 'api' : '');
$modname = isset ($modname) ? ((string) $modname) : '';
static $loaded = array();
if (!empty($loaded[$modtype])) {
// Already loaded from somewhere else
// check the modules state
if (!$modinfo) { // check for bad pnVarValidate($modname)
// create variables for the OS preped version of the directory
$mosfile = "modules/$osdirectory/pn{$ostype}{$osapi}.php";
$sosfile = "system/$osdirectory/pn{$ostype}{$osapi}.php";
$mosdir = "modules/$osdirectory/pn{$ostype}{$osapi}";
$sosdir = "system/$osdirectory/pn{$ostype}{$osapi}";
// Load the file from modules
// Load the file from system
// Load the module language files
* @author Jim McDonald <jim@mcdee.net>
* @link http://www.mcdee.net
* @param 'modname' the name of the module
* @param 'type' the type of function to run
* @param 'func' the specific function to run
* @param 'args' the arguments to pass to the function
function pnModFunc($modname, $type= 'user', $func= 'main', $args= array())
return pnModFuncExec($modname, $type, $func, $args);
* run a module API function
* @author Jim McDonald <jim@mcdee.net>
* @link http://www.mcdee.net
* @param 'modname' the name of the module
* @param 'type' the type of function to run
* @param 'func' the specific function to run
* @param 'args' the arguments to pass to the function
function pnModAPIFunc($modname, $type= 'user', $func= 'main', $args= array())
return pnModFuncExec($modname, $type, $func, $args, true);
* @param 'modname' the name of the module
* @param 'type' the type of function to run
* @param 'func' the specific function to run
* @param 'args' the arguments to pass to the function
* @param 'api' whether or not to execute an API (or regular) function
function pnModFuncExec ($modname, $type= 'user', $func= 'main', $args= array(), $api= false)
// define input, all numbers and booleans to strings
$modname = isset ($modname) ? ((string) $modname) : '';
$ftype = ($api ? 'api' : '');
$loadfunc = ($api ? 'pnModAPILoad' : 'pnModLoad');
$path = ($modinfo['type'] == '3' ? 'system' : 'modules');
// Build function name and call function
$modfunc = "{ $modname}_{ $type}{ $ftype}_{ $func}";
if ($loadfunc($modname, $type)) {
if (($GLOBALS['loadstages'] & PN_CORE_THEME) && file_exists($file = "themes/$theme/functions/$modname/pn{$type}{$ftype}/$func.php")) {
} elseif (file_exists($file = "config/functions/$modname/pn{$type}{$ftype}/$func.php")) {
} elseif (file_exists($file = "$path/$modname/pn{$type}{$ftype}/$func.php")) {
// if we get here, the function does not exist - show an error and die()
// to-do: get execptions working for better handling of such errors
// commented out for the minute since the new url scheme calls a module
// api that might not exist (to decode module specific urls) - markwest
/* include_once 'header.php';
echo DataUtil::formatForDisplayHTML(_UNKNOWNFUNC) . " " . DataUtil::formatForDisplay($modfunc) . "()<br />\n";
if (SecurityUtil::checkPermission($modname . '.*', '.*', ACCESS_ADMIN)) {
foreach($args as $key => $value) {
echo DataUtil::formatForDisplay($key) . " => " . DataUtil::formatForDisplay($value) . "<br />\n";
include_once 'footer.php';
* generate a module function URL
* if the module is non-API compliant (type 1) then
* b) $type=admin will generate admin.php?module=... and $type=user will generate index.php?name=...
* @author Jim McDonald <jim@mcdee.net>
* @link http://www.mcdee.net
* @param 'modname' the name of the module
* @param 'type' the type of function to run
* @param 'func' the specific function to run
* @param 'args' the array of arguments to put on the URL
* @param 'ssl' set to constant null,true,false $ssl = true not $ssl = 'true' null - leave the current status untouched, true - create a ssl url, false - create a non-ssl url
* @param 'fragment' the framgment to target within the URL
* @param 'fqurl' Fully Qualified URL. True to get full URL, eg for Redirect, else gets root-relative path unless SSL
* @return sting absolute URL for call
function pnModURL($modname, $type = 'user', $func = 'main', $args = array(), $ssl = null, $fragment = null, $fqurl = null)
// define input, all numbers and booleans to strings
$modname = isset ($modname) ? ((string) $modname) : '';
// set the module name to the display name if this is present
if (isset ($modinfo['displayname']) && !empty($modinfo['displayname'])) {
// define some statics as this API is likely to be called many times
static $entrypoint, $host, $baseuri, $https, $shorturls, $shorturlstype, $shorturlsstripentrypoint;
if (!isset ($entrypoint)) {
if (empty($host)) return false;
// use friendly url setup
if (!isset ($shorturls)) {
if (!isset ($shorturlstype)) {
if (!isset ($shorturlsstripentrypoint)) {
$shorturlsstripentrypoint = pnConfigGetVar('shorturlsstripentrypoint');
// Only produce full URL when HTTPS is on or $ssl is set
if ((isset ($https) && $https == 'on') || $ssl != null || $fqurl == true) {
$siteRoot = 'http'. (($https == 'on' && $ssl !== false) || $ssl === true ? 's': ''). '://'. $host. $baseuri. '/';
// Only convert User URLs. Exclude links that append a theme parameter
if ($shorturls && $shorturlstype == 0 && $type== 'user') {
if (isset ($args['theme'])) {
// Module-specific Short URLs
$url = pnModAPIFunc($modinfo['name'], 'user', 'encodeurl', array('modname' => $modname, 'type' => $type, 'func' => $func, 'args' => $args));
// Generic short URLs: [module]/[function]/[param1]/[value1]/[param2]/[value2]
foreach ($args as $k => $v) {
foreach ($v as $k2 => $w) {
$vars .= "/$k[$k2]/$w"; // &$k[$k2]=$w
$vars .= "/$k/$v"; // &$k=$v
if ((!empty($func) && $func != 'main') || $vars != '') {
$url = $modname. $func. $vars;
if (!$shorturlsstripentrypoint) {
$url = "$entrypoint/$url". (!empty($query) ? '?'. $query : '');
$url = "$url". (!empty($query) ? '?'. $query : '');
$urlargs = "module=$modname";
if ((!empty($type)) && ($type != 'user'))
$urlargs .= "&type=$type";
if ((!empty($func)) && ($func != 'main'))
$urlargs .= "&func=$func";
$url = "$entrypoint?$urlargs";
// <rabbitt> added array check on args
foreach ($args as $k => $v) {
foreach($v as $l => $w) {
$url .= "&$k" . "[$l]=$w";
* see if a module is available
* @author Jim McDonald <jim@mcdee.net>
* @link http://www.mcdee.net
* @param 'modname' the name of the module
* @return bool true if the module is available, false if not
// define input, all numbers and booleans to strings
$modname = (isset ($modname) ? strtolower((string) $modname) : '');
static $modstate = array();
if (!isset ($modstate[$modname])) {
$modinfo = pnModGetInfo(pnModGetIDFromName($modname));
$modstate[$modname] = $modinfo['state'];
if ((isset ($modstate[$modname]) && $modstate[$modname] == PNMODULE_STATE_ACTIVE) ||
* get name of current top-level module
* @author Jim McDonald <jim@mcdee.net>
* @link http://www.mcdee.net
* @return string the name of the current top-level module, false if not in a module
if (empty($modname) || (!pnModAvailable($modname) && $type <> 'init')) {
// anything from user.php is the user module
// not really - of course but it'll do..... [markwest]
if (stristr($_SERVER['PHP_SELF'], 'user.php')) {
// strip any NS- prefixes
if (substr($ourmod,0,3) == 'NS-') {
// the parameters may provide the module alias so lets get
// the real name from the db
$module = isset ($modinfo['name']) ? $modinfo['name'] : $ourmod;
* register a hook function
* @author Jim McDonald <jim@mcdee.net>
* @link http://www.mcdee.net
* @param 'hookobject' the hook object
* @param 'hookaction' the hook action
* @param 'hookarea' the area of the hook (either 'GUI' or 'API')
* @param 'hookmodule' name of the hook module
* @param 'hooktype' name of the hook type
* @param 'hookfunc' name of the hook function
* @return bool true if successful, false otherwise
$hookmodule, $hooktype, $hookfunc)
// define input, all numbers and booleans to strings
$hookmodule = isset ($hookmodule) ? ((string) $hookmodule) : '';
$obj = array('object' => $hookobject,
'tmodule' => $hookmodule,
* unregister a hook function
* @author Jim McDonald <jim@mcdee.net>
* @link http://www.mcdee.net
* @param 'hookobject' the hook object
* @param 'hookaction' the hook action
* @param 'hookarea' the area of the hook (either 'GUI' or 'API')
* @param 'hookmodule' name of the hook module
* @param 'hooktype' name of the hook type
* @param 'hookfunc' name of the hook function
* @return bool true if successful, false otherwise
$hookmodule, $hooktype, $hookfunc)
// define input, all numbers and booleans to strings
$hookmodule = isset ($hookmodule) ? ((string) $hookmodule) : '';
$hookscolumn = $pntable['hooks_column'];
* carry out hook operations for module
* @author Jim McDonald <jim@mcdee.net>
* @link http://www.mcdee.net
* @param 'hookobject' the object the hook is called for - one of 'item', 'category' or 'module'
* @param 'hookaction' the action the hook is called for - one of 'new', 'create', 'modify', 'update', 'delete', 'transform', 'display', 'modifyconfig', 'updateconfig'
* @param 'hookid' the id of the object the hook is called for (module-specific)
* @param 'extrainfo' extra information for the hook, dependent on hookaction
* @param 'implode' implode collapses all display hooks into a single string - default to true for compatability with .7x
* @return mixed string output from GUI hooks, extrainfo array for API hooks
function pnModCallHooks($hookobject, $hookaction, $hookid, $extrainfo= array(), $implode = true)
if (!isset ($hookaction)) {
if (isset ($extrainfo['module']) &&
$modname = $extrainfo['module'];
if (!isset ($modulehooks[$lModname])) {
$hookscolumn = $pntable['hooks_column'];
$orderby = "$hookscolumn[sequence] ASC";
$modulehooks[$lModname] = $hooks;
foreach($modulehooks[$lModname] as $modulehook) {
if (!isset ($extrainfo['tmodule']) || (isset ($extrainfo['tmodule']) && $extrainfo['tmodule'] == $modulehook['tmodule'])) {
if (($modulehook['action'] == $hookaction) && ($modulehook['object'] == $hookobject)) {
if (isset ($modulehook['tarea']) && $modulehook['tarea'] == 'GUI') {
if (pnModAvailable($modulehook['tmodule'], $modulehook['ttype']) && pnModLoad($modulehook['tmodule'], $modulehook['ttype'])) {
$output[$modulehook['tmodule']] = pnModFunc($modulehook['tmodule'], $modulehook['ttype'], $modulehook['tfunc'],
array('objectid' => $hookid,
'extrainfo' => $extrainfo));
if (isset ($modulehook['tmodule']) && pnModAvailable($modulehook['tmodule'], $modulehook['ttype']) && pnModAPILoad($modulehook['tmodule'], $modulehook['ttype'])) {
$extrainfo = pnModAPIFunc($modulehook['tmodule'], $modulehook['ttype'], $modulehook['tfunc'],
array('objectid' => $hookid,
'extrainfo' => $extrainfo));
// check what type of information we need to return
$hookaction == 'display' ||
$hookaction == 'modify' ||
$hookaction == 'modifyconfig') {
if ($implode || empty($output)) {
* Determine if a module is hooked by another module
* @author Mark West (mark@markwest.me.uk)
* @link http://www.markwest.me.uk
* @param 'tmodule' the target module
* @param 'smodule' the source module - default the current top most module
* @return bool true if the current module is hooked by the target module, false otherwise
static $hooked = array();
if (isset ($hooked[$tmodule][$smodule])) {
return $hooked[$tmodule][$smodule];
// define input, all numbers and booleans to strings
$tmodule = isset ($tmodule) ? ((string) $tmodule) : '';
$smodule = isset ($smodule) ? ((string) $smodule) : '';
$hookscolumn = $pntable['hooks_column'];
$hooked[$tmodule][$smodule] = ($numitems > 0);
return $hooked[$tmodule][$smodule];
* loads the language files for a module
* @link http://www.markwest.me.uk
* @param modname - name of the module
* @param type - type of the language file to load e.g. user, admin
* @param api - load api lang file or gui lang file
// define input, all numbers and booleans to strings
$modname = isset ($modname) ? ((string) $modname) : '';
// create variables for the OS preped version of the directory
$directory = $modinfo['directory'];
$path = ($modinfo['type'] == '3' ? 'system' : 'modules');
$moddir = "$path/$directory/pnlang";
$osfile = $type . $osapi . '.php';
// This directory is for easy of use when developing language packs.
// See http://community.zikula.org/index.php?module=Wiki&tag=LanguagePack
if (isset ($GLOBALS['PNConfig']['System']['development']) && $GLOBALS['PNConfig']['System']['development'])
$files[] = "config/languages/$currentlang/$moddir/$currentlang/$osfile";
$files[] = "config/languages/$currentlang/$directory/$osfile";
$files[] = "$moddir/$currentlang/$osfile";
$files[] = "config/languages/$defaultlang/$directory/$osfile";
$files[] = "$moddir/$defaultlang/$osfile";
* Get the base directory for a module
* Example: If the webroot is located at
* and the module name is Template and is found
* in the modules directory then this function
* would return /var/www/html/modules/Template
* If the Template module was located in the system
* directory then this function would return
* /var/www/html/system/Template
* This allows you to say:
* include(pnModGetBaseDir() . '/includes/private_functions.php');
* @param $modname - name of module to that you want the
* @return string - the path from the root directory to the
$directory = 'system/'. $modname;
$directory = 'modules/'. $modname;
* small wrapper function to avoid duplicate sql
* @return array modules table
function pnModGetModsTable()
if (!isset ($modstable) || defined('_PNINSTALLVER')) {
|