/textpattern/lib/txplib_misc.php
PHP | 6665 lines | 4403 code | 728 blank | 1534 comment | 368 complexity | dae7c70e15316972451dd92cbcf576e7 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1, GPL-2.0
Large files files are truncated, but you can click here to view the full file
- <?php
- /*
- * Textpattern Content Management System
- * http://textpattern.com
- *
- * Copyright (C) 2014 The Textpattern Development Team
- *
- * This file is part of Textpattern.
- *
- * Textpattern is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation, version 2.
- *
- * Textpattern is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Textpattern. If not, see <http://www.gnu.org/licenses/>.
- */
- /**
- * Collection of miscellaneous tools.
- *
- * @package Misc
- */
- /**
- * Strips NULL bytes.
- *
- * @param string|array $in The input value
- * @return mixed
- */
- function deNull($in)
- {
- return is_array($in) ? doArray($in, 'deNull') : strtr($in, array("\0" => ''));
- }
- /**
- * Strips carriage returns and linefeeds.
- *
- * @param string|array $in The input value
- * @return mixed
- */
- function deCRLF($in)
- {
- return is_array($in) ? doArray($in, 'deCRLF') : strtr($in, array("\n" => '', "\r" => ''));
- }
- /**
- * Applies a callback to a given string or an array.
- *
- * @param string|array $in An array or a string to run through the callback function
- * @param callback $function The callback function
- * @return mixed
- * @example
- * echo doArray(array('value1', 'value2'), 'intval');
- */
- function doArray($in, $function)
- {
- if (is_array($in)) {
- return array_map($function, $in);
- }
- if (is_array($function)) {
- return call_user_func($function, $in);
- }
- return $function($in);
- }
- /**
- * Un-quotes a quoted string or an array of values.
- *
- * @param string|array $in The input value
- * @return mixed
- */
- function doStrip($in)
- {
- return is_array($in) ? doArray($in, 'doStrip') : doArray($in, 'stripslashes');
- }
- /**
- * Strips HTML and PHP tags from a string or an array.
- *
- * @param string|array $in The input value
- * @return mixed
- * @example
- * echo doStripTags('<p>Hello world!</p>');
- */
- function doStripTags($in)
- {
- return is_array($in) ? doArray($in, 'doStripTags') : doArray($in, 'strip_tags');
- }
- /**
- * Converts entity escaped brackets back to characters.
- *
- * @param string|array $in The input value
- * @return mixed
- */
- function doDeEnt($in)
- {
- return doArray($in, 'deEntBrackets');
- }
- /**
- * Converts entity escaped brackets back to characters.
- *
- * @param string $in The input value
- * @return string
- */
- function deEntBrackets($in)
- {
- $array = array(
- '<' => '<',
- '<' => '<',
- '<' => '<',
- '>' => '>',
- '>' => '>',
- '>' => '>',
- );
- foreach ($array as $k => $v) {
- $in = preg_replace("/".preg_quote($k)."/i", $v, $in);
- }
- return $in;
- }
- /**
- * Escapes special characters for use in an SQL statement.
- *
- * Always use this function when dealing with user-defined values
- * in SQL statements. If this function is not used to escape
- * user-defined data in a statement, the query is vulnerable to
- * SQL injection attacks.
- *
- * @param string|array $in The input value
- * @return mixed An array of escaped values or a string depending on $in
- * @package DB
- * @example
- * echo safe_field('column', 'table', "color='" . doSlash(gps('color')) . "'");
- */
- function doSlash($in)
- {
- return doArray($in, 'safe_escape');
- }
- /**
- * Escape SQL LIKE pattern's wildcards for use in an SQL statement.
- *
- * @param string|array $in The input value
- * @return mixed An array of escaped values or a string depending on $in
- * @since 4.6.0
- * @package DB
- * @example
- * echo safe_field('column', 'table', "color LIKE '" . doLike(gps('color')) . "'");
- */
- function doLike($in)
- {
- return doArray($in, 'safe_escape_like');
- }
- /**
- * A shell for htmlspecialchars() with $flags defaulting to ENT_QUOTES.
- *
- * @param string $string The string being converted
- * @param int $flags A bitmask of one or more flags. The default is ENT_QUOTES
- * @param string $encoding Defines encoding used in conversion. The default is UTF-8
- * @param bool $double_encode When double_encode is turned off PHP will not encode existing HTML entities, the default is to convert everything
- * @return string
- * @see http://www.php.net/manual/function.htmlspecialchars.php
- * @since 4.5.0
- * @package Filter
- */
- function txpspecialchars($string, $flags = ENT_QUOTES, $encoding = 'UTF-8', $double_encode = true)
- {
- // Ignore ENT_HTML5 and ENT_XHTML for now.
- // ENT_HTML5 and ENT_XHTML are defined in PHP 5.4+ but we consistently encode single quotes as ' in any doctype.
- // global $prefs;
- // static $h5 = null;
- //
- // if (defined(ENT_HTML5)) {
- // if ($h5 === null) {
- // $h5 = ($prefs['doctype'] == 'html5' && txpinterface == 'public');
- // }
- //
- // if ($h5) {
- // $flags = ($flags | ENT_HTML5) & ~ENT_HTML401;
- // }
- // }
- //
- return htmlspecialchars($string, $flags, $encoding, $double_encode);
- }
- /**
- * Converts special characters to HTML entities.
- *
- * @param array|string $in The input value
- * @return mixed The array or string with HTML syntax characters escaped
- * @package Filter
- */
- function doSpecial($in)
- {
- return doArray($in, 'txpspecialchars');
- }
- /**
- * Converts the given value to NULL.
- *
- * @param mixed $a The input value
- * @return null
- * @package Filter
- * @access private
- */
- function _null($a)
- {
- return null;
- }
- /**
- * Converts an array of values to NULL.
- *
- * @param array $in The array
- * @return array
- * @package Filter
- */
- function array_null($in)
- {
- return array_map('_null', $in);
- }
- /**
- * Escapes a page title. Converts <, >, ', " characters to HTML entities.
- *
- * @param string $title The input string
- * @return string The string escaped
- * @package Filter
- */
- function escape_title($title)
- {
- return strtr($title, array(
- '<' => '<',
- '>' => '>',
- "'" => ''',
- '"' => '"',
- ));
- }
- /**
- * Sanitises a string for use in a JavaScript string.
- *
- * This function escapes \, \n, \r, " and ' characters. When
- * you need to pass a string from PHP to JavaScript, use this
- * function to sanitise the value to avoid XSS attempts.
- *
- * @param string $js JavaScript input
- * @return string Escaped JavaScript
- * @since 4.4.0
- * @package Filter
- */
- function escape_js($js)
- {
- return addcslashes($js, "\\\'\"\n\r");
- }
- /**
- * A shell for htmlspecialchars() with $flags defaulting to ENT_QUOTES.
- *
- * @param string $str The input string
- * @return string
- * @deprecated in 4.2.0
- * @see txpspecialchars()
- * @package Filter
- */
- function escape_output($str)
- {
- trigger_error(gTxt('deprecated_function_with', array('{name}' => __FUNCTION__, '{with}' => 'txpspecialchars')), E_USER_NOTICE);
- return txpspecialchars($str);
- }
- /**
- * Replaces < and > characters with entities.
- *
- * @param string $str The input string
- * @return string
- * @deprecated in 4.2.0
- * @see txpspecialchars()
- * @package Filter
- */
- function escape_tags($str)
- {
- trigger_error(gTxt('deprecated_function', array('{name}' => __FUNCTION__)), E_USER_NOTICE);
- return strtr($str, array(
- '<' => '<',
- '>' => '>',
- ));
- }
- /**
- * Escapes CDATA section for an XML document.
- *
- * @param string $str The string
- * @return string XML representation wrapped in CDATA tags
- * @package XML
- */
- function escape_cdata($str)
- {
- return '<![CDATA['.str_replace(']]>', ']]]><![CDATA[]>', $str).']]>';
- }
- /**
- * Returns a localisation string.
- *
- * @param string $var String name
- * @param array $atts Replacement pairs
- * @param string $escape Convert special characters to HTML entities. Either "html" or ""
- * @return string A localisation string
- * @package L10n
- */
- function gTxt($var, $atts = array(), $escape = 'html')
- {
- global $textarray;
- if (!is_array($atts)) {
- $atts = array();
- }
- if ($escape == 'html') {
- foreach ($atts as $key => $value) {
- $atts[$key] = txpspecialchars($value);
- }
- }
- $v = strtolower($var);
- if (isset($textarray[$v])) {
- $out = $textarray[$v];
- if ($out !== '') {
- return strtr($out, $atts);
- }
- }
- if ($atts) {
- return $var.': '.join(', ', $atts);
- }
- return $var;
- }
- /**
- * Loads client-side localisation scripts.
- *
- * This function passes localisation strings from the database
- * to JavaScript.
- *
- * Only works on the admin-side pages.
- *
- * @param string|array $var Scalar or array of string keys
- * @param array $atts Array or array of arrays of variable substitution pairs
- * @since 4.5.0
- * @package L10n
- * @example
- * gTxtScript(array('string1', 'string2', 'string3'));
- */
- function gTxtScript($var, $atts = array())
- {
- global $textarray_script;
- if (!is_array($textarray_script)) {
- $textarray_script = array();
- }
- $data = is_array($var) ? array_map('gTxt', $var, $atts) : (array) gTxt($var, $atts);
- $textarray_script = $textarray_script + array_combine((array) $var, $data);
- }
- /**
- * Returns given timestamp in a format of 01 Jan 2001 15:19:16.
- *
- * @param int $timestamp The UNIX timestamp
- * @return string A formatted date
- * @access private
- * @see safe_stftime()
- * @package DateTime
- * @example
- * echo gTime();
- */
- function gTime($timestamp = 0)
- {
- return safe_strftime('%d %b %Y %X', $timestamp);
- }
- /**
- * Cretes a dumpfile from a backtrace and outputs given parameters.
- *
- * @package Debug
- */
- function dmp()
- {
- static $f = false;
- if (defined('txpdmpfile')) {
- global $prefs;
- if (!$f) {
- $f = fopen($prefs['tempdir'].'/'.txpdmpfile, 'a');
- }
- $stack = get_caller();
- fwrite($f, "\n[".$stack[0].t.safe_strftime('iso8601')."]\n");
- }
- $a = func_get_args();
- if (!$f) {
- echo "<pre dir=\"auto\">".n;
- }
- foreach ($a as $thing) {
- $out = is_scalar($thing) ? strval($thing) : var_export($thing, true);
- if ($f) {
- fwrite($f, $out.n);
- } else {
- echo txpspecialchars($out).n;
- }
- }
- if (!$f) {
- echo "</pre>".n;
- }
- }
- /**
- * Gets the given language's strings from the database.
- *
- * This function gets the given language from the database
- * and returns the strings as an array.
- *
- * If no $events is specified, only appropriate strings for the
- * current context are returned. If 'txpinterface' constant equals 'admin' all
- * strings are returned. Otherwise, only strings from events 'common' and 'public'.
- *
- * If $events is FALSE, returns all strings.
- *
- * @param string $lang The language code
- * @param array|string|bool $events An array of loaded events
- * @return array
- * @package L10n
- * @see load_lang_event()
- * @example
- * print_r(
- * load_lang('en-gb', false)
- * );
- */
- function load_lang($lang, $events = null)
- {
- if ($events === null && txpinterface != 'admin') {
- $events = array('public', 'common');
- }
- $where = '';
- if ($events) {
- $where .= ' and event in('.join(',', quote_list((array) $events)).')';
- }
- foreach (array($lang, 'en-gb') as $lang_code) {
- $rs = safe_rows('name, data', 'txp_lang', "lang='".doSlash($lang_code)."'".$where);
- if (!empty($rs)) {
- break;
- }
- }
- $out = array();
- if (!empty($rs)) {
- foreach ($rs as $a) {
- if (!empty($a['name'])) {
- $out[$a['name']] = $a['data'];
- }
- }
- }
- return $out;
- }
- /**
- * Loads date definitions from a localisation file.
- *
- * @param string $lang The language
- * @package L10n
- * @deprecated in 4.6.0
- */
- function load_lang_dates($lang)
- {
- $filename = is_file(txpath.'/lang/'.$lang.'_dates.txt')?
- txpath.'/lang/'.$lang.'_dates.txt':
- txpath.'/lang/en-gb_dates.txt';
- $file = @file(txpath.'/lang/'.$lang.'_dates.txt', 'r');
- if (is_array($file)) {
- foreach ($file as $line) {
- if ($line[0] == '#' || strlen($line) < 2) {
- continue;
- }
- list($name, $val) = explode('=>', $line, 2);
- $out[trim($name)] = trim($val);
- }
- return $out;
- }
- return false;
- }
- /**
- * Gets language strings for the given event.
- *
- * If no $lang is specified, the strings are loaded
- * from the currently active language.
- *
- * @param string $event The event to get, e.g. "common", "admin", "public"
- * @param string $lang The language code
- * @return array|string Array of string on success, or an empty string when no strings were found
- * @package L10n
- * @see load_lang()
- * @example
- * print_r(
- * load_lang_event('common')
- * );
- */
- function load_lang_event($event, $lang = LANG)
- {
- $installed = (false !== safe_field('name', 'txp_lang',"lang='".doSlash($lang)."' limit 1"));
- $lang_code = ($installed) ? $lang : 'en-gb';
- $rs = safe_rows_start('name, data', 'txp_lang', "lang='".doSlash($lang_code)."' AND event='".doSlash($event)."'");
- $out = array();
- if ($rs && !empty($rs)) {
- while ($a = nextRow($rs)) {
- $out[$a['name']] = $a['data'];
- }
- }
- return ($out) ? $out : '';
- }
- /**
- * Requires privileges from a user.
- *
- * @deprecated in 4.3.0
- * @see require_privs()
- * @package User
- */
- function check_privs()
- {
- trigger_error(gTxt('deprecated_function_with', array('{name}' => __FUNCTION__, '{with}' => 'require_privs')), E_USER_NOTICE);
- global $txp_user;
- $privs = safe_field("privs", "txp_users", "name='".doSlash($txp_user)."'");
- $args = func_get_args();
- if (!in_array($privs,$args)) {
- exit(pageTop('Restricted').'<p style="margin-top:3em;text-align:center">'.
- gTxt('restricted_area').'</p>');
- }
- }
- /**
- * Grants privileges to user-groups.
- *
- * This function will not let you to override existing privs.
- *
- * @param string $res The resource
- * @param string $perm List of user-groups, e.g. '1,2,3'
- * @package User
- * @example
- * add_privs('my_admin_side_panel_event', '1,2,3,4,5');
- */
- function add_privs($res, $perm = '1')
- {
- global $txp_permissions;
- if (!isset($txp_permissions[$res])) {
- $perm = join(',', do_list($perm));
- $txp_permissions[$res] = $perm;
- }
- }
- /**
- * Checks if a user has privileges to the given resource.
- *
- * @param string $res The resource
- * @param string $user The user. If no user name is supplied, assume the current logged in user
- * @return bool
- * @package User
- * @example
- * add_privs('my_privilege_resource', '1,2,3');
- * if (has_privs('my_privilege_resource', 'username'))
- * {
- * echo "'username' has privileges to 'my_privilege_resource'.";
- * }
- */
- function has_privs($res, $user = '')
- {
- global $txp_user, $txp_permissions;
- static $privs;
- $user = (string) $user;
- if ($user === '') {
- $user = (string) $txp_user;
- }
- if ($user !== '') {
- if (!isset($privs[$user])) {
- $privs[$user] = safe_field("privs", "txp_users", "name = '".doSlash($user)."'");
- }
- if (isset($txp_permissions[$res]) && $privs[$user] && $txp_permissions[$res]) {
- return in_list($privs[$user], $txp_permissions[$res]);
- }
- }
- return false;
- }
- /**
- * Require privileges from a user to the given resource.
- *
- * Terminates the script if user doesn't have required privileges.
- *
- * @param string|null $res The resource, or NULL
- * @param string $user The user. If no user name is supplied, assume the current logged in user
- * @package User
- * @example
- * require_privs('article.edit');
- */
- function require_privs($res = null, $user = '')
- {
- if ($res === null || !has_privs($res, $user)) {
- pagetop(gTxt('restricted_area'));
- echo graf(gTxt('restricted_area'), array('class' => 'restricted-area'));
- end_page();
- exit;
- }
- }
- /**
- * Gets a list of users having access to a resource.
- *
- * @param string $res The resource, e.g. 'article.edit.published'
- * @return array A list of usernames
- * @since 4.5.0
- * @package User
- */
- function the_privileged($res)
- {
- global $txp_permissions;
- if (isset($txp_permissions[$res])) {
- return safe_column('name', 'txp_users', "FIND_IN_SET(privs, '{$txp_permissions[$res]}') order by name asc");
- } else {
- return array();
- }
- }
- /**
- * Gets a list of user groups.
- *
- * @return array
- * @package User
- * @example
- * print_r(
- * get_groups()
- * );
- */
- function get_groups()
- {
- global $txp_groups;
- return doArray($txp_groups, 'gTxt');
- }
- /**
- * Gets the dimensions of an image for a HTML <img> tag.
- *
- * @param string $name The filename
- * @return string|bool height="100" width="40", or FALSE on failure
- * @package Image
- * @example
- * if ($size = sizeImage('/path/to/image.png'))
- * {
- * echo "<img src='image.png' {$size} />";
- * }
- */
- function sizeImage($name)
- {
- $size = @getimagesize($name);
- return is_array($size) ? $size[3] : false;
- }
- /**
- * Lists image types that can be safely uploaded.
- *
- * This function returns different results
- * based on the logged in user's privileges.
- *
- * @param int $type If set, validates the given value
- * @return mixed
- * @package Image
- * @since 4.6.0
- * @example
- * list($width, $height, $extension) = getimagesize('image');
- * if ($type = get_safe_image_types($extension))
- * {
- * echo "Valid image of {$type}.";
- * }
- */
- function get_safe_image_types($type = null)
- {
- if (!has_privs('image.create.trusted')) {
- $extensions = array(0, '.gif', '.jpg', '.png');
- } else {
- $extensions = array(0, '.gif', '.jpg', '.png', '.swf', 0, 0, 0, 0, 0, 0, 0, 0, '.swf');
- }
- if (func_num_args() > 0) {
- return !empty($extensions[$type]) ? $extensions[$type] : false;
- }
- return $extensions;
- }
- /**
- * Checks if GD supports the given image type.
- *
- * @param string $image_type Either '.gif', '.png', '.jpg'
- * @return bool TRUE if the type is supported
- * @package Image
- */
- function check_gd($image_type)
- {
- if (!function_exists('gd_info')) {
- return false;
- }
- $gd_info = gd_info();
- switch ($image_type) {
- case '.gif' :
- return ($gd_info['GIF Create Support'] == true);
- break;
- case '.png' :
- return ($gd_info['PNG Support'] == true);
- break;
- case '.jpg' :
- return (!empty($gd_info['JPEG Support']) || !empty($gd_info['JPG Support']));
- break;
- }
- return false;
- }
- /**
- * Uploads an image.
- *
- * This function can be used to upload a new image or replace an existing one.
- * If $id is specified, the image will be replaced. If $uploaded is set
- * FALSE, $file can take a local file instead of HTTP file upload variable.
- *
- * All uploaded files will included on the Images panel.
- *
- * @param array $file HTTP file upload variables
- * @param array $meta Image meta data, allowed keys 'caption', 'alt', 'category'
- * @param int $id Existing image's ID
- * @param bool $uploaded If FALSE, $file takes a filename instead of upload vars
- * @return array|string An array of array(message, id) on success, localized error string on error
- * @package Image
- * @example
- * print_r(image_data(
- * $_FILES['myfile'],
- * array(
- * 'caption' => '',
- * 'alt' => '',
- * 'category' => '',
- * )
- * ));
- */
- function image_data($file, $meta = array(), $id = 0, $uploaded = true)
- {
- global $txp_user, $event;
- $name = $file['name'];
- $error = $file['error'];
- $file = $file['tmp_name'];
- if ($uploaded) {
- $file = get_uploaded_file($file);
- if (get_pref('file_max_upload_size') < filesize($file)) {
- unlink($file);
- return upload_get_errormsg(UPLOAD_ERR_FORM_SIZE);
- }
- }
- if (empty($file)) {
- return upload_get_errormsg(UPLOAD_ERR_NO_FILE);
- }
- list($w, $h, $extension) = getimagesize($file);
- $ext = get_safe_image_types($extension);
- if (!$ext) {
- return gTxt('only_graphic_files_allowed');
- }
- $name = substr($name, 0, strrpos($name, '.')).$ext;
- $safename = doSlash($name);
- $meta = lAtts(array(
- 'category' => '',
- 'caption' => '',
- 'alt' => ''
- ), (array) $meta, false);
- extract(doSlash($meta));
- $q = "
- name = '$safename',
- ext = '$ext',
- w = $w,
- h = $h,
- alt = '$alt',
- caption = '$caption',
- category = '$category',
- date = now(),
- author = '".doSlash($txp_user)."'
- ";
- if (empty($id)) {
- $rs = safe_insert('txp_image', $q);
- if ($rs) {
- $id = $GLOBALS['ID'] = $rs;
- }
- $update = false;
- } else {
- $id = assert_int($id);
- $rs = safe_update('txp_image', $q, "id = $id");
- $update = true;
- }
- if (!$rs) {
- return gTxt('image_save_error');
- }
- $newpath = IMPATH.$id.$ext;
- if (shift_uploaded_file($file, $newpath) == false) {
- if (!$update) {
- safe_delete('txp_image', "id = $id");
- }
- unset($GLOBALS['ID']);
- return $newpath.sp.gTxt('upload_dir_perms');
- }
- @chmod($newpath, 0644);
- // GD is supported
- if (check_gd($ext)) {
- // Auto-generate a thumbnail using the last settings
- if (get_pref('thumb_w') > 0 || get_pref('thumb_h') > 0) {
- $t = new txp_thumb($id);
- $t->crop = (bool) get_pref('thumb_crop');
- $t->hint = '0';
- $t->width = (int) get_pref('thumb_w');
- $t->height = (int) get_pref('thumb_h');
- $t->write();
- }
- }
- $message = gTxt('image_uploaded', array('{name}' => $name));
- update_lastmod();
- // call post-upload plugins with new image's $id
- callback_event('image_uploaded', $event, false, $id);
- return array($message, $id);
- }
- /**
- * Gets an image as an array.
- *
- * @param string $where SQL where clause
- * @return array|bool An image data, or FALSE on failure
- * @package Image
- * @example
- * if ($image = fileDownloadFetchInfo('id = 1'))
- * {
- * print_r($image);
- * }
- */
- function imageFetchInfo($where)
- {
- $rs = safe_row('*', 'txp_image', $where);
- if ($rs) {
- return image_format_info($rs);
- }
- return false;
- }
- /**
- * Formats image info.
- *
- * This function takes an image data array generated
- * by imageFetchInfo() and formats the contents.
- *
- * @param array $image The image
- * @return array
- * @see imageFetchInfo()
- * @access private
- * @package Image
- */
- function image_format_info($image)
- {
- if (($unix_ts = @strtotime($image['date'])) > 0) {
- $image['date'] = $unix_ts;
- }
- return $image;
- }
- /**
- * Formats link info.
- *
- * @param array $link The link to format
- * @return array Formatted link data
- * @access private
- * @package Link
- */
- function link_format_info($link)
- {
- if (($unix_ts = @strtotime($link['date'])) > 0) {
- $link['date'] = $unix_ts;
- }
- return $link;
- }
- /**
- * Gets a HTTP GET or POST parameter.
- *
- * This function internally handles and normalises MAGIC_QUOTES_GPC,
- * strips CRLF from GET parameters and removes NULL bytes.
- *
- * @param string $thing The parameter to get
- * @return string|array The value of $thing, or an empty string
- * @package Network
- * @example
- * if (gps('sky') == 'blue' && gps('roses') == 'red')
- * {
- * echo 'Roses are red, sky is blue.';
- * }
- */
- function gps($thing)
- {
- $out = '';
- if (isset($_GET[$thing])) {
- if (MAGIC_QUOTES_GPC) {
- $out = doStrip($_GET[$thing]);
- } else {
- $out = $_GET[$thing];
- }
- $out = doArray($out, 'deCRLF');
- } elseif (isset($_POST[$thing])) {
- if (MAGIC_QUOTES_GPC) {
- $out = doStrip($_POST[$thing]);
- } else {
- $out = $_POST[$thing];
- }
- }
- $out = doArray($out, 'deNull');
- return $out;
- }
- /**
- * Gets an array of HTTP GET or POST parameters.
- *
- * @param array $array The parameters to extract
- * @return array
- * @package Network
- * @example
- * extract(gpsa(array('sky', 'roses'));
- * if ($sky == 'blue' && $roses == 'red')
- * {
- * echo 'Roses are red, sky is blue.';
- * }
- */
- function gpsa($array)
- {
- if (is_array($array)) {
- $out = array();
- foreach ($array as $a) {
- $out[$a] = gps($a);
- }
- return $out;
- }
- return false;
- }
- /**
- * Gets a HTTP POST parameter.
- *
- * This function internally handles and normalises MAGIC_QUOTES_GPC,
- * and removes NULL bytes.
- *
- * @param string $thing The parameter to get
- * @return string|array The value of $thing, or an empty string
- * @package Network
- * @example
- * if (ps('sky') == 'blue' && ps('roses') == 'red')
- * {
- * echo 'Roses are red, sky is blue.';
- * }
- */
- function ps($thing)
- {
- $out = '';
- if (isset($_POST[$thing])) {
- if (MAGIC_QUOTES_GPC) {
- $out = doStrip($_POST[$thing]);
- } else {
- $out = $_POST[$thing];
- }
- }
- $out = doArray($out, 'deNull');
- return $out;
- }
- /**
- * Gets an array of HTTP POST parameters.
- *
- * @param array $array The parameters to extract
- * @return array
- * @package Network
- * @example
- * extract(psa(array('sky', 'roses'));
- * if ($sky == 'blue' && $roses == 'red')
- * {
- * echo 'Roses are red, sky is blue.';
- * }
- */
- function psa($array)
- {
- foreach ($array as $a) {
- $out[$a] = ps($a);
- }
- return $out;
- }
- /**
- * Gets an array of HTTP POST parameters and strips HTML and PHP tags from values.
- *
- * @param array $array The parameters to extract
- * @return array
- * @package Network
- */
- function psas($array)
- {
- foreach ($array as $a) {
- $out[$a] = doStripTags(ps($a));
- }
- return $out;
- }
- /**
- * Gets all received HTTP POST parameters.
- *
- * @return array
- * @package Network
- */
- function stripPost()
- {
- if (isset($_POST)) {
- if (MAGIC_QUOTES_GPC) {
- return doStrip($_POST);
- } else {
- return $_POST;
- }
- }
- return '';
- }
- /**
- * Gets a variable from $_SERVER global array.
- *
- * @param mixed $thing The variable
- * @return mixed The variable, or an empty string on error
- * @package System
- * @example
- * echo serverSet('HTTP_USER_AGENT');
- */
- function serverSet($thing)
- {
- return (isset($_SERVER[$thing])) ? $_SERVER[$thing] : '';
- }
- /**
- * Gets the client's IP address.
- *
- * This function supports proxies and uses 'X_FORWARDED_FOR'
- * HTTP header if deemed necessary.
- *
- * @return string
- * @package Network
- * @example
- * if ($ip = remote_addr())
- * {
- * echo "Your IP address is: {$ip}.";
- * }
- */
- function remote_addr()
- {
- $ip = serverSet('REMOTE_ADDR');
- if (($ip == '127.0.0.1' || $ip == '::1' || $ip == '::ffff:127.0.0.1' || $ip == serverSet('SERVER_ADDR')) && serverSet('HTTP_X_FORWARDED_FOR')) {
- $ips = explode(', ', serverSet('HTTP_X_FORWARDED_FOR'));
- $ip = $ips[0];
- }
- return $ip;
- }
- /**
- * Gets a variable from HTTP POST or a prefixed cookie.
- *
- * This function gets either a HTTP cookie of the given
- * name prefixed with 'txp_', or a HTTP POST parameter
- * without a prefix.
- *
- * @param string $thing The variable
- * @return array|string The variable or an empty string
- * @package Network
- * @example
- * if ($cs = psc('myVariable'))
- * {
- * echo "'txp_myVariable' cookie or 'myVariable' POST parameter contained: '{$cs}'.";
- * }
- */
- function pcs($thing)
- {
- if (isset($_COOKIE["txp_".$thing])) {
- if (MAGIC_QUOTES_GPC) {
- return doStrip($_COOKIE["txp_".$thing]);
- } else {
- return $_COOKIE["txp_".$thing];
- }
- } elseif (isset($_POST[$thing])) {
- if (MAGIC_QUOTES_GPC) {
- return doStrip($_POST[$thing]);
- } else {
- return $_POST[$thing];
- }
- }
- return '';
- }
- /**
- * Gets a HTTP cookie.
- *
- * This function internally normalises MAGIC_QUOTES_GPC.
- *
- * @param string $thing The cookie
- * @return string The cookie or an empty string
- * @package Network
- * @example
- * if ($cs = cs('myVariable'))
- * {
- * echo "'myVariable' cookie contained: '{$cs}'.";
- * }
- */
- function cs($thing)
- {
- if (isset($_COOKIE[$thing])) {
- if (MAGIC_QUOTES_GPC) {
- return doStrip($_COOKIE[$thing]);
- } else {
- return $_COOKIE[$thing];
- }
- }
- return '';
- }
- /**
- * Converts a boolean to a localised "Yes" or "No" string.
- *
- * @param bool $status The boolean. Ignores type and as such can also take a string or an integer
- * @return string No if FALSE, Yes otherwise
- * @package L10n
- * @example
- * echo yes_no(3 * 3 === 2);
- */
- function yes_no($status)
- {
- return ($status) ? gTxt('yes') : gTxt('no');
- }
- /**
- * Gets UNIX timestamp with microseconds.
- *
- * @return float
- * @package DateTime
- * @example
- * echo getmicrotime();
- */
- function getmicrotime()
- {
- list($usec, $sec) = explode(" ", microtime());
- return ((float) $usec + (float) $sec);
- }
- /**
- * Loads the given plugin or checks if it was loaded.
- *
- * @param string $name The plugin
- * @param bool $force If TRUE loads the plugin even if it's disabled
- * @return bool TRUE if the plugin is loaded
- * @example
- * if (load_plugin('abc_plugin'))
- * {
- * echo "'abc_plugin' is active.";
- * }
- */
- function load_plugin($name, $force = false)
- {
- global $plugins, $plugins_ver, $prefs, $txp_current_plugin;
- if (is_array($plugins) and in_array($name, $plugins)) {
- return true;
- }
- if (!empty($prefs['plugin_cache_dir'])) {
- $dir = rtrim($prefs['plugin_cache_dir'], '/') . '/';
- // In case it's a relative path.
- if (!is_dir($dir)) {
- $dir = rtrim(realpath(txpath.'/'.$dir), '/') . '/';
- }
- if (is_file($dir . $name . '.php')) {
- $plugins[] = $name;
- set_error_handler("pluginErrorHandler");
- if (isset($txp_current_plugin)) {
- $txp_parent_plugin = $txp_current_plugin;
- }
- $txp_current_plugin = $name;
- include($dir . $name . '.php');
- $txp_current_plugin = isset($txp_parent_plugin) ? $txp_parent_plugin : null;
- $plugins_ver[$name] = @$plugin['version'];
- restore_error_handler();
- return true;
- }
- }
- $rs = safe_row("name, code, version", "txp_plugin", ($force ? '' : 'status = 1 AND '). "name='".doSlash($name)."'");
- if ($rs) {
- $plugins[] = $rs['name'];
- $plugins_ver[$rs['name']] = $rs['version'];
- set_error_handler("pluginErrorHandler");
- if (isset($txp_current_plugin)) {
- $txp_parent_plugin = $txp_current_plugin;
- }
- $txp_current_plugin = $rs['name'];
- eval($rs['code']);
- $txp_current_plugin = isset($txp_parent_plugin) ? $txp_parent_plugin : null;
- restore_error_handler();
- return true;
- }
- return false;
- }
- /**
- * Loads a plugin.
- *
- * Identical to load_plugin() except upon failure it issues an E_USER_ERROR.
- *
- * @param string $name The plugin
- * @return bool
- * @see load_plugin()
- */
- function require_plugin($name)
- {
- if (!load_plugin($name)) {
- trigger_error("Unable to include required plugin \"{$name}\"",E_USER_ERROR);
- return false;
- }
- return true;
- }
- /**
- * Loads a plugin.
- *
- * Identical to load_plugin() except upon failure it issues an E_USER_WARNING.
- *
- * @param string $name The plugin
- * @return bool
- * @see load_plugin()
- */
- function include_plugin($name)
- {
- if (!load_plugin($name)) {
- trigger_error("Unable to include plugin \"{$name}\"",E_USER_WARNING);
- return false;
- }
- return true;
- }
- /**
- * Error handler for plugins.
- *
- * @param int $errno
- * @param string $errstr
- * @param string $errfile
- * @param int $errline
- * @access private
- * @package Debug
- */
- function pluginErrorHandler($errno, $errstr, $errfile, $errline)
- {
- global $production_status, $txp_current_plugin;
- $error = array();
- if ($production_status == 'testing') {
- $error = array(
- E_WARNING => 'Warning',
- E_RECOVERABLE_ERROR => 'Catchable fatal error',
- E_USER_ERROR => 'User_Error',
- E_USER_WARNING => 'User_Warning',
- );
- } elseif ($production_status == 'debug') {
- $error = array(
- E_WARNING => 'Warning',
- E_NOTICE => 'Notice',
- E_RECOVERABLE_ERROR => 'Catchable fatal error',
- E_USER_ERROR => 'User_Error',
- E_USER_WARNING => 'User_Warning',
- E_USER_NOTICE => 'User_Notice',
- );
- if (!isset($error[$errno])) {
- $error[$errno] = $errno;
- }
- }
- if (!isset($error[$errno]) || !error_reporting()) {
- return;
- }
- printf('<pre dir="auto">'.gTxt('plugin_load_error').' <b>%s</b> -> <b>%s: %s on line %s</b></pre>',
- $txp_current_plugin, $error[$errno], $errstr, $errline);
- if ($production_status == 'debug') {
- print "\n<pre class=\"backtrace\" dir=\"ltr\"><code>".txpspecialchars(join("\n", get_caller(10)))."</code></pre>";
- }
- }
- /**
- * Error handler for page templates.
- *
- * @param int $errno
- * @param string $errstr
- * @param string $errfile
- * @param int $errline
- * @access private
- * @package Debug
- */
- function tagErrorHandler($errno, $errstr, $errfile, $errline)
- {
- global $production_status, $txp_current_tag, $txp_current_form, $pretext;
- $error = array();
- if ($production_status == 'testing') {
- $error = array(
- E_WARNING => 'Warning',
- E_RECOVERABLE_ERROR => 'Textpattern Catchable fatal error',
- E_USER_ERROR => 'Textpattern Error',
- E_USER_WARNING => 'Textpattern Warning',
- );
- } elseif ($production_status == 'debug') {
- $error = array(
- E_WARNING => 'Warning',
- E_NOTICE => 'Notice',
- E_RECOVERABLE_ERROR => 'Textpattern Catchable fatal error',
- E_USER_ERROR => 'Textpattern Error',
- E_USER_WARNING => 'Textpattern Warning',
- E_USER_NOTICE => 'Textpattern Notice',
- );
- if (!isset($error[$errno])) {
- $error[$errno] = $errno;
- }
- }
- if (!isset($error[$errno]) || !error_reporting()) {
- return;
- }
- if (empty($pretext['page'])) {
- $page = gTxt('none');
- } else {
- $page = $pretext['page'];
- }
- if (!isset($txp_current_form)) {
- $txp_current_form = gTxt('none');
- }
- $locus = gTxt('while_parsing_page_form', array(
- '{page}' => $page,
- '{form}' => $txp_current_form,
- ));
- printf("<pre dir=\"auto\">".gTxt('tag_error').' <b>%s</b> -> <b> %s: %s %s</b></pre>',
- txpspecialchars($txp_current_tag), $error[$errno], $errstr, $locus);
- if ($production_status == 'debug') {
- print "\n<pre class=\"backtrace\" dir=\"ltr\"><code>".txpspecialchars(join("\n", get_caller(10)))."</code></pre>";
- $trace_msg = gTxt('tag_error').' '.$txp_current_tag.' -> '.$error[$errno].': '.$errstr.' '.$locus;
- trace_add($trace_msg);
- }
- }
- /**
- * Error handler for XML feeds.
- *
- * @param int $errno
- * @param string $errstr
- * @param string $errfile
- * @param int $errline
- * @access private
- * @package Debug
- */
- function feedErrorHandler($errno, $errstr, $errfile, $errline)
- {
- global $production_status;
- if ($production_status != 'debug') {
- return;
- }
- return tagErrorHandler($errno, $errstr, $errfile, $errline);
- }
- /**
- * Error handler for admin-side pages.
- *
- * @param int $errno
- * @param string $errstr
- * @param string $errfile
- * @param int $errline
- * @access private
- * @package Debug
- */
- function adminErrorHandler($errno, $errstr, $errfile, $errline)
- {
- global $production_status, $theme, $event, $step;
- $error = array();
- if ($production_status == 'testing') {
- $error = array(
- E_WARNING => 'Warning',
- E_RECOVERABLE_ERROR => 'Catchable fatal error',
- E_USER_ERROR => 'User_Error',
- E_USER_WARNING => 'User_Warning',
- );
- } elseif ($production_status == 'debug') {
- $error = array(
- E_WARNING => 'Warning',
- E_NOTICE => 'Notice',
- E_RECOVERABLE_ERROR => 'Catchable fatal error',
- E_USER_ERROR => 'User_Error',
- E_USER_WARNING => 'User_Warning',
- E_USER_NOTICE => 'User_Notice',
- );
- if (!isset($error[$errno])) {
- $error[$errno] = $errno;
- }
- }
- if (!isset($error[$errno]) || !error_reporting()) {
- return;
- }
- // When even a minimum environment is missing.
- if (!isset($production_status)) {
- echo '<pre dir="auto">'.gTxt('internal_error').' "'.$errstr.'"'.n."in $errfile at line $errline".'</pre>';
- return;
- }
- $backtrace = '';
- if (has_privs('debug.verbose')) {
- $msg = $error[$errno].' "'.$errstr.'"';
- } else {
- $msg = gTxt('internal_error');
- }
- if ($production_status == 'debug' && has_privs('debug.backtrace')) {
- $msg .= n."in $errfile at line $errline";
- $backtrace = join(n, get_caller(5, 1));
- }
- if ($errno == E_ERROR || $errno == E_USER_ERROR) {
- $httpstatus = 500;
- } else {
- $httpstatus = 200;
- }
- $out = "$msg.\n$backtrace";
- if (http_accept_format('html')) {
- if ($backtrace) {
- echo "<pre dir=\"auto\">$msg.</pre>".
- n.'<pre class="backtrace" dir="ltr"><code>'.
- txpspecialchars($backtrace).'</code></pre>';
- } elseif (is_object($theme)) {
- echo $theme->announce(array($out, E_ERROR), true);
- } else {
- echo "<pre dir=\"auto\">$out</pre>";
- }
- } elseif (http_accept_format('js')) {
- if (is_object($theme)) {
- send_script_response($theme->announce_async(array($out, E_ERROR), true));
- } else {
- send_script_response('/* '. $out . '*/');
- }
- } elseif (http_accept_format('xml')) {
- send_xml_response(array(
- 'http-status' => $httpstatus,
- 'internal_error' => "$out",
- ));
- } else {
- txp_die($msg, 500);
- }
- }
- /**
- * Error handler for public-side.
- *
- * @param int $errno
- * @param string $errstr
- * @param string $errfile
- * @param int $errline
- * @access private
- * @package Debug
- */
- function publicErrorHandler($errno, $errstr, $errfile, $errline)
- {
- global $production_status;
- $error = array();
- if ($production_status == 'testing') {
- $error = array(
- E_WARNING => 'Warning',
- E_USER_ERROR => 'Textpattern Error',
- E_USER_WARNING => 'Textpattern Warning',
- );
- } elseif ($production_status == 'debug') {
- $error = array(
- E_WARNING => 'Warning',
- E_NOTICE => 'Notice',
- E_USER_ERROR => 'Textpattern Error',
- E_USER_WARNING => 'Textpattern Warning',
- E_USER_NOTICE => 'Textpattern Notice',
- );
- if (!isset($error[$errno])) {
- $error[$errno] = $errno;
- }
- }
- if (!isset($error[$errno]) || !error_reporting()) {
- return;
- }
- printf ("<pre dir=\"auto\">".gTxt('general_error').' <b>%s: %s on line %s</b></pre>',
- $error[$errno], $errstr, $errline);
- if ($production_status == 'debug') {
- print "\n<pre class=\"backtrace\" dir=\"ltr\"><code>".txpspecialchars(join("\n", get_caller(10)))."</code></pre>";
- }
- }
- /**
- * Loads plugins.
- *
- * @param bool $type If TRUE loads admin-side plugins, otherwise public
- */
- function load_plugins($type = false)
- {
- global $prefs, $plugins, $plugins_ver, $app_mode;
- if (!is_array($plugins)) {
- $plugins = array();
- }
- if (!empty($prefs['plugin_cache_dir'])) {
- $dir = rtrim($prefs['plugin_cache_dir'], '/') . '/';
- // In case it's a relative path.
- if (!is_dir($dir)) {
- $dir = rtrim(realpath(txpath.'/'.$dir), '/') . '/';
- }
- $files = glob($dir.'*.php');
- if ($files) {
- natsort($files);
- foreach ($files as $f) {
- trace_add("[Loading plugin from cache dir '$f']");
- load_plugin(basename($f, '.php'));
- }
- }
- }
- $admin = ($app_mode == 'async' ? '4,5' : '1,3,4,5');
- $where = 'status = 1 AND type IN ('.($type ? $admin : '0,1,5').')';
- $rs = safe_rows("name, code, version", "txp_plugin", $where.' order by load_order asc, name asc');
- if ($rs) {
- $old_error_handler = set_error_handler("pluginErrorHandler");
- foreach ($rs as $a) {
- if (!in_array($a['name'], $plugins)) {
- $plugins[] = $a['name'];
- $plugins_ver[$a['name']] = $a['version'];
- $GLOBALS['txp_current_plugin'] = $a['name'];
- trace_add("[Loading plugin '{$a['name']}' version '{$a['version']}']");
- $eval_ok = eval($a['code']);
- if ($eval_ok === false) {
- echo gTxt('plugin_load_error_above').strong($a['name']).n.br;
- }
- unset($GLOBALS['txp_current_plugin']);
- }
- }
- restore_error_handler();
- }
- }
- /**
- * Attachs a handler to a callback event.
- *
- * @param callback $func The callback function
- * @param string $event The callback event
- * @param string $step The callback step
- * @param bool $pre Before or after. Works only with selected callback events
- * @package Callback
- * @example
- * register_callback('my_callback_function', 'article.updated');
- * function my_callback_function($event)
- * {
- * return "'$event' fired.";
- * }
- */
- function register_callback($func, $event, $step = '', $pre = 0)
- {
- global $plugin_callback;
- $plugin_callback[] = array(
- 'function' => $func,
- 'event' => $event,
- 'step' => $step,
- 'pre' => $pre,
- );
- }
- /**
- * Registers an admin-side extension page.
- *
- * For now this just does the same as register_callback().
- *
- * @param callback $func The callback function
- * @param string $event The callback event
- * @param string $step The callback step
- * @param bool $top The top or the bottom of the page
- * @access private
- * @see register_callback()
- * @package Callback
- */
- function register_page_extension($func, $event, $step = '', $top = 0)
- {
- register_callback($func, $event, $step, $top);
- }
- /**
- * Call an event's callback.
- *
- * This function executes all callback handlers attached to the
- * matched event and step.
- *
- * When this function is called, any event handlers attached with
- * register_callback() to the matching event, step and pre will be called.
- * The handlers, callback functions, will be executed in the same order they
- * were registered.
- *
- * Any extra arguments will be passed to the callback handlers in the same
- * argument position. This allows passing any type of data to the attached
- * handlers. Callback handlers will also receive the event and the step.
- *
- * This function returns a compined value of all values returned by the callback
- * handlers.
- *
- * @param string $event The callback event
- * @param string $step Additional callback step
- * @param bool $pre Allows two callbacks, a prepending and an appending, with same event and step
- * @return mixed The value returned by the attached callback functions, or an empty string
- * @package Callback
- * @see register_callback()
- * @example
- * register_callback('my_callback_function', 'my_custom_event');
- * function my_callback_function($event, $step, $extra)
- * {
- * return "Passed '$extra' on '$event'.";
- * }
- * echo callback_event('my_custom_event', '', 0, 'myExtraValue');
- */
- function callback_event($event, $step = '', $pre = 0)
- {
- global $plugin_callback, $production_status;
- if (!is_array($plugin_callback)) {
- return '';
- }
- // Any payload parameters?
- $argv = func_get_args();
- $argv = (count($argv) > 3) ? array_slice($argv, 3) : array();
- foreach ($plugin_callback as $c) {
- if ($c['event'] == $event && (empty($c['step']) || $c['step'] == $step) && $c['pre'] == $pre) {
- if (is_callable($c['function'])) {
- $return_value = call_user_func_array($c['function'], array('event' => $event, 'step' => $step) + $argv);
- if (isset($out)) {
- if (is_array($return_value) && is_array($out)) {
- $out = array_merge($out, $return_value);
- } elseif (is_bool($return_value) && is_bool($out)) {
- $out = $return_value && $out;
- } else {
- $out .= $return_value;
- }
- } else {
- $out = $return_value;
- }
- } elseif ($production_status == 'debug') {
- trigger_error(gTxt('unknown_callback_function', array('{function}' => callback_tostring($c['function']))), E_USER_WARNING);
- }
- }
- }
- if (isset($out)) {
- return $out;
- }
- return '';
- }
- /**
- * Call an event's callback with two optional byref parameters.
- *
- * @param string $event The callback event
- * @param string $step Optional callback step
- * @param bool $pre Allows two callbacks, a prepending and an appending, with same event and step
- * @param mixed $data Optional arguments for event handlers
- * @param mixed $options Optional arguments for event handlers
- * @return array Collection of return values from event handlers
- * @since 4.5.0
- * @package Callback
- */
- function callback_event_ref($event, $step = '', $pre = 0, &$data = null, &$options = null)
- {
- global $plugin_callback, $production_status;
- if (!is_array($plugin_callback)) {
- return array();
- }
- $return_value = array();
- foreach ($plugin_callback as $c) {
- if ($c['event'] == $event and (empty($c['step']) or $c['step'] == $step) and $c['pre'] == $pre) {
- if (is_callable($c['function'])) {
- // Cannot call event handler via call_user_func() as this would dereference all arguments.
- // Side effect: callback handler *must* be ordinary function, *must not* be class method in PHP <5.4
- // see https://bugs.php.net/bug.php?id=47160
- $return_value[] = $c['function']($event, $step, $data, $options);
- } elseif ($production_status == 'debug') {
- trigger_error(gTxt('unknown_callback_function', array('{function}' => callback_tostring($c['function']))), E_USER_WARNING);
- }
- }
- }
- return $return_value;
- }
- /**
- * Converts a callable to a string presentation.
- *
- * <code>
- * echo callback_tostring(array('class', 'method'));
- * </code>
- *
- * @param callback $callback The callback
- * @return string The $callback as a human-readable string
- * @since 4.5.0
- * @package Callback
- * @deprecated in 4.6.0
- * @see Textpattern_Type_Callable::toString()
- */
- function callback_tostring($callback)
- {
- return Txp::get('Textpattern_Type_Callable', $callback)->toString();
- }
- /**
- * Checks if a callback event has active handlers.
- *
- * @param string $event The callback event
- * @param string $step The callback step
- * @param bool $pre The position
- * @return bool TRUE if the event is active, FALSE otherwise
- * @since 4.6.0
- * @package Callback
- * @example
- * if (has_handler('article_saved'))
- * {
- * echo "There are active handlers for 'article_saved' event.";
- * }
- */
- function has_handler($event, $step = '', $pre = 0)
- {
- return (bool) callback_handlers($event, $step, $pre, false);
- }
- /**
- * Lists handlers attached to an event.
- *
- * @param string $event The callback event
- * @param string $step The callback step
- * @param bool $pre The position
- * @param bool $as_string Return callables in string representation
- * @return array|bool An array of handlers, or FALSE
- * @since 4.6.0
- * @package Callback
- * @example
- * if ($handlers = callback_handlers('article_saved'))
- * {
- * print_r($handlers);
- * }
- */
- function callback_handlers($event, $step = '', $pre = 0, $as_string = true)
- {
- global $plugin_callback;
- $out = array();
- foreach ((array) $plugin_callback as $c) {
- if ($c['event'] == $event && (!$c['step'] || $c['step'] == $step) && $c['pre'] == $pre) {
- if ($as_string) {
- $out[] = callback_tostring($c['function']);
- } else {
- $out[] = $c['function'];
- }
- }
- }
- if ($out) {
- return $out;
- }
- return false;
- }
- /**
- * Registers a new admin-side panel and adds a navigation link to the menu.
- *
- * @param string $area The menu the panel appears in, e.g. "home", "content", "presentation", "admin", "extensions"
- * @param string $panel The panel's event
- * @param st…
Large files files are truncated, but you can click here to view the full file