aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--wikilib.d/PmWiki.Functions10
-rw-r--r--wikilib.d/PmWiki.Links10
-rw-r--r--wikilib.d/PmWiki.MarkupExpressions12
-rw-r--r--wikilib.d/PmWiki.PmWikiPhilosophy14
4 files changed, 23 insertions, 23 deletions
diff --git a/wikilib.d/PmWiki.Functions b/wikilib.d/PmWiki.Functions
index bf1726ed..fa49b446 100644
--- a/wikilib.d/PmWiki.Functions
+++ b/wikilib.d/PmWiki.Functions
@@ -1,9 +1,9 @@
-version=pmwiki-2.3.23 ordered=1 urlencoded=1
+version=pmwiki-2.3.33 ordered=1 urlencoded=1
author=Petko
charset=UTF-8
-csum=Add InsertEditFunction() (+813)
+csum=include MarkupExpressions#ftimeformats (+60)
name=PmWiki.Functions
-rev=202
+rev=203
targets=Cookbook.Functions,PmWiki.CustomMarkup,PmWiki.CustomActions,PmWiki.BasicVariables,PmWiki.LayoutVariables,PmWiki.Forms,PmWiki.SecurityVariables,Cookbook.PccfToPcfOverride,PmWiki.LinkVariables,PmWiki.OtherVariables,PmWiki.EditVariables,PmWiki.UploadVariables,PmWiki.Functions,PmWiki.Variables,PmWiki.Internationalizations,PmWiki.FmtPageName,PmWiki.MakeLink,PmWiki.ConditionalMarkup,PmWiki.Drafts,PmWiki.IncludeOtherPages,PmWiki.UpdatePage,Cookbook.MarkupExpressionSamples,Cookbook.ParseArgs,Category.PmWikiDeveloper,!PmWikiDeveloper
-text=(:Summary: How some of the functions in pmwiki.php work:)%0a(:Audience: admins (advanced) :)%0a%0aThis page describes some of the internal workings of PmWiki by explaining how some of the functions in @@pmwiki.php@@ work. For a more brief list/overview on functions useful to for instance cookbook writers, see Cookbook:Functions. %0a%0aTo use this functions you have to make sure that all relevant internal variables have been initialized correctly. See [[Custom Markup]] and [[(PmWiki:)Custom Actions]] for more information on how these functions are typically called via %25hlt php%25[@Markup()@] or [@$HandleActions[]@].%0a%0a!! [[#PSFT]] PSFT()%0a%0a%25hlt php%25[@PSFT($format, $timestamp=null, $locale=null, $tz=null)@]%0a%0aThe %25hlt php%25@@PSFT()@@ function (''PmWiki String Format Time'', added in 2.3.0) is intended to be a safe replacement for the very widely used PHP functions @@[[https://www.php.net/strftime|strftime()]]@@ and @@[[https://www.php.net/gmstrftime|gmtstrftime()]]@@ which became deprecated in PHP 8.1.%0a%0aUnlike %25hlt php%25@@strftime()@@, @@PSFT()@@ accepts 2 additional arguments @@$locale@@ and @@$tz@@, which allow to set a different language or timezone.%0a%0aPmWiki 2.3.0 uses this function in all cases where it previously used %25hlt php%25@@strftime()@@, including the %25pmhlt%25[@{(ftime)}@] Markup Expression. If your local customizations and recipes use %25hlt php%25@@strftime()@@, you should be able to safely replace all calls to @@strftime()@@ with @@PSFT()@@, without changing the arguments. Any calls to @@gmtstrftime($fmt, $stamp)@@ can be replaced with @@PSFT($fmt, $stamp, null, 'GMT')@@.%0a%0aThe old functions were deprecated by the PHP developers because they behaved inconsistently on different platforms, and were dependent on installed system locales (i.e. a language would only work if the system had its locale installed). The new function uses the PHP class [[https://www.php.net/manual/en/class.intldateformatter.php|IntlDateFormatter]] and should be better. Unfortunately, it is not always enabled by hosting providers. %0a%0aSo depending on your installation, a specific language may be available with %25hlt php%25@@strftime()@@ and/or with @@IntlDateFormatter@@.%0a%0aIn addition, some rarely used shortcut percent-formats [@%25c, %25x, %25X@] also behave inconsistently on different platforms, and the new formatter may show a slightly different output. You can always replace these shortcut formats with the full formats you require.%0a%0aFor these reasons, %25hlt php%25@@PSFT()@@ is currently a compromise, by default reusing @@strftime()@@ for PHP 8.0 or earlier. Updating your calls from @@strftime()@@ shouldn't cause any changes in your outputs.%0a%0aYou can set in @@config.php@@ the variable %25hlt php%25@@$EnableFTimeNew = 1;@@ for @@PSFT()@@ to try using @@IntlDateFormatter@@ before PHP 8.1. If @@IntlDateFormatter@@ is not available, it will show the month and day names in English. Check what works.%0a%0aSince the %25hlt php%25@@strftime()@@ function is deprecated, it is unlikely for it to add new formats. We have added 2 custom formats:%0a* [@%25o@] for the "ordinal suffix" of the date, as "st" in "January 1st". If @@IntlDateFormatter@@ is not available, it will show the suffix in English%0a* [@%25L@] for a human-readable timestamp of the format %25pmhlt%25[@@2022-09-25T11:49:08Z@]%25%25 which will be displayed formatted either as $TimeFmt or in the local time zone of the visitor, see $EnableLocalTimes.%0a%0a>>frame%3c%3c%0aA difference between %25hlt php%25@@strftime($format, $stamp)@@ and @@PSFT($format, $stamp)@@ is how they interpret a false, empty or non-numeric @@$stamp@@ argument.%0a|| class=simpletable%0a||! @@$stamp@@ argument ||! @@strftime($format, $stamp)@@ ||! @@PSFT($format, $stamp)@@ ||%0a|| numeric || the stamp || the stamp ||%0a|| missing or ''null'' || current time || current time ||%0a|| ''false'' || 1970-01-01 || current time ||%0a|| "" (empty string) \\%0aother non-numeric || 1970-01-01 or ''false'' (older PHP versions) \\%0a ''Warning: TypeError'' (PHP 7.4+) || current time ||%0aFor PmWiki, it seemed reasonable to make empty strings and other non-numeric values default to the current time. If your %25hlt php%25@@$stamp@@ variable may be empty or ''false'', and your recipes rely on @@strftime()@@ returning "1970-01-01", you can cast the stamp to integer:%0a%25hlt php%25[@%0a PSFT($format, intval($stamp));%0a@]%0a>>%3c%3c%0a%0a%0a!! [[#pmtoken]] pmtoken()%0a%25hlt php%25[@pmtoken($check = 0, $abort = false)@]%0a%0aThe %25hlt php%25@@pmtoken()@@ function sets or checks a unique session identifier to be used in input forms, with the goal of preventing cross-site request forgeries (CSRF).%0a%0aCalling %25hlt php%25@@pmtoken()@@ or @@pmtoken(0)@@ will create a token if it doesn't exist, store it in the @@$_SESSION@@ array, and return it. It will also set the variables [@$FmtV['$TokenValue']@] which can be used in HTML templates and [@$InputValues['pmtoken']@] to be used in markup [[forms]], although it may be simpler to use %25pmhlt%25[@(:input pmtoken:)@] instead.%0a%0aThe name of the input element, by default 'pmtoken', can be changed by setting for example %25hlt php%25[@$FmtV['$TokenName'] = 'CSRFtoken';@].%0a%0aCalling %25hlt php%25@@pmtoken(1)@@ will check the @@$_POST['pmtoken']@@ value and will return true if it is valid.%0a%0aCalling %25hlt php%25@@pmtoken(2)@@ will check the @@$_GET['pmtoken']@@ value and will return true if it is valid.%0a%0aCalling %25hlt php%25@@pmtoken(1, true)@@ or @@pmtoken(2, true)@@ with a second truthy argument, and the token is invalid, will directly call @@Abort()@@ and exit.%0a%0a%0a!! [[#pmcrypt]] pmcrypt()%0a%25hlt php%25[@pmcrypt($password, $salt = null)@]%0a%0aThe %25hlt php%25@@pmcrypt()@@ function is intended to be a safe replacement for the [[https://www.php.net/crypt|PHP 5.6+ crypt() function]] without providing a $salt, which would raise a notice. If a salt is provided, crypt() is called to check an existing password. If a salt is not provided, [[https://www.php.net/password_hash|password_hash()]] will be called to create a cryptographically strong password hash.%0a%0a!! [[#pmsetcookie]] pmsetcookie()%0a%25hlt php%25[@pmsetcookie($name, $val="", $exp=0, $path="", $dom="", $secure=null, $httponly=null)@]%0a%0aThis function is intended as a replacement for [[https://www.php.net/setcookie|setcookie()]]. It will automatically set the $secure and $httponly arguments if they are not set by the caller function and if $EnableCookieSecure and $EnableCookieHTTPOnly are enabled.%0a%0a!![[#PCCF]] PCCF() %25red%25 Deprecated since PHP 7.2%25%25%0a%25hlt php%25[@PCCF($php_code, $callback_template='default', $callback_arguments = '$m')@] %0a%0aThe %25hlt php%25@@PCCF()@@ function (''PmWiki Create Callback Function'') can be used to create callback functions used with [[https://www.php.net/preg_replace_callback|preg_replace_callback]]. It is required for PHP 5.5, but will also work with earlier PHP versions.%0a%0aThe first argument is the PHP code to be evaluated. %0a%0aThe second argument (optional) is the callback template, a key from the global @@$CallbackFnTemplates@@ array. There are two templates that can be used by recipe authors: %0a* 'default' will pass @@$php_code@@ as a function code%0a* 'return' will wrap @@$php_code@@ like "@@return $php_code;@@" (since PmWiki 2.2.62)%0a%0aThe third argument (optional) is the argument of the callback function. Note that PmWiki uses the '$m' argument to pass the matches of a regular expression search, but your function can use other argument(s).%0a%0a%25hlt php%25@@PCCF()@@ will create an anonymous (lambda) callback function containing the supplied code, and will cache it. On subsequent calls with the same @@$php_code@@, @@PCCF()@@ will return the cached function name.%0a%0aSee the [[https://www.php.net/create_function | PHP create function]].%0a%0a>>font-style=italic%3c%3c%0aPHP 7.2 deprecates %25hlt php%25@@create_function()@@ and future versions will remove it. If you need to migrate older code that used @@PCCF()@@, you can usually write regular functions and pass the function name where you previously passed the result of PCCF(). For example, suppose you had a pattern like this:%0a-> %25hlt php%25@@'/(?%3c=^| )([a-z])/' => PCCF("return strtoupper(\$m[1]);"),@@%0a%0aFor PHP 7.2 compatibility, you can write a callback function:%0a-> %25hlt php%25@@function @@%25green%25my_callback%25hlt php%25@@($m) { return strtoupper($m[1]); }@@%0a%0athen change the pattern to look like this:%0a-> %25hlt php%25@@'/(?%3c=^| )([a-z])/' => '%25green%25my_callback%25%25',@@%0a%0aSee also: the recipe [[(Cookbook:)PccfToPcfOverride]] allows existing recipes to run on PHP 7 without causing deprecated @@create_function()@@ messages.%0a>>%3c%3c%0a%0a!![[#PPRA]] PPRA()%0a%25hlt php%25[@PPRA($array_search_replace, $string)@]%0a%0aThe %25hlt php%25@@PPRA()@@ function (''PmWiki Preg Replace Array'') can be used to perform a regular expression replacement with or without evaluation, for PHP 5.5 compatibility. %0a%0aSince PmWiki 2.2.56, PmWiki uses this function to process the following arrays: $MakePageNamePatterns, $FmtP, $QualifyPatterns, $ROEPatterns, $ROSPatterns, $SaveAttrPatterns, $MakeUploadNamePatterns. Any custom settings should continue to work for PHP 5.4 and earlier, but wikis running on PHP 5.5 may need to make a few changes.%0a%0aThe first argument contains the 'search'=>'replace' pairs, the second is the "haystack" string to be manipulated.%0a%0aThe 'replace' parts of the array can be strings or function names. If the 'replace' part is a callable function name, it will be called with the array of matches as a first argument via %25hlt php%25@@preg_replace_callback()@@. If not a callable function, a simple @@preg_replace()@@ will be performed.%0a%0aPreviously, PmWiki used such constructs:%0a-> %25hlt php%25@@$fmt = preg_replace(array_keys($FmtP), array_values($FmtP), $fmt);@@%0a%0aIt is now possible to use simply this:%0a-> %25hlt php%25@@$fmt = PPRA($FmtP, $fmt);@@%0a%0aNote that since PHP 5.5, the search patterns cannot have an /e evaluation flag. When creating the $array_search_replace array, before PHP 5.5 we could use something like (eg. for $MakePageNamePatterns):%0a-> %25hlt php%25@@'/(?%3c=^| )([a-z])/e' => "strtoupper('$1')",@@%0a%0aSince PHP 5.5, we should use this (will also work in PHP 5.4 and earlier):%0a-> %25hlt php%25@@'/(?%3c=^| )([a-z])/' => PCCF("return strtoupper(\$m[1]);"),@@%0a%0aNote that the @@/e@@ flag should be now omitted, instead of @@'$0', '$1', '$2',@@ we should use @@$m[0], $m[1], $m[2],@@ etc. in the replacement code, and there is no need to call @@PSS()@@ in the replacement code, as backslashes are not automatically added.%0a%0a>>font-style=italic%3c%3c%0aFor PHP 7.2 and newer, instead of using %25hlt php%25@@PCCF()@@ to create anonymous functions, we add a real function in our add-on, and then pass the function name as the pattern replacement (see example at [[#PCCF|PCCF]], which will also work on PHP 4 and 5):%0a-> %25hlt php%25@@'/(?%3c=^| )([a-z])/' => '%25green%25my_callback%25%25',@@%0a>>%3c%3c%0a%0a!![[#PPRE]] PPRE() %25red%25 Deprecated since PHP 7.2%25%25%0a%25hlt php%25[@PPRE($search_pattern, $replacement_code, $string)@]%0a%0aThe %25hlt php%25@@PPRE()@@ function (''PmWiki Preg Replace Evaluate'') can be used to perform a regular expression replacement with evaluation.%0a%0aSince PHP 5.5, the %25hlt php%25@@preg_replace()@@ function has deprecated the /e evaluation flag, and displays warnings when the flag is used. The @@PPRE()@@ function automatically creates a callback function with the replacement code and calls it.%0a%0aBefore PHP 5.5, it was possible to use such calls:%0a-> %25hlt php%25@@$fmt = preg_replace('/\\$([A-Z]\\w*Fmt)\\b/e','$GLOBALS["$1"]',$fmt);@@%0a%0aSince PHP 5.5, it is possible to replace the previous snippet with the following (also works before PHP 5.5):%0a-> %25hlt php%25@@$fmt = PPRE('@@%25green%25/\\$([A-Z]\\w*Fmt)\\b/%25hlt php%25@@','$GLOBALS[$m[1]]',$fmt);@@%0a%0aNote that the @@/e@@ flag should be now omitted, instead of @@'$0', '$1', '$2',@@ we should use @@$m[0], $m[1], $m[2],@@ etc. in the replacement code, and there is no need to call @@PSS()@@ in the replacement code, as backslashes are not automatically added.%0a%0a>>font-style=italic%3c%3c%0aFor PHP 7.2 and newer, calling this function will raise "deprecated" notices. You need to rewrite your code to use [[https://www.php.net/preg_replace_callback|preg_replace_callback]], by moving the code into real functions:%0a%0a-> %25hlt php%25@@$fmt = preg_replace_callback('@@%25green%25/\\$([A-Z]\\w*Fmt)\\b/%25hlt php%25@@', 'my_global_var_callback',$fmt);@@%0a-> %25hlt php%25@@function my_global_var_callback($m) { return $GLOBALS[$m[1]]; }@@%0a%0ainstead of using %25hlt php%25@@PCCF()@@ to create anonymous functions, we add a real function in our add-on, and then pass the function name as the pattern replacement (see example at [[#PCCF|PCCF]], which will also work on PHP 4 and 5):%0a=> %25hlt php%25@@'/(?%3c=^| )([a-z])/' => '%25green%25my_callback%25%25',@@%0a>>%3c%3c%0a%0a(:if false:)(:comment Needs review and may change:)%0a!![[#PRCB]] PRCB()%0a%25hlt php%25[@PRCB($pat, $repl, $subj, $vars=null, $limit=-1, &$count=null, $flags=0)@]%0a%0aThe %25hlt php%25@@PRCB()@@ function (''PmWiki Regex Replace Callback'') makes it simple to pass variables to a named callback function with [[https://php.net/preg_replace_callback|preg_replace_callback()]].%0a%0aIf you need to use preg_replace_callback() and pass some variables to the callback function, you can do something like:%0a%0a%25hlt php%25[@$result = PRCB($patern, 'my_callback', $subject, $pagename);@]%0a%0aThen your function will be called this way: %25hlt php%25[@my_callback($matches, $pagename);@]. You can pass multiple variables with an array.%0a%0aThe function can also be used without passing variables, just shorter than @@preg_replace_callback()@@:%0a%0a%25hlt php%25[@$result = PRCB($patern, 'my_callback', $subject);@]%0a%0a(:ifend:)%0a%0a!![[#Qualify]] Qualify()%0a%25hlt php%25[@Qualify($pagename, $text)@]%0a%0a%25hlt php%25@@Qualify()@@ applies $QualifyPatterns to convert relative links and references into absolute equivalents.%0aThis function is called by usual wiki markups that include text from other pages.%0aIt will rewrite links like %25pmhlt%25[@[[Page]]@] into [@[[Group/Page]]@], and page (text) variables like [@{$Title}@] into [@{Group.Page$Title}@]%0aso that they work the same way in the source page and in the including page.%0aSee also $QualifyPatterns and %25pmhlt%25@@[[({$Name}#)RetrieveAuthSection]]()@@.%0a%0a%0a!![[#PHSC]] PHSC()%0a%25hlt php%25[@PHSC($string_or_array, $flags=ENT_COMPAT, $encoding=null, $double_encode=true)@]%0a%0aThe %25hlt php%25@@PHSC()@@ function (''PmWiki HTML Special Characters'') is a replacement for the PHP function [[https://www.php.net/htmlspecialchars|htmlspecialchars]]. %0a%0aThe %25hlt php%25@@htmlspecialchars()@@ function was modified since PHP 5.4 in two ways: it now requires a valid string for the supplied encoding, and it changes the default encoding to UTF-8. This can cause sections of the page to become blank/empty on many sites using the ISO-8859-1 encoding without having set the third argument ($encoding) when calling @@htmlspecialchars()@@.%0a%0aThe %25hlt php%25@@PHSC()@@ function calls @@htmlspecialchars()@@ with an 8-bit encoding as third argument, whatever the encoding of the wiki (unless you supply an encoding). This way the string never contains invalid characters.%0a%0aIt should be safe for recipe developers to replace all calls to %25hlt php%25@@htmlspecialchars()@@ with calls to @@PHSC()@@. Only the first argument is required when calling @@PHSC()@@, although authors may wish to call @@PHSC($string_or_array, ENT_QUOTES)@@.%0a%0aUnlike %25hlt php%25@@htmlspecialchars()@@, the @@PHSC()@@ function can process arrays recursively (only the values are converted, not the keys of the array).%0a%0a!![[#PSS]] PSS()%0a%25hlt php%25[@PSS($string)@]%0a%0aThe %25hlt php%25@@PSS()@@ function (''PmWiki Strip Slashes'') removes the backslashes that are automatically inserted in front of quotation marks by the /e option of PHP's preg_replace function. @@PSS()@@ is%0amost commonly used in replacement arguments to @@Markup()@@, when the pattern specifies /e and one or more of the parenthesized subpatterns could contain a quote or backslash. %0a("PSS" stands for "PmWiki Strip Slashes".)%0a->From PM: PmWiki expects %25hlt php%25@@PSS()@@ to always occur inside of double-quoted strings and to contain single quoted strings internally. The reason for this is that we don't want the @@$1@@ or @@$2@@ to accidentally contain characters that would then be interpreted inside of the double-quoted string when the PSS is evaluated.%0a-->%25hlt php%25@@Markup('foo', 'inline', '/(something)/e', 'Foo(PSS("$1"))'); # wrong@@%0a-->%25hlt php%25@@Markup('foo', 'inline', '/(something)/e', "Foo(PSS('$1'))"); # right@@%0a%0a%25note%25 Note, the extra slashes are only added by %25hlt php%25@@preg_replace()@@ with an @@/e@@ modifier. The markup definitions with @@Markup_e()@@ do NOT need to use @@PSS()@@ in the replacement strings. The new-type markup definitions with @@Markup()@@ and a simple function name as a replacement do NOT need to use @@PSS()@@ inside the replacement function. If you migrate old markup rules to the new format, delete the @@PSS()@@ calls.%0a%0a!!! Example %25block notoc%25%0aThis is a fictitious example where %25hlt php%25@@PSS()@@ should be used.%0aLet us assume that you wish to define a directive %25pmhlt%25[@(:example:)@]%0asuch that %25pmhlt%25[@(:example "A horse":)@] results in the HTML%0a-> %25hlt html%25[@%3cdiv>"A horse"%3c/div>@].%0aHere is how the markup rule can be created:%0a-> %25hlt php%25[@%0aMarkup('example', 'directives',%0a '/\\(:example\\s(.*?):\\)/e',%0a "Keep('%3cdiv>'.PSS('$1').'%3c/div>')");%0a@]%0aWe need to use %25hlt php%25@@PSS()@@ around the '@@$1@@' because the matched text could contain quotation marks, and the @@/e@@ will add backslashes in front of them.%0a%0a!![[#stripmagic]] stripmagic()%0a%25hlt php%25[@stripmagic($string)@]%0a%0aThis function should be used when processing the contents of %25hlt php%25[@$_POST@] or [@$_GET@] variables when they could contain quotes or backslashes. It verifies [@get_magic_quotes()@], if true, strips the automatically inserted escapes from the string.%0a%0aThe function can process arrays recursively (only the values are processed).%0a%0a!![[#FmtPageName]] FmtPageName()%0a%0a%25hlt php%25[@FmtPageName($fmt, $pagename)@]%0a%0a[[#FmtPageName-desc]]Returns %25hlt php%25[@$fmt@], with @@$variable@@ and [=$[internationalisation]=] substitutions performed, under the assumption that the current page is [@pagename@]. See [[PmWiki.Variables]] for an (incomplete) list of available variables, [[PmWiki.Internationalizations]] for internationalisation. Security: not to be run on user-supplied data.%0a%0aThis is one of the major functions in PmWiki, see [[PmWiki.FmtPageName]] for%0alots of details.%0a%0a%0a!![[#Markup]] Markup()%0a%25hlt php%25[@Markup($name, $when, $pattern, $replace)@]%0a%0a[[#Markup-desc]]Adds a new markup to the conversion table. Described in greater detail at [[PmWiki.CustomMarkup]].%0a%0aThis function is used to insert translation rules into the PmWiki's translation engine. The arguments to %25hlt php%25[@Markup()@] are all strings, where:%0a%0a:%25hlt php%25[@$name@]: The string names the rule that is inserted. If a rule of the same name already exists, then this rule is ignored.%0a:%25hlt php%25[@$when@]: This string is used to control ''when'' a rule is to be applied relative to other rules. A specification of "[@%3cxyz@]" says to apply this rule prior to the rule named "xyz", while "[@>xyz@]" says to apply this rule after the rule "xyz". See [[(PmWiki:)CustomMarkup]] for more details on the order of rules.%0a:%25hlt php%25[@$pattern@]: This string is a [[regular expression -> https://www.php.net/preg_replace]] that is used by the translation engine to look for occurrences of this rule in the markup source.%0a:%25hlt php%25[@$replace@]: This string will replace the matched text when a match occurs, or the function name that will return the replacement text.%0a%0aAlso see: [[PmWiki.CustomMarkup]] and [[Cookbook:Functions#Markup]]%0a%0a!![[#MarkupToHTML]] MarkupToHTML()%0a%0a%25hlt php%25[@MarkupToHTML($pagename, $str)@]%0a%0a[[#MarkupToHTML-desc]] Converts the string %25hlt php%25[@$str@] containing PmWiki markup into the corresponding HTML code, assuming the current page is [@$pagename@].%0a%25hlt php%25@@MarkupToHTML()@@ replaces @@\n\n@@ sequences by @@%3c:vspace>@@ first thing when text is passed to it. Subsequently @@%3c:vspace>@@ is processed by the markup rules:%0a-> '@@!vspace@@' removes @@%3c:vspace>@@ after headings.%0a-> '@@%3cvspace>%3cp>@@' replaces @@%3c:vspace>%3cp>@@ with @@%3cp class='vspace'>@@%0a-> '@@%3cvspace>@@' replaces %3c:vspace> with @@%3cdiv class='vspace'>@@%0a-> and finally%0a-> '@@^%3c:@@' removes any remaining @@%3c:vspace>@@, mostly from restored [=[=]=escaped text=].%0a%0aAlso see: [[Cookbook:Functions#MarkupToHTML]]%0a%0a!![[#mkdirp]] mkdirp()%0a%25hlt php%25[@mkdirp($dir)@]%0a%0aThe function %25hlt php%25[@mkdirp($dir)@] creates a directory, [@$dir@], if it doesn't already exist, including any parent directories that might be needed. For each directory created, it checks that the permissions on the directory are sufficient to allow PmWiki scripts to read and write files in that directory. This includes checking for restrictions imposed by PHP's safe_mode setting. If [@mkdirp()@] is unable to successfully create a read/write directory, [@mkdirp()@] aborts with an error message telling the administrator the steps to take to either create @@$dir@@ manually or give PmWiki sufficient permissions to be able to do it.%0a%0a!![[#Lock]] Lock()%0a%25hlt php%25[@Lock(0)@]%0a%0aThis function is used to make sure only one instance of PmWiki is running when files are being written. It does not "lock pages" for editing.%0a%0aFrom a recipe, use:%0a* %25hlt php%25[@Lock(2);@] to acquire an ''exclusive'' lock, so that no other PHP processes can modify files. This can be used when your function is writing files on the server.%0a* %25hlt php%25[@Lock(1);@] to acquire a ''shared'' lock. This may be used when your function is reading files from the server, in case another process is writing them at the same time.%0a* %25hlt php%25[@Lock(0);@] to ''release'' a previous exclusive or shared lock. Use this immediately after your function finishes reading or writing the files.%0a%0aIf you don't release an acquired lock, it should be automatically released at the end of the processing.%0a%0a%0a!![[#MakeLink]] MakeLink()%0a%25hlt php%25[@MakeLink($pagename, $target, $txt, $suffix, $fmt)@]%0a%0aThe function %25hlt php%25[@MakeLink($pagename, $target, $txt, $suffix, $fmt)@] returns an html-formatted anchor link. Its arguments are as follows:%0a $pagename is the source page%0a $target is where the link should go%0a $txt is the value to use for '$LinkText' in the output %0a $suffix is any suffix string to be added to $txt%0a $fmt is a format string to use%0a%0aIf $txt is NULL or not specified, then it is automatically computed from $target.%0a%0aIf $fmt is NULL or not specified, then MakeLink uses the default%0aformat as specified by the type of link. For page links this%0ameans the $LinkPageExistsFmt and $LinkPageCreateFmt variables,%0afor intermap-style links it comes from either the $IMapLinkFmt%0aarray or from $UrlLinkFmt. Inside of the formatting strings,%0a$LinkUrl is replaced by the resolved url for the link, $LinkText%0ais replaced with the appropriate text, and $LinkAlt is replaced%0aby any "title" (alternate text) information associated with the%0alink.%0a%0aAlso see: [[PmWiki:MakeLink]] and [[Cookbook:Functions#MakeLink]]%0a%0a!![[#MakeUploadName]] MakeUploadName()%0a%25hlt php%25@@MakeUploadName($pagename, $x)@@%0a%0a%25hlt php%25@@MakeUploadName()@@ simply takes a string @@$x@@ (representing an attachment's%0aname) and converts it to a valid name by removing any unwanted characters.%0aIt also requires the name to begin and end with an alphanumeric character,%0aand as of 2.0.beta28 it forces any file extensions to lowercase.%0aThis function is defined in @@scripts/upload.php@@ and only used when uploads%0aare enabled.%0a%0a!![[#DownloadUrl]] DownloadUrl()%0a%25hlt php%25@@DownloadUrl($pagename, $path)@@%0a%0aThis function returns the public URL of an attached file. The arguments are as follow:%0a* $pagename - the currently processed page%0a* %25hlt php%25@@$path@@ - the file path, as in @@file.ext@@ or @@OtherPage/file.ext@@ or @@Group/OtherPage/file.ext@@%0a%0aIf the file doesn't exist, the function returns false. The global variable %25hlt php%25@@$FmtV['$LinkUpload']@@ contains the URL to the upload form, for a file with such a name to be attached. The global variable %25hlt php%25@@$FmtV['$LinkDownload']@@ contains the URL to the file, as if it were uploaded to the wiki.%0a%0aThe function calls [[#MakeUploadName|%25hlt php%25@@MakeUploadName()@@]] on the @@$path@@ argument so you don't need to do it before calling it.%0a%0aThe returned URL respects $UploadPrefixFmt and $EnableDirectDownload of the wiki.%0a%0a%0a!![[#SessionAuth]] SessionAuth()%0a%25hlt php%25[@SessionAuth($pagename, $auth=NULL)@]%0a%0a%25hlt php%25@@SessionAuth()@@ manages keeping authentication via cookie-sessions. Session contains every password or validated id and associated groups from previous calls. It adds elements passed by @@$auth@@ to session. It also writes every element saved in session to @@$AuthPw(passwords)@@ and @@$AuthList(ids and groups)@@.%0a%0a!![[#IsAuthorized]] IsAuthorized()%0a%25hlt php%25[@IsAuthorized($chal, $source, &$from)@]%0a%0a%25hlt php%25@@IsAuthorized()@@ takes a pageattributesstring (e. g. "id:user1 $1$Ff3w34HASH...") in @@$chal@@.%0a%0a%25hlt php%25@@$source@@ is simply returned and used for building the authcascade (pageattributes - groupattributes - @@$DefaultPassword@@).%0a%0a%25hlt php%25@@$from@@ will be returned if @@$chal@@ is empty, because it is not checked before calling @@IsAuthorized()@@, this is needed for the authcascade. %0a%25hlt php%25@@IsAuthorized()@@ returns an array with three values: @@$auth@@ @@1@@ - authenticated, @@0@@ - not authenticated, @@-1@@ - refused; @@$passwd@@; @@$source@@ from the parameter list.%0a%0a!![[#CondAuth]] CondAuth()%0a%25hlt php%25[@CondAuth($pagename, 'auth level')@]%0a%0a%25hlt php%25[@CondAuth()@] implements the [[ConditionalMarkup]] for [@(:if auth level:)@]. For instance [@ CondAuth($pagename,'edit')@] is true if authorization level is 'edit'. Use inside local configuration files to build conditionals with a check of authorization level, similar to using [@(:if auth level:)@] on a wiki page.%0a%0aNote that %25hlt php%25@@CondAuth()@@ should be called after all authorization levels and passwords have been defined. For example, if you use it with [[Drafts]], you should include the @@draft.php@@ script before calling @@CondAuth()@@:%0a%25hlt php%25[@%0a $EnableDrafts = 1;%0a $DefaultPasswords['publish'] = pmcrypt('secret');%0a include_once("$FarmD/scripts/draft.php");%0a if (! CondAuth($pagename, 'edit')) { /* whatever */ }%0a@]%0aBest is to use %25hlt php%25@@CondAuth()@@ near the bottom of your @@config.php@@ script.%0a%0a!! [[#RetrieveAuthPage]] RetrieveAuthPage()%0a%25hlt php%25@@RetrieveAuthPage($pagename, $level, $authprompt=true, $since=0)@@%0a%0aPm words as said in https://www.pmwiki.org/pipermail/pmwiki-users/2005-April/012804.html %0awhere:%0a%0a $pagename - name of page to be read%0a $level - authorization level required (read/edit/auth/upload)%0a $authprompt - true if user should be prompted for a password if needed%0a $since - how much of the page history to read%0a 0 == read entire page including all of history%0a READPAGE_CURRENT == read page without loading history%0a timestamp == read history only back through timestamp%0a%0aThe @@$since@@ parameter allows PmWiki to stop reading from a page file%0aas soon as it has whatever information is needed -- i.e., if an operation%0asuch as browsing isn't going to need the page's history, then specifying%0aREADPAGE_CURRENT can result in a much faster loading time. (This can be %0aespecially important for things such as searching and page listings.)%0aHowever, if combined with %25hlt php%25@@UpdatePage()@@, the updated page will have no history.%0a%0aUse e.g. %25hlt php%25[@$page = @RetrieveAuthPage('Main.MyPage', 'read')@] to obtain a page object that contains all the information of the correspondent file in separate keys, e.g. [@$page['text']@] will contain a string with the current wiki markup of Main.MyPage. Use this generally in preference to the alternative function [@ReadPage($pagename, $since=0)@] since it respects the authorisation of the user, i.e. it checks the authorisation level before loading the page, or it can be set to do so. [@ReadPage()@] reads a page regardless of permission.%0a%0aPassing 'ALWAYS' as the authorization level (instead of 'read', 'edit', etc.) will cause %25hlt php%25@@RetrieveAuthPage()@@ to always read and return the page, even if it happens to be protected by a read password.%0a%0a%0a!! [[#RetrieveAuthSection]] RetrieveAuthSection()%0a%25hlt php%25@@RetrieveAuthSection($pagename, $pagesection, $list=NULL, $auth='read')@@%0a%0a%25hlt php%25@@RetrieveAuthSection()@@ extracts a section of text from a page. If @@$pagesection@@ starts with anything other than '@@#@@', the text before the first '@@#@@' (or all of it, if there is no '@@#@@') identifies the page to extract text from. Otherwise @@RetrieveAuthSection()@@ looks in the pages given by @@$list@@ (should be an array), or in @@$pagename@@ if @@$list@@ is not specified. %0a* The selected page is placed in the global @@$RASPageName@@ variable. %0a* The caller is responsible for calling %25hlt php%25@@Qualify()@@ as needed, i.e. if you need to control how unqualified page and variable names shall be resolved.%0a** To have them act as in the original text, let %25hlt php%25@@Qualify()@@ resolve them relative to the source page.%0a** If the imported text was not meant as wikitext but as some other kind of markup that might happen to contain double pairs of square brackets, (:comment %3c-- not: pairs of 〚double square brackets〛 = U+301A/U+301B:) or dollar signs inside curly brackets, you probably don't want to %25hlt php%25@@Qualify()@@ them. If you output them into wikitext, you'll probably need to @@Keep()@@ the text (:comment %3c-- translators: conceptually this means to have Keep() pack the text in a container that marks it as "final".:) (in case of HTML, XML, RSS or similar output, @@PHSC()@@ first!), to prevent later stages of processing from interpreting the apparent wiki markups in context of the target page.%0a** If your code produces wikitext for an auxiliary page that is meant to be included by another page higher up in the inclusion chain, and want links and variables to work as if they were in the auxiliary page, use the auxiliary page's "GroupName.PageName" as the $pagename argument for %25hlt php%25@@Qualify()@@.%0a%0aProvides a way to limit the array that is returned by ReadPage, so that it only pulls the content up to a specific section marker. For example, pulling from start of page to '##blogend':%0a->%25hlt php%25[@%0afunction FeedText($pagename, &$page, $tag) {%0a $text = RetrieveAuthSection($pagename, '##blogend');%0a $content = MarkupToHTML($pagename, $text);%0a return "%3c$tag>%3c![CDATA[$content]]>%3c/$tag>";%0a}%0a@]%0a%0aThe '##blogend' argument says to read from the beginning of the page to just before the line containing the [[#blogend]] marker. See%0a[[PmWiki:IncludeOtherPages | IncludeOtherPages]] for more information about the section specifications.%0a%0aThis version won't read text from pages that are read-protected; if you want to get text even from read-protected pages, then %0a->%25hlt php%25[@%0a $text = RetrieveAuthSection($pagename, '##blogend', NULL, 'ALWAYS');%0a@]%0a%0a%0a!! [[#UpdatePage]] UpdatePage()%0a%25hlt php%25@@UpdatePage($pagename, $old (page object), $new (page object));@@%0a%0a''[[PmWiki:UpdatePage|More Technical Notes]]''%0a%0a%25hlt php%25[@UpdatePage()@] allows cookbook recipes to mimic the behavior of editing wiki pages via the browser. Internally, PmWiki does several housekeeping tasks which are accessible via this function (preserving history/diff information, updating page revision numbers, updating RecentChanges pages, sending email notifications, etc._%0a* "Page object" refers to an array pulled from %25hlt php%25[@RetrieveAuthPage($pagename, $level, $authprompt=true, $since=0);@] (preferred), or [@ReadPage($pagename); @] (disregards page security). Note that @@$new['text']@@ should contain all page data for the new version of the page. %0a* If a page doesn't exist, %25hlt php%25@@UpdatePage()@@ will attempt to create it.%0a* Ignoring @@$old@@ (e.g. %25hlt php%25[@UpdatePage($pagename, '', $new);@]) will erase all historical page data---a ''tabula rasa''.%0a** If you retrieved @@$old@@ using %25hlt php%25@@RetrieveAuthPage($pagename,$auth,$prompt,READPAGE_CURRENT)@@ and set @@$new=$old@@, then @@UpdatePage()@@ will also erase all historical data%0a%25hlt php%25@@UpdatePage()@@ cannot be called directly from @@config.php@@ because there are necessary initializations which occur later in @@pmwiki.php@@. It is not enough to just load @@stdconfig.php@@. If you want to use @@UpdatePage()@@ you will need to do it within a [[PmWiki:CustomMarkup | custom markup]], a [[Cookbook:MarkupExpressionSamples | custom markup expression]], or a [[PmWiki:CustomActions | custom action]].%0a%0a%0a!! [[#InsertEditFunction]] InsertEditFunction()%0a%25hlt php%25@@InsertEditFunction($newfn, $where='%3cPostPage')@@%0a%0aThis function makes it easy for recipe authors to insert a custom function in a specific position of the processing, see $EditFunctions and [[#UpdatePage|UpdatePage()]]. %0a%0aThe first argument is the name of the new function.%0a%0aThe second argument is the position where to place the new function, related to other edit functions? It can be:%0a* @@"%3c"@@ at the start, before the first edit function%0a* @@">"@@ at the end, after the last edit function%0a* @@"%3cExistingEditFunction"@@ before a specified edit function%0a* @@">ExistingEditFunction"@@ after a specified edit function%0a%0aThe function will return ''true'' on success, and ''false'' on failure (when the specified position or existing function was not recognized).%0a%0a!! [[#DisableSkinParts]] DisableSkinParts()%0a%25hlt php%25@@DisableSkinParts('parts to disable');@@%0a%0aThis function allows easy disabling of the skin sections header, footer, title, actions, and sidebars, like the corresponding directives %25pmhlt%25@@[=(:notitle:) (:noleft:)=]@@ etc. In your function, use something like:%0a->%25hlt php%25[@%0a DisableSkinParts('Left Header Footer Action Title');%0a@]%0a%0a!! [[#ParseArgs]] ParseArgs()%0aSee Cookbook:ParseArgs. %0a%0a!! [[#Redirect]] Redirect()%0a%0a!! [[#PageIndexTerms]] PageIndexTerms()%0a%0a!! [[#AsSpaced]] AsSpacedUTF8(), AsSpaced()%0a>>hlt php%3c%3c%0a@@AsSpaced()@@ is declared in @@pmwiki.php@@ \\%0a@@AsSpaced()@@ converts a string with WikiWords into a spaced version of that string.%0aIt can be overridden via $AsSpacedFunction, as it is in @@AsSpacedUTF8()@@. \\%0a@@AsSpacedUTF8()@@ is declared in the @@xlpage-utf-8.php@@ script.%0a>>%3c%3c%0a%0aCategories: [[!PmWiki Developer]]
-time=1684475221
+text=(:Summary: How some of the functions in pmwiki.php work:)%0a(:Audience: admins (advanced) :)%0a%0aThis page describes some of the internal workings of PmWiki by explaining how some of the functions in @@pmwiki.php@@ work. For a more brief list/overview on functions useful to for instance cookbook writers, see Cookbook:Functions. %0a%0aTo use this functions you have to make sure that all relevant internal variables have been initialized correctly. See [[Custom Markup]] and [[(PmWiki:)Custom Actions]] for more information on how these functions are typically called via %25hlt php%25[@Markup()@] or [@$HandleActions[]@].%0a%0a!! [[#PSFT]] PSFT()%0a%0a%25hlt php%25[@PSFT($format, $timestamp=null, $locale=null, $tz=null)@]%0a%0aThe %25hlt php%25@@PSFT()@@ function (''PmWiki String Format Time'', added in 2.3.0) is intended to be a safe replacement for the very widely used PHP functions @@[[https://www.php.net/strftime|strftime()]]@@ and @@[[https://www.php.net/gmstrftime|gmtstrftime()]]@@ which became deprecated in PHP 8.1.%0a%0aUnlike %25hlt php%25@@strftime()@@, @@PSFT()@@ accepts 2 additional arguments @@$locale@@ and @@$tz@@, which allow to set a different language or timezone.%0a%0aPmWiki 2.3.0 uses this function in all cases where it previously used %25hlt php%25@@strftime()@@, including the %25pmhlt%25[@{(ftime)}@] Markup Expression. If your local customizations and recipes use %25hlt php%25@@strftime()@@, you should be able to safely replace all calls to @@strftime()@@ with @@PSFT()@@, without changing the arguments. Any calls to @@gmtstrftime($fmt, $stamp)@@ can be replaced with @@PSFT($fmt, $stamp, null, 'GMT')@@.%0a%0aThe old functions were deprecated by the PHP developers because they behaved inconsistently on different platforms, and were dependent on installed system locales (i.e. a language would only work if the system had its locale installed). The new function uses the PHP class [[https://www.php.net/manual/en/class.intldateformatter.php|IntlDateFormatter]] and should be better. Unfortunately, it is not always enabled by hosting providers. %0a%0aSo depending on your installation, a specific language may be available with %25hlt php%25@@strftime()@@ and/or with @@IntlDateFormatter@@.%0a%0aIn addition, some rarely used shortcut percent-formats [@%25c, %25x, %25X@] also behave inconsistently on different platforms, and the new formatter may show a slightly different output. You can always replace these shortcut formats with the full formats you require.%0a%0aFor these reasons, %25hlt php%25@@PSFT()@@ is currently a compromise, by default reusing @@strftime()@@ for PHP 8.0 or earlier. Updating your calls from @@strftime()@@ shouldn't cause any changes in your outputs.%0a%0aYou can set in @@config.php@@ the variable %25hlt php%25@@$EnableFTimeNew = 1;@@ for @@PSFT()@@ to try using @@IntlDateFormatter@@ before PHP 8.1. If @@IntlDateFormatter@@ is not available, it will show the month and day names in English. Check what works.%0a%0aSince the %25hlt php%25@@strftime()@@ function is deprecated, it is unlikely for it to add new formats. We have added 2 custom formats:%0a* [@%25o@] for the "ordinal suffix" of the date, as "st" in "January 1st". If @@IntlDateFormatter@@ is not available, it will show the suffix in English%0a* [@%25L@] for a human-readable timestamp of the format %25pmhlt%25[@@2022-09-25T11:49:08Z@]%25%25 which will be displayed formatted either as $TimeFmt or in the local time zone of the visitor, see $EnableLocalTimes.%0a%0a(:include MarkupExpressions#ftimeformats#ftimeformatsend:)%0a%0a>>frame%3c%3c%0aA difference between %25hlt php%25@@strftime($format, $stamp)@@ and @@PSFT($format, $stamp)@@ is how they interpret a false, empty or non-numeric @@$stamp@@ argument.%0a|| class=simpletable%0a||! @@$stamp@@ argument ||! @@strftime($format, $stamp)@@ ||! @@PSFT($format, $stamp)@@ ||%0a|| numeric || the stamp || the stamp ||%0a|| missing or ''null'' || current time || current time ||%0a|| ''false'' || 1970-01-01 || current time ||%0a|| "" (empty string) \\%0aother non-numeric || 1970-01-01 or ''false'' (older PHP versions) \\%0a ''Warning: TypeError'' (PHP 7.4+) || current time ||%0aFor PmWiki, it seemed reasonable to make empty strings and other non-numeric values default to the current time. If your %25hlt php%25@@$stamp@@ variable may be empty or ''false'', and your recipes rely on @@strftime()@@ returning "1970-01-01", you can cast the stamp to integer:%0a%25hlt php%25[@%0a PSFT($format, intval($stamp));%0a@]%0a>>%3c%3c%0a%0a%0a!! [[#pmtoken]] pmtoken()%0a%25hlt php%25[@pmtoken($check = 0, $abort = false)@]%0a%0aThe %25hlt php%25@@pmtoken()@@ function sets or checks a unique session identifier to be used in input forms, with the goal of preventing cross-site request forgeries (CSRF).%0a%0aCalling %25hlt php%25@@pmtoken()@@ or @@pmtoken(0)@@ will create a token if it doesn't exist, store it in the @@$_SESSION@@ array, and return it. It will also set the variables [@$FmtV['$TokenValue']@] which can be used in HTML templates and [@$InputValues['pmtoken']@] to be used in markup [[forms]], although it may be simpler to use %25pmhlt%25[@(:input pmtoken:)@] instead.%0a%0aThe name of the input element, by default 'pmtoken', can be changed by setting for example %25hlt php%25[@$FmtV['$TokenName'] = 'CSRFtoken';@].%0a%0aCalling %25hlt php%25@@pmtoken(1)@@ will check the @@$_POST['pmtoken']@@ value and will return true if it is valid.%0a%0aCalling %25hlt php%25@@pmtoken(2)@@ will check the @@$_GET['pmtoken']@@ value and will return true if it is valid.%0a%0aCalling %25hlt php%25@@pmtoken(1, true)@@ or @@pmtoken(2, true)@@ with a second truthy argument, and the token is invalid, will directly call @@Abort()@@ and exit.%0a%0a%0a!! [[#pmcrypt]] pmcrypt()%0a%25hlt php%25[@pmcrypt($password, $salt = null)@]%0a%0aThe %25hlt php%25@@pmcrypt()@@ function is intended to be a safe replacement for the [[https://www.php.net/crypt|PHP 5.6+ crypt() function]] without providing a $salt, which would raise a notice. If a salt is provided, crypt() is called to check an existing password. If a salt is not provided, [[https://www.php.net/password_hash|password_hash()]] will be called to create a cryptographically strong password hash.%0a%0a!! [[#pmsetcookie]] pmsetcookie()%0a%25hlt php%25[@pmsetcookie($name, $val="", $exp=0, $path="", $dom="", $secure=null, $httponly=null)@]%0a%0aThis function is intended as a replacement for [[https://www.php.net/setcookie|setcookie()]]. It will automatically set the $secure and $httponly arguments if they are not set by the caller function and if $EnableCookieSecure and $EnableCookieHTTPOnly are enabled.%0a%0a!![[#PCCF]] PCCF() %25red%25 Deprecated since PHP 7.2%25%25%0a%25hlt php%25[@PCCF($php_code, $callback_template='default', $callback_arguments = '$m')@] %0a%0aThe %25hlt php%25@@PCCF()@@ function (''PmWiki Create Callback Function'') can be used to create callback functions used with [[https://www.php.net/preg_replace_callback|preg_replace_callback]]. It is required for PHP 5.5, but will also work with earlier PHP versions.%0a%0aThe first argument is the PHP code to be evaluated. %0a%0aThe second argument (optional) is the callback template, a key from the global @@$CallbackFnTemplates@@ array. There are two templates that can be used by recipe authors: %0a* 'default' will pass @@$php_code@@ as a function code%0a* 'return' will wrap @@$php_code@@ like "@@return $php_code;@@" (since PmWiki 2.2.62)%0a%0aThe third argument (optional) is the argument of the callback function. Note that PmWiki uses the '$m' argument to pass the matches of a regular expression search, but your function can use other argument(s).%0a%0a%25hlt php%25@@PCCF()@@ will create an anonymous (lambda) callback function containing the supplied code, and will cache it. On subsequent calls with the same @@$php_code@@, @@PCCF()@@ will return the cached function name.%0a%0aSee the [[https://www.php.net/create_function | PHP create function]].%0a%0a>>font-style=italic%3c%3c%0aPHP 7.2 deprecates %25hlt php%25@@create_function()@@ and future versions will remove it. If you need to migrate older code that used @@PCCF()@@, you can usually write regular functions and pass the function name where you previously passed the result of PCCF(). For example, suppose you had a pattern like this:%0a-> %25hlt php%25@@'/(?%3c=^| )([a-z])/' => PCCF("return strtoupper(\$m[1]);"),@@%0a%0aFor PHP 7.2 compatibility, you can write a callback function:%0a-> %25hlt php%25@@function @@%25green%25my_callback%25hlt php%25@@($m) { return strtoupper($m[1]); }@@%0a%0athen change the pattern to look like this:%0a-> %25hlt php%25@@'/(?%3c=^| )([a-z])/' => '%25green%25my_callback%25%25',@@%0a%0aSee also: the recipe [[(Cookbook:)PccfToPcfOverride]] allows existing recipes to run on PHP 7 without causing deprecated @@create_function()@@ messages.%0a>>%3c%3c%0a%0a!![[#PPRA]] PPRA()%0a%25hlt php%25[@PPRA($array_search_replace, $string)@]%0a%0aThe %25hlt php%25@@PPRA()@@ function (''PmWiki Preg Replace Array'') can be used to perform a regular expression replacement with or without evaluation, for PHP 5.5 compatibility. %0a%0aSince PmWiki 2.2.56, PmWiki uses this function to process the following arrays: $MakePageNamePatterns, $FmtP, $QualifyPatterns, $ROEPatterns, $ROSPatterns, $SaveAttrPatterns, $MakeUploadNamePatterns. Any custom settings should continue to work for PHP 5.4 and earlier, but wikis running on PHP 5.5 may need to make a few changes.%0a%0aThe first argument contains the 'search'=>'replace' pairs, the second is the "haystack" string to be manipulated.%0a%0aThe 'replace' parts of the array can be strings or function names. If the 'replace' part is a callable function name, it will be called with the array of matches as a first argument via %25hlt php%25@@preg_replace_callback()@@. If not a callable function, a simple @@preg_replace()@@ will be performed.%0a%0aPreviously, PmWiki used such constructs:%0a-> %25hlt php%25@@$fmt = preg_replace(array_keys($FmtP), array_values($FmtP), $fmt);@@%0a%0aIt is now possible to use simply this:%0a-> %25hlt php%25@@$fmt = PPRA($FmtP, $fmt);@@%0a%0aNote that since PHP 5.5, the search patterns cannot have an /e evaluation flag. When creating the $array_search_replace array, before PHP 5.5 we could use something like (eg. for $MakePageNamePatterns):%0a-> %25hlt php%25@@'/(?%3c=^| )([a-z])/e' => "strtoupper('$1')",@@%0a%0aSince PHP 5.5, we should use this (will also work in PHP 5.4 and earlier):%0a-> %25hlt php%25@@'/(?%3c=^| )([a-z])/' => PCCF("return strtoupper(\$m[1]);"),@@%0a%0aNote that the @@/e@@ flag should be now omitted, instead of @@'$0', '$1', '$2',@@ we should use @@$m[0], $m[1], $m[2],@@ etc. in the replacement code, and there is no need to call @@PSS()@@ in the replacement code, as backslashes are not automatically added.%0a%0a>>font-style=italic%3c%3c%0aFor PHP 7.2 and newer, instead of using %25hlt php%25@@PCCF()@@ to create anonymous functions, we add a real function in our add-on, and then pass the function name as the pattern replacement (see example at [[#PCCF|PCCF]], which will also work on PHP 4 and 5):%0a-> %25hlt php%25@@'/(?%3c=^| )([a-z])/' => '%25green%25my_callback%25%25',@@%0a>>%3c%3c%0a%0a!![[#PPRE]] PPRE() %25red%25 Deprecated since PHP 7.2%25%25%0a%25hlt php%25[@PPRE($search_pattern, $replacement_code, $string)@]%0a%0aThe %25hlt php%25@@PPRE()@@ function (''PmWiki Preg Replace Evaluate'') can be used to perform a regular expression replacement with evaluation.%0a%0aSince PHP 5.5, the %25hlt php%25@@preg_replace()@@ function has deprecated the /e evaluation flag, and displays warnings when the flag is used. The @@PPRE()@@ function automatically creates a callback function with the replacement code and calls it.%0a%0aBefore PHP 5.5, it was possible to use such calls:%0a-> %25hlt php%25@@$fmt = preg_replace('/\\$([A-Z]\\w*Fmt)\\b/e','$GLOBALS["$1"]',$fmt);@@%0a%0aSince PHP 5.5, it is possible to replace the previous snippet with the following (also works before PHP 5.5):%0a-> %25hlt php%25@@$fmt = PPRE('@@%25green%25/\\$([A-Z]\\w*Fmt)\\b/%25hlt php%25@@','$GLOBALS[$m[1]]',$fmt);@@%0a%0aNote that the @@/e@@ flag should be now omitted, instead of @@'$0', '$1', '$2',@@ we should use @@$m[0], $m[1], $m[2],@@ etc. in the replacement code, and there is no need to call @@PSS()@@ in the replacement code, as backslashes are not automatically added.%0a%0a>>font-style=italic%3c%3c%0aFor PHP 7.2 and newer, calling this function will raise "deprecated" notices. You need to rewrite your code to use [[https://www.php.net/preg_replace_callback|preg_replace_callback]], by moving the code into real functions:%0a%0a-> %25hlt php%25@@$fmt = preg_replace_callback('@@%25green%25/\\$([A-Z]\\w*Fmt)\\b/%25hlt php%25@@', 'my_global_var_callback',$fmt);@@%0a-> %25hlt php%25@@function my_global_var_callback($m) { return $GLOBALS[$m[1]]; }@@%0a%0ainstead of using %25hlt php%25@@PCCF()@@ to create anonymous functions, we add a real function in our add-on, and then pass the function name as the pattern replacement (see example at [[#PCCF|PCCF]], which will also work on PHP 4 and 5):%0a=> %25hlt php%25@@'/(?%3c=^| )([a-z])/' => '%25green%25my_callback%25%25',@@%0a>>%3c%3c%0a%0a(:if false:)(:comment Needs review and may change:)%0a!![[#PRCB]] PRCB()%0a%25hlt php%25[@PRCB($pat, $repl, $subj, $vars=null, $limit=-1, &$count=null, $flags=0)@]%0a%0aThe %25hlt php%25@@PRCB()@@ function (''PmWiki Regex Replace Callback'') makes it simple to pass variables to a named callback function with [[https://php.net/preg_replace_callback|preg_replace_callback()]].%0a%0aIf you need to use preg_replace_callback() and pass some variables to the callback function, you can do something like:%0a%0a%25hlt php%25[@$result = PRCB($patern, 'my_callback', $subject, $pagename);@]%0a%0aThen your function will be called this way: %25hlt php%25[@my_callback($matches, $pagename);@]. You can pass multiple variables with an array.%0a%0aThe function can also be used without passing variables, just shorter than @@preg_replace_callback()@@:%0a%0a%25hlt php%25[@$result = PRCB($patern, 'my_callback', $subject);@]%0a%0a(:ifend:)%0a%0a!![[#Qualify]] Qualify()%0a%25hlt php%25[@Qualify($pagename, $text)@]%0a%0a%25hlt php%25@@Qualify()@@ applies $QualifyPatterns to convert relative links and references into absolute equivalents.%0aThis function is called by usual wiki markups that include text from other pages.%0aIt will rewrite links like %25pmhlt%25[@[[Page]]@] into [@[[Group/Page]]@], and page (text) variables like [@{$Title}@] into [@{Group.Page$Title}@]%0aso that they work the same way in the source page and in the including page.%0aSee also $QualifyPatterns and %25pmhlt%25@@[[({$Name}#)RetrieveAuthSection]]()@@.%0a%0a%0a!![[#PHSC]] PHSC()%0a%25hlt php%25[@PHSC($string_or_array, $flags=ENT_COMPAT, $encoding=null, $double_encode=true)@]%0a%0aThe %25hlt php%25@@PHSC()@@ function (''PmWiki HTML Special Characters'') is a replacement for the PHP function [[https://www.php.net/htmlspecialchars|htmlspecialchars]]. %0a%0aThe %25hlt php%25@@htmlspecialchars()@@ function was modified since PHP 5.4 in two ways: it now requires a valid string for the supplied encoding, and it changes the default encoding to UTF-8. This can cause sections of the page to become blank/empty on many sites using the ISO-8859-1 encoding without having set the third argument ($encoding) when calling @@htmlspecialchars()@@.%0a%0aThe %25hlt php%25@@PHSC()@@ function calls @@htmlspecialchars()@@ with an 8-bit encoding as third argument, whatever the encoding of the wiki (unless you supply an encoding). This way the string never contains invalid characters.%0a%0aIt should be safe for recipe developers to replace all calls to %25hlt php%25@@htmlspecialchars()@@ with calls to @@PHSC()@@. Only the first argument is required when calling @@PHSC()@@, although authors may wish to call @@PHSC($string_or_array, ENT_QUOTES)@@.%0a%0aUnlike %25hlt php%25@@htmlspecialchars()@@, the @@PHSC()@@ function can process arrays recursively (only the values are converted, not the keys of the array).%0a%0a!![[#PSS]] PSS()%0a%25hlt php%25[@PSS($string)@]%0a%0aThe %25hlt php%25@@PSS()@@ function (''PmWiki Strip Slashes'') removes the backslashes that are automatically inserted in front of quotation marks by the /e option of PHP's preg_replace function. @@PSS()@@ is%0amost commonly used in replacement arguments to @@Markup()@@, when the pattern specifies /e and one or more of the parenthesized subpatterns could contain a quote or backslash. %0a("PSS" stands for "PmWiki Strip Slashes".)%0a->From PM: PmWiki expects %25hlt php%25@@PSS()@@ to always occur inside of double-quoted strings and to contain single quoted strings internally. The reason for this is that we don't want the @@$1@@ or @@$2@@ to accidentally contain characters that would then be interpreted inside of the double-quoted string when the PSS is evaluated.%0a-->%25hlt php%25@@Markup('foo', 'inline', '/(something)/e', 'Foo(PSS("$1"))'); # wrong@@%0a-->%25hlt php%25@@Markup('foo', 'inline', '/(something)/e', "Foo(PSS('$1'))"); # right@@%0a%0a%25note%25 Note, the extra slashes are only added by %25hlt php%25@@preg_replace()@@ with an @@/e@@ modifier. The markup definitions with @@Markup_e()@@ do NOT need to use @@PSS()@@ in the replacement strings. The new-type markup definitions with @@Markup()@@ and a simple function name as a replacement do NOT need to use @@PSS()@@ inside the replacement function. If you migrate old markup rules to the new format, delete the @@PSS()@@ calls.%0a%0a!!! Example %25block notoc%25%0aThis is a fictitious example where %25hlt php%25@@PSS()@@ should be used.%0aLet us assume that you wish to define a directive %25pmhlt%25[@(:example:)@]%0asuch that %25pmhlt%25[@(:example "A horse":)@] results in the HTML%0a-> %25hlt html%25[@%3cdiv>"A horse"%3c/div>@].%0aHere is how the markup rule can be created:%0a-> %25hlt php%25[@%0aMarkup('example', 'directives',%0a '/\\(:example\\s(.*?):\\)/e',%0a "Keep('%3cdiv>'.PSS('$1').'%3c/div>')");%0a@]%0aWe need to use %25hlt php%25@@PSS()@@ around the '@@$1@@' because the matched text could contain quotation marks, and the @@/e@@ will add backslashes in front of them.%0a%0a!![[#stripmagic]] stripmagic()%0a%25hlt php%25[@stripmagic($string)@]%0a%0aThis function should be used when processing the contents of %25hlt php%25[@$_POST@] or [@$_GET@] variables when they could contain quotes or backslashes. It verifies [@get_magic_quotes()@], if true, strips the automatically inserted escapes from the string.%0a%0aThe function can process arrays recursively (only the values are processed).%0a%0a!![[#FmtPageName]] FmtPageName()%0a%0a%25hlt php%25[@FmtPageName($fmt, $pagename)@]%0a%0a[[#FmtPageName-desc]]Returns %25hlt php%25[@$fmt@], with @@$variable@@ and [=$[internationalisation]=] substitutions performed, under the assumption that the current page is [@pagename@]. See [[PmWiki.Variables]] for an (incomplete) list of available variables, [[PmWiki.Internationalizations]] for internationalisation. Security: not to be run on user-supplied data.%0a%0aThis is one of the major functions in PmWiki, see [[PmWiki.FmtPageName]] for%0alots of details.%0a%0a%0a!![[#Markup]] Markup()%0a%25hlt php%25[@Markup($name, $when, $pattern, $replace)@]%0a%0a[[#Markup-desc]]Adds a new markup to the conversion table. Described in greater detail at [[PmWiki.CustomMarkup]].%0a%0aThis function is used to insert translation rules into the PmWiki's translation engine. The arguments to %25hlt php%25[@Markup()@] are all strings, where:%0a%0a:%25hlt php%25[@$name@]: The string names the rule that is inserted. If a rule of the same name already exists, then this rule is ignored.%0a:%25hlt php%25[@$when@]: This string is used to control ''when'' a rule is to be applied relative to other rules. A specification of "[@%3cxyz@]" says to apply this rule prior to the rule named "xyz", while "[@>xyz@]" says to apply this rule after the rule "xyz". See [[(PmWiki:)CustomMarkup]] for more details on the order of rules.%0a:%25hlt php%25[@$pattern@]: This string is a [[regular expression -> https://www.php.net/preg_replace]] that is used by the translation engine to look for occurrences of this rule in the markup source.%0a:%25hlt php%25[@$replace@]: This string will replace the matched text when a match occurs, or the function name that will return the replacement text.%0a%0aAlso see: [[PmWiki.CustomMarkup]] and [[Cookbook:Functions#Markup]]%0a%0a!![[#MarkupToHTML]] MarkupToHTML()%0a%0a%25hlt php%25[@MarkupToHTML($pagename, $str)@]%0a%0a[[#MarkupToHTML-desc]] Converts the string %25hlt php%25[@$str@] containing PmWiki markup into the corresponding HTML code, assuming the current page is [@$pagename@].%0a%25hlt php%25@@MarkupToHTML()@@ replaces @@\n\n@@ sequences by @@%3c:vspace>@@ first thing when text is passed to it. Subsequently @@%3c:vspace>@@ is processed by the markup rules:%0a-> '@@!vspace@@' removes @@%3c:vspace>@@ after headings.%0a-> '@@%3cvspace>%3cp>@@' replaces @@%3c:vspace>%3cp>@@ with @@%3cp class='vspace'>@@%0a-> '@@%3cvspace>@@' replaces %3c:vspace> with @@%3cdiv class='vspace'>@@%0a-> and finally%0a-> '@@^%3c:@@' removes any remaining @@%3c:vspace>@@, mostly from restored [=[=]=escaped text=].%0a%0aAlso see: [[Cookbook:Functions#MarkupToHTML]]%0a%0a!![[#mkdirp]] mkdirp()%0a%25hlt php%25[@mkdirp($dir)@]%0a%0aThe function %25hlt php%25[@mkdirp($dir)@] creates a directory, [@$dir@], if it doesn't already exist, including any parent directories that might be needed. For each directory created, it checks that the permissions on the directory are sufficient to allow PmWiki scripts to read and write files in that directory. This includes checking for restrictions imposed by PHP's safe_mode setting. If [@mkdirp()@] is unable to successfully create a read/write directory, [@mkdirp()@] aborts with an error message telling the administrator the steps to take to either create @@$dir@@ manually or give PmWiki sufficient permissions to be able to do it.%0a%0a!![[#Lock]] Lock()%0a%25hlt php%25[@Lock(0)@]%0a%0aThis function is used to make sure only one instance of PmWiki is running when files are being written. It does not "lock pages" for editing.%0a%0aFrom a recipe, use:%0a* %25hlt php%25[@Lock(2);@] to acquire an ''exclusive'' lock, so that no other PHP processes can modify files. This can be used when your function is writing files on the server.%0a* %25hlt php%25[@Lock(1);@] to acquire a ''shared'' lock. This may be used when your function is reading files from the server, in case another process is writing them at the same time.%0a* %25hlt php%25[@Lock(0);@] to ''release'' a previous exclusive or shared lock. Use this immediately after your function finishes reading or writing the files.%0a%0aIf you don't release an acquired lock, it should be automatically released at the end of the processing.%0a%0a%0a!![[#MakeLink]] MakeLink()%0a%25hlt php%25[@MakeLink($pagename, $target, $txt, $suffix, $fmt)@]%0a%0aThe function %25hlt php%25[@MakeLink($pagename, $target, $txt, $suffix, $fmt)@] returns an html-formatted anchor link. Its arguments are as follows:%0a $pagename is the source page%0a $target is where the link should go%0a $txt is the value to use for '$LinkText' in the output %0a $suffix is any suffix string to be added to $txt%0a $fmt is a format string to use%0a%0aIf $txt is NULL or not specified, then it is automatically computed from $target.%0a%0aIf $fmt is NULL or not specified, then MakeLink uses the default%0aformat as specified by the type of link. For page links this%0ameans the $LinkPageExistsFmt and $LinkPageCreateFmt variables,%0afor intermap-style links it comes from either the $IMapLinkFmt%0aarray or from $UrlLinkFmt. Inside of the formatting strings,%0a$LinkUrl is replaced by the resolved url for the link, $LinkText%0ais replaced with the appropriate text, and $LinkAlt is replaced%0aby any "title" (alternate text) information associated with the%0alink.%0a%0aAlso see: [[PmWiki:MakeLink]] and [[Cookbook:Functions#MakeLink]]%0a%0a!![[#MakeUploadName]] MakeUploadName()%0a%25hlt php%25@@MakeUploadName($pagename, $x)@@%0a%0a%25hlt php%25@@MakeUploadName()@@ simply takes a string @@$x@@ (representing an attachment's%0aname) and converts it to a valid name by removing any unwanted characters.%0aIt also requires the name to begin and end with an alphanumeric character,%0aand as of 2.0.beta28 it forces any file extensions to lowercase.%0aThis function is defined in @@scripts/upload.php@@ and only used when uploads%0aare enabled.%0a%0a!![[#DownloadUrl]] DownloadUrl()%0a%25hlt php%25@@DownloadUrl($pagename, $path)@@%0a%0aThis function returns the public URL of an attached file. The arguments are as follow:%0a* $pagename - the currently processed page%0a* %25hlt php%25@@$path@@ - the file path, as in @@file.ext@@ or @@OtherPage/file.ext@@ or @@Group/OtherPage/file.ext@@%0a%0aIf the file doesn't exist, the function returns false. The global variable %25hlt php%25@@$FmtV['$LinkUpload']@@ contains the URL to the upload form, for a file with such a name to be attached. The global variable %25hlt php%25@@$FmtV['$LinkDownload']@@ contains the URL to the file, as if it were uploaded to the wiki.%0a%0aThe function calls [[#MakeUploadName|%25hlt php%25@@MakeUploadName()@@]] on the @@$path@@ argument so you don't need to do it before calling it.%0a%0aThe returned URL respects $UploadPrefixFmt and $EnableDirectDownload of the wiki.%0a%0a%0a!![[#SessionAuth]] SessionAuth()%0a%25hlt php%25[@SessionAuth($pagename, $auth=NULL)@]%0a%0a%25hlt php%25@@SessionAuth()@@ manages keeping authentication via cookie-sessions. Session contains every password or validated id and associated groups from previous calls. It adds elements passed by @@$auth@@ to session. It also writes every element saved in session to @@$AuthPw(passwords)@@ and @@$AuthList(ids and groups)@@.%0a%0a!![[#IsAuthorized]] IsAuthorized()%0a%25hlt php%25[@IsAuthorized($chal, $source, &$from)@]%0a%0a%25hlt php%25@@IsAuthorized()@@ takes a pageattributesstring (e. g. "id:user1 $1$Ff3w34HASH...") in @@$chal@@.%0a%0a%25hlt php%25@@$source@@ is simply returned and used for building the authcascade (pageattributes - groupattributes - @@$DefaultPassword@@).%0a%0a%25hlt php%25@@$from@@ will be returned if @@$chal@@ is empty, because it is not checked before calling @@IsAuthorized()@@, this is needed for the authcascade. %0a%25hlt php%25@@IsAuthorized()@@ returns an array with three values: @@$auth@@ @@1@@ - authenticated, @@0@@ - not authenticated, @@-1@@ - refused; @@$passwd@@; @@$source@@ from the parameter list.%0a%0a!![[#CondAuth]] CondAuth()%0a%25hlt php%25[@CondAuth($pagename, 'auth level')@]%0a%0a%25hlt php%25[@CondAuth()@] implements the [[ConditionalMarkup]] for [@(:if auth level:)@]. For instance [@ CondAuth($pagename,'edit')@] is true if authorization level is 'edit'. Use inside local configuration files to build conditionals with a check of authorization level, similar to using [@(:if auth level:)@] on a wiki page.%0a%0aNote that %25hlt php%25@@CondAuth()@@ should be called after all authorization levels and passwords have been defined. For example, if you use it with [[Drafts]], you should include the @@draft.php@@ script before calling @@CondAuth()@@:%0a%25hlt php%25[@%0a $EnableDrafts = 1;%0a $DefaultPasswords['publish'] = pmcrypt('secret');%0a include_once("$FarmD/scripts/draft.php");%0a if (! CondAuth($pagename, 'edit')) { /* whatever */ }%0a@]%0aBest is to use %25hlt php%25@@CondAuth()@@ near the bottom of your @@config.php@@ script.%0a%0a!! [[#RetrieveAuthPage]] RetrieveAuthPage()%0a%25hlt php%25@@RetrieveAuthPage($pagename, $level, $authprompt=true, $since=0)@@%0a%0aPm words as said in https://www.pmwiki.org/pipermail/pmwiki-users/2005-April/012804.html %0awhere:%0a%0a $pagename - name of page to be read%0a $level - authorization level required (read/edit/auth/upload)%0a $authprompt - true if user should be prompted for a password if needed%0a $since - how much of the page history to read%0a 0 == read entire page including all of history%0a READPAGE_CURRENT == read page without loading history%0a timestamp == read history only back through timestamp%0a%0aThe @@$since@@ parameter allows PmWiki to stop reading from a page file%0aas soon as it has whatever information is needed -- i.e., if an operation%0asuch as browsing isn't going to need the page's history, then specifying%0aREADPAGE_CURRENT can result in a much faster loading time. (This can be %0aespecially important for things such as searching and page listings.)%0aHowever, if combined with %25hlt php%25@@UpdatePage()@@, the updated page will have no history.%0a%0aUse e.g. %25hlt php%25[@$page = @RetrieveAuthPage('Main.MyPage', 'read')@] to obtain a page object that contains all the information of the correspondent file in separate keys, e.g. [@$page['text']@] will contain a string with the current wiki markup of Main.MyPage. Use this generally in preference to the alternative function [@ReadPage($pagename, $since=0)@] since it respects the authorisation of the user, i.e. it checks the authorisation level before loading the page, or it can be set to do so. [@ReadPage()@] reads a page regardless of permission.%0a%0aPassing 'ALWAYS' as the authorization level (instead of 'read', 'edit', etc.) will cause %25hlt php%25@@RetrieveAuthPage()@@ to always read and return the page, even if it happens to be protected by a read password.%0a%0a%0a!! [[#RetrieveAuthSection]] RetrieveAuthSection()%0a%25hlt php%25@@RetrieveAuthSection($pagename, $pagesection, $list=NULL, $auth='read')@@%0a%0a%25hlt php%25@@RetrieveAuthSection()@@ extracts a section of text from a page. If @@$pagesection@@ starts with anything other than '@@#@@', the text before the first '@@#@@' (or all of it, if there is no '@@#@@') identifies the page to extract text from. Otherwise @@RetrieveAuthSection()@@ looks in the pages given by @@$list@@ (should be an array), or in @@$pagename@@ if @@$list@@ is not specified. %0a* The selected page is placed in the global @@$RASPageName@@ variable. %0a* The caller is responsible for calling %25hlt php%25@@Qualify()@@ as needed, i.e. if you need to control how unqualified page and variable names shall be resolved.%0a** To have them act as in the original text, let %25hlt php%25@@Qualify()@@ resolve them relative to the source page.%0a** If the imported text was not meant as wikitext but as some other kind of markup that might happen to contain double pairs of square brackets, (:comment %3c-- not: pairs of 〚double square brackets〛 = U+301A/U+301B:) or dollar signs inside curly brackets, you probably don't want to %25hlt php%25@@Qualify()@@ them. If you output them into wikitext, you'll probably need to @@Keep()@@ the text (:comment %3c-- translators: conceptually this means to have Keep() pack the text in a container that marks it as "final".:) (in case of HTML, XML, RSS or similar output, @@PHSC()@@ first!), to prevent later stages of processing from interpreting the apparent wiki markups in context of the target page.%0a** If your code produces wikitext for an auxiliary page that is meant to be included by another page higher up in the inclusion chain, and want links and variables to work as if they were in the auxiliary page, use the auxiliary page's "GroupName.PageName" as the $pagename argument for %25hlt php%25@@Qualify()@@.%0a%0aProvides a way to limit the array that is returned by ReadPage, so that it only pulls the content up to a specific section marker. For example, pulling from start of page to '##blogend':%0a->%25hlt php%25[@%0afunction FeedText($pagename, &$page, $tag) {%0a $text = RetrieveAuthSection($pagename, '##blogend');%0a $content = MarkupToHTML($pagename, $text);%0a return "%3c$tag>%3c![CDATA[$content]]>%3c/$tag>";%0a}%0a@]%0a%0aThe '##blogend' argument says to read from the beginning of the page to just before the line containing the [[#blogend]] marker. See%0a[[PmWiki:IncludeOtherPages | IncludeOtherPages]] for more information about the section specifications.%0a%0aThis version won't read text from pages that are read-protected; if you want to get text even from read-protected pages, then %0a->%25hlt php%25[@%0a $text = RetrieveAuthSection($pagename, '##blogend', NULL, 'ALWAYS');%0a@]%0a%0a%0a!! [[#UpdatePage]] UpdatePage()%0a%25hlt php%25@@UpdatePage($pagename, $old (page object), $new (page object));@@%0a%0a''[[PmWiki:UpdatePage|More Technical Notes]]''%0a%0a%25hlt php%25[@UpdatePage()@] allows cookbook recipes to mimic the behavior of editing wiki pages via the browser. Internally, PmWiki does several housekeeping tasks which are accessible via this function (preserving history/diff information, updating page revision numbers, updating RecentChanges pages, sending email notifications, etc._%0a* "Page object" refers to an array pulled from %25hlt php%25[@RetrieveAuthPage($pagename, $level, $authprompt=true, $since=0);@] (preferred), or [@ReadPage($pagename); @] (disregards page security). Note that @@$new['text']@@ should contain all page data for the new version of the page. %0a* If a page doesn't exist, %25hlt php%25@@UpdatePage()@@ will attempt to create it.%0a* Ignoring @@$old@@ (e.g. %25hlt php%25[@UpdatePage($pagename, '', $new);@]) will erase all historical page data---a ''tabula rasa''.%0a** If you retrieved @@$old@@ using %25hlt php%25@@RetrieveAuthPage($pagename,$auth,$prompt,READPAGE_CURRENT)@@ and set @@$new=$old@@, then @@UpdatePage()@@ will also erase all historical data%0a%25hlt php%25@@UpdatePage()@@ cannot be called directly from @@config.php@@ because there are necessary initializations which occur later in @@pmwiki.php@@. It is not enough to just load @@stdconfig.php@@. If you want to use @@UpdatePage()@@ you will need to do it within a [[PmWiki:CustomMarkup | custom markup]], a [[Cookbook:MarkupExpressionSamples | custom markup expression]], or a [[PmWiki:CustomActions | custom action]].%0a%0a%0a!! [[#InsertEditFunction]] InsertEditFunction()%0a%25hlt php%25@@InsertEditFunction($newfn, $where='%3cPostPage')@@%0a%0aThis function makes it easy for recipe authors to insert a custom function in a specific position of the processing, see $EditFunctions and [[#UpdatePage|UpdatePage()]]. %0a%0aThe first argument is the name of the new function.%0a%0aThe second argument is the position where to place the new function, related to other edit functions? It can be:%0a* @@"%3c"@@ at the start, before the first edit function%0a* @@">"@@ at the end, after the last edit function%0a* @@"%3cExistingEditFunction"@@ before a specified edit function%0a* @@">ExistingEditFunction"@@ after a specified edit function%0a%0aThe function will return ''true'' on success, and ''false'' on failure (when the specified position or existing function was not recognized).%0a%0a!! [[#DisableSkinParts]] DisableSkinParts()%0a%25hlt php%25@@DisableSkinParts('parts to disable');@@%0a%0aThis function allows easy disabling of the skin sections header, footer, title, actions, and sidebars, like the corresponding directives %25pmhlt%25@@[=(:notitle:) (:noleft:)=]@@ etc. In your function, use something like:%0a->%25hlt php%25[@%0a DisableSkinParts('Left Header Footer Action Title');%0a@]%0a%0a!! [[#ParseArgs]] ParseArgs()%0aSee Cookbook:ParseArgs. %0a%0a!! [[#Redirect]] Redirect()%0a%0a!! [[#PageIndexTerms]] PageIndexTerms()%0a%0a!! [[#AsSpaced]] AsSpacedUTF8(), AsSpaced()%0a>>hlt php%3c%3c%0a@@AsSpaced()@@ is declared in @@pmwiki.php@@ \\%0a@@AsSpaced()@@ converts a string with WikiWords into a spaced version of that string.%0aIt can be overridden via $AsSpacedFunction, as it is in @@AsSpacedUTF8()@@. \\%0a@@AsSpacedUTF8()@@ is declared in the @@xlpage-utf-8.php@@ script.%0a>>%3c%3c%0a%0aCategories: [[!PmWiki Developer]]
+time=1714125000
diff --git a/wikilib.d/PmWiki.Links b/wikilib.d/PmWiki.Links
index 4cb9e886..51809777 100644
--- a/wikilib.d/PmWiki.Links
+++ b/wikilib.d/PmWiki.Links
@@ -1,9 +1,9 @@
-version=pmwiki-2.3.13 ordered=1 urlencoded=1
+version=pmwiki-2.3.33 ordered=1 urlencoded=1
author=Petko
charset=UTF-8
-csum=fix signature markup; NEVER suggest modifying pmwiki.php or other core files (-35)
+csum= %25item pmhlt%25 for many highlighted markups in the same item (+10)
name=PmWiki.Links
-rev=240
+rev=241
targets=PmWiki.WikiSandbox,PmWiki.BasicEditing,Main.WikiSandbox,Main.HomePage,PmWiki.WikiWikiWeb,PmWiki.Installation,PmWiki.WikiWord,PmWiki.LinkVariables,PmWiki.Links,PmWiki.InterMap,PmWiki.NonexistentPages,PmWiki.CreatingNewPages,PmWiki.WikiGroup,PmWiki.Categories,Profiles.Author,PmWiki.LayoutVariables,PmWiki.PageSections,Cookbook.FixURL,Cookbook.DirList,PmWiki.Robots,Cookbook.PopupWindow,Cookbook.DeObMail,Cookbook.AddUrlSchemes,PmWiki.PageLists,PmWiki.LinkSchemes,Cookbook.ExternalLinks,PmWiki.Images,PmWiki.ConditionalMarkup,Cookbook.Footnotes
-text=(:Summary:Multiple mechanisms for creating links:)%0a(:Audience: authors (basic) :)%0aA key feature of [[wiki(WikiWeb)]]-based systems is the ease of creating %25newwin%25[[Wikipedia:Hyperlink|hyperlinks]]%25%25 (or short '''links''') in the text of a document. %0aPmWiki provides multiple mechanisms for creating such links.%0a%0a!! [[#links]]Links to other pages in the wiki%0a%0aTo create an internal link to another page, simply enclose the name of the page inside double square brackets, as in %25pmhlt%25[@[[wiki sandbox]]@] or %25pmhlt%25[@[[installation]]@]. This results in links to [[wiki sandbox]] and [[installation]], respectively.%0a%0aPmWiki creates a link by using the text inside the double brackets. It does this by removing spaces between the words, and automatically capitalizing the first letter of each word following spaces or other punctuation (like ~). Thus %25pmhlt%25[@[[Wiki Sandbox]]@], [@[[wiki sandbox]]@], and [@[[WikiSandbox]]@] all display differently but create the same link to the page titled [@WikiSandbox@].%0aOr in other words, PmWiki will automatically create the "link path name" using the page name in ''CamelCase'', but the "link text" will display in the format you have entered it.%0a%0aSome PmWiki sites (default not) will recognize words written in CamelCase, called a [[WikiWord]], automatically as a link to a page of the same name.%0a%0a!!! [[#othertext]]Links with different link text%0a%0aThere are three ways to get a different link text:%0a%0a#'''Hide link text'''. Link text within (parentheses) will not be not displayed, so that %25pmhlt%25[@[[(wiki) sandbox]]@] links to ''[=WikiSandbox=]'' but displays as [[(wiki) sandbox]]. For addresses actually containing parentheses, use %2528 and %2529 [[https://www.example.com/linkwith%2528parenthese%2529]].%0a%0a#'''Change link text'''. You can specify another link text after a vertical brace, as in %25pmhlt%25[@[[WikiSandbox | a play area]]@], or you can use an arrow ([@->@]) to reverse the order of the link text and the target, as in [@[[a play area -> WikiSandbox]]@]. Both links displays as [[a play area -> WikiSandbox]].%0a%0a#'''Show page title instead of page name'''. The use of special characters in the page name is not a problem for PmWiki, but on some servers it may be better to use only plain A-Z letters for the page "name" (which is also a filename), and set the page "title" to the extended or international characters with the %25pmhlt%25[@(:title PageTitle:)@] directive within the page. The page title can be shown instead of the page name with the [@[[PageName|+]]@] link markup, e.g. page [@BasicEditing@] contains the directive [=(:title=] {BasicEditing$Title}:) with the result that a link written as [@[[BasicEditing|+]]@] will display as [[BasicEditing|+]]. [-See also $EnableLinkPlusTitlespaced.-]\\%0aSince PmWiki version 2.2.14 this works also for those technical pages that have an entry in the XLPage, without the need to add the [=(:title PageTitleName:)=] directive within that page (for more details see [[(PmWikiHome:Localization.)Localization]]).%0a%0aOn top of above ways, a suffix can be added to the end of a link, which becomes part of the link text but not of the target page name.\\%0a'''Note:''' This feature works with the %25pmhlt%25[@[[PageName|+]]@] markup only since Version 2.2.90.%0a%0a[[#markupheaders]]%0a(:table class='markup horiz' align='center':)%0a(:cellnr class='markup1':)%0a[-'''What to type'''-]%0a(:cell class='markup2':)%0a[-'''What it looks like'''-]%0a(:tableend:)%0a[[#markupheadersend]]%0a%0a(:markup class=horiz:)%0a* [[(wiki) sandbox]]%0a* [[(wiki) sandbox]]es%0a* [[WikiSandbox | wiki sandbox]],%0a* [[WikiSandbox | wiki sandbox]]es%0a* [[BasicEditing | +]]%0a(:markupend:)%0a%0a!!! [[#tooltiptitle]] Links with tool tip%0aFrom version 2.2.14 PmWiki can show tooltip titles with the following format:%0a: '''external link''' : %25pmhlt%25[@[[https://pmwiki.org"external tool tip title" | external link ]]@], eg [[https://pmwiki.org"external tool tip title" | external link ]] or [[https://pmwiki.org"external tool tip title" ]]%0a: '''internal link''': %25pmhlt%25[@[[Links"internal tool tip title" | internal link ]]@], eg [[Links"internal tool tip title" | internal link ]] or [[Links"internal tool tip title" ]]%0a: '''[[#anchors|Anchor links]]''': %25pmhlt%25[@[[#name"anchor tool tip title"|anchor link text]]@] (since Version 2.2.48), eg [[#name"anchor tool tip title"|anchor link text]] or [[#name"anchor tool tip title"]]%0a: '''[[InterMap]] link''' : %25pmhlt%25[@[[Wikipedia:Wiki"tool tip title"| InterMap link ]]@], eg [[Wikipedia:Wiki"tool tip title"| InterMap link ]] or [[Wikipedia:Wiki"tool tip title" ]]%0a%0a %0a!!! [[#nonexistent]]Links to nonexistent pages%0a%0aLinks to [[nonexistent pages]] are displayed specially, to invite others to create the page.%0aSee [[Creating new pages]] to learn more.%0a%0a!!! [[#othergroup]]Links to pages in other wiki groups%0a%0aLinks as written above are links between pages of the same group. To create a link to a page in another group, add the name of that other group together with a dot or slash as prefix to the page name. For example, links to %25pmhlt%25[@Main/WikiSandbox@] could be written as:%0a%0a(:include {$FullName}#markupheaders#markupheadersend:)%0a%0a(:markup class=horiz:)%0a* [[Main.WikiSandbox]]%0a* [[Main/WikiSandbox]]%0a* [[(Main.Wiki)Sandbox]]%0a* [[Main.WikiSandbox | link text]]%0a* [[Main.WikiSandbox | +]]%0a(:markupend:)%0a%0aTo link to the "default home page" of a group, the name of the page can be omitted:%0a%0a(:markup class=horiz:)%0a* [[Main.]]%0a* [[Main/]]%0a(:markupend:)%0a%0aSee [[Wiki Group]] to learn more about PmWiki groups.%0a%0a!!! [[#categories]]Category links%0a%0aCategories are a way to organize and find related pages. The idea is that every page that falls into a particular subject area should have a link to a shared page containing links to other pages on that subject. These ''shared pages'' are created in the special group [@Category@], and thus these subject areas are called "categories".%0a%0aAdding a page to the category [@Subject@] is simple by adding the %25pmhlt%25[@[[!Subject]]@] markup somewhere on that page. This will create a link to the page [@Category.Subject@]. So [@[[!Subject]]@] is a kind of link shortcut to the page [@Category.Subject@]. See [[Categories]] to learn more.%0a%0a!!! [[#profiles]]User page links -- "signatures"%0a%0aSimilar is %25pmhlt%25[@[[~Author]]@] a link shortcut to the page [@Author@] in the special group [@Profiles@]. PmWiki automatically creates this type of link for the ''current author'', when it encounters three tilde characters ([@~@]) in a row (@@~~[==]~@@) in the page text. The current author is the name found in the "Author" field, when you create or modify a page. The current date and time is appended when four tilde characters in a row are encountered (@@~~[==]~~@@).%0a%0aSo, when the Author field contains "Author":\\%0a%25pmhlt%25@@~~[==]~@@ markup will be replaced by: [[~Author]]\\%0a%25pmhlt%25@@~~[==]~~@@ markup will be replaced by: [[~Author]] October 10, 2010, at 04:50 PM%0a%0aTime format can be modified in local configuration with $CurrentTime.%0a%0a!!! [[#linkshortcuts]]Link shortcuts%0a%0a%25pmhlt%25[@[[PageName|#]]@] creates a [[#reference|reference]] link as shown below'^[[#reference|#]]^'.%0a%0a!!! [[#anchors]]Links to specific locations within a page -- "anchors"%0a%0aTo define a location, or bookmark, within a page to which you may jump directly, use the markup %25pmhlt%25[@[[#name]]@]. This creates an "[[https://www.w3.org/TR/html4/struct/links.html#h-12.2.1|anchor]]" that uniquely identifies that location in the page. Then to have a link jump directly to that anchor, use one of%0a%0a* %25pmhlt%25[@[[#name|link text]]@] within the same page, or%0a* %25pmhlt%25[@[[PageName#name]]@] or [@[[PageName#name|link text]]@] for a location on another page%0a* %25pmhlt%25The form [@[[PageName(#name)]]@] may be useful for hiding the anchor text in a link. %0a%0aFor example, here's a link to the [[#intermaps | Intermaps]] section, below. %0a%0aNotes:%0a* %25red%25The anchor itself [[https://www.w3.org/TR/html4/types.html#type-name|must]] begin with a letter%25%25, '''not a number'''.%0a* %25green%25Valid characters for anchor names%25%25 are letters, digits, dash (-), underscore (_), and the period (.).%0a* A link to an anchor must have the '''same capitalization as the anchor''' itself. %0a* %25pmhlt%25Spaces are not allowed in an anchor: "[@[[#my anchor]]@]" won't work, "[@[[#myanchor]]@]" will.%0a* All anchor names in a page should be unique.%0a%0a%0a!!! [[#sections]]Sections%0aWhile in HTML the purpose of [[#anchors|anchors]] is mostly for jumping to a position in the text, in PmWiki they serve an internal purpose, too: Each anchor also creates a section, because sections are defined as the part of the page between their start anchor and the next anchor. %0aFor more details, see [[PmWiki:Page Sections|Page Sections]].%0a%0a%0a!!! [[#actions]]Links to actions%0a%0aTo link to a specific action for the current page use %25pmhlt%25[@[[{$FullName}?action=actionname|link text]]@].%0a%0aExamples:%0a* %25pmhlt%25[@[[{$FullName}?action=edit|Edit]]@] for editing%0a* %25pmhlt%25[@[[{$FullName}?action=diff|History]]@] for history.%0a%0a!! Links outside the wiki%0a[[#externallinks]]%0a!!! Links to external sites ([=URLs=])%0a%0aLinks to external sites simply begin with a prefix such as 'https:', 'ftp:', etc. Thus %25pmhlt%25[@https://google.com/@] and [@[[https://google.com/]]@] both link to Google. As with the above, an author can specify the link text by using the vertical brace or arrow syntax, as in [@[[https://google.com/ | Google]]@] and [@[[Google -> https://google.com]]@].%0a%0aIf the external link includes (parentheses), escape these using [=%2528=] for "(" and [=%2529=] for ")" : %0a(:markup:)%0a[[https://en.wikipedia.org/wiki/Wiki_%2528disambiguation%2529 | link to "Wiki (disambiguation)" ]]%0a(:markupend:)%0a%0aThe recipe Cookbook:FixURL makes it easy to encode parentheses and other special characters in link addresses.%0a%0a!!! [[#escaped]] Links with special characters%0aTo have any special characters, including quotes, spaces, parentheses and pipes in link addresses escape them using %25pmhlt%25[@[=link address=]@].%0a%0a!!! [[#path]] Links from the wiki to resources on the same website%0a%0aYou can use the %25pmhlt%25[@Path:@] prefix to add links outside of the wiki but on the same website.%0a%0aUse @@[=Path:=]%25blue%25/path/to/resource%25%25@@ with a leading slash for links relative to the website document root as in @@www.example.com%25blue%25/path/to/resource%25%25@@.%0a%0aYou can also define a custom [[InterMap]] prefix to a specific path on your website and use it as a shortcut, for example:%0a%0a Pictures: /assets/pictures/$1%0a%0aThen in a wiki page, use %25pmhlt%25[@Pictures:photo.jpg@] instead of [@Path:/assets/pictures/photo.jpg@] or [@https://www.example.com/assets/pictures/photo.jpg@]%0a%0aSee [[InterMap]] for more information.%0a%0a!!! Links to intranet (local) files%0a%0a'''Not all browsers will follow such links''' (some Internet Explorer versions reportedly follow them). You can link to a file system by including the prefix %25pmhlt%25[@'file:///'@]. So [@file:///S:\ProjPlan.mpp@] and [@[[Shared S drive->file:///S:\]]@] are both valid links. On a Windows file system you may want to use network locations (eg [@file:///\\server1\rootdirectory\subdirectory@]) rather than drive letters which may not be consistent across all users. Not all browsers will follow such links, Internet Explorer does allow them.%0a%0aSee also Cookbook:DirList.%0a%0a!! Link characteristics%0a!!! [[#reference]]Links as References%0a%0aLinks may also be specified as '''References''', so the target appears as an anonymous ''numeric'' reference rather than a ''textual'' reference. The following markup is provided to produce sequential reference numbering within a PmWiki page:%0a%0aFormatting the link as: %25pmhlt%25[@[[https://google.com |#]]@] produces: [[https://google.com |#]] as the link.%0a%0aSubsequent occurrence of the reference link format on the same page will be incremented automatically as per the following example: Entering %25pmhlt%25[@[[https://pmwiki.com |#]]@] produces [[https://pmwiki.com |#]], [@[[#intermaps |#]]@] produces [[#intermaps |#]], and so on for further reference links.%0a%0aBut, it should be noticed that the feature is deliberately kept simple and doesn't work as bibliographic references: this supplemental link %25pmhlt%25[@[[https://pmwiki.com |#]]@] would produces [[https://pmwiki.com |#]] and not reuse the first link definition.%0a%0a!!! [[#intermaps]]Intermaps%0a%0a[[Inter Map]] links are also supported (see [[Inter Map]]). In particular, the %25pmhlt%25[@Path:@] InterMap entry can be used to create links using relative or absolute paths on the current site (e.g., [@Path:../../somedir/foo.html@] or [@Path:/dir/something.gif@]).%0a%0a!!! Links that open a new browser window%0a%0aTo have a link open in another window, use %25pmhlt%25[@%25newwin%25...%25%25@]:%0a%0a* %25pmhlt%25[@%25newwin%25 https://pmichaud.com %25%25@] produces %25newwin%25 https://pmichaud.com %25%25%0a* %25pmhlt%25[@%25newwin%25 [[https://google.com/ | Google]] %25%25@] produces %25newwin%25 [[https://google.com/ | Google]]%25%25%0a* %25pmhlt%25[@%25newwin%25 [[Main.WikiSandbox]] %25%25@] produces %25newwin%25 [[Main.WikiSandbox]]%25%25%0a%0aYou can also specify that links should open in a new window via the %25pmhlt%25[@%25target=_blank%25...%25%25@] attribute:%0a%0a(:markup class=horiz:)%0aThe following link %25target=_blank%25 https://pmichaud.com %25%25%0awill open in a new window.%0a(:markupend:)%0a%0a!!! [[#robots]]Links that are not followed by [[(PmWiki:)robots]]%0a%0aPrefix a link with [=%25rel=nofollow%25=] to advise %25newwin rel=nofollow%25[[https://robotstxt.org/|robots]] and [[https://validator.w3.org/checklink|link checkers]]%25%25 not to follow it.%0a%0a%0a!! Links and CSS classes%0a%0aPmWiki automatically gives classes to several types of links. Among other things, this enables you to format each type differently.%0a%0aNote: This may be an incomplete list.%0a:.selflink:A link to the current page. Useful in sidebars to show "you are here".%0a:.wikilink:A link to another page within the wiki.%0a:.urllink:A link to a page outside the wiki.%0a%0a!! Notes%0a%0a'''Note:''' The default behavior of "+" above can be overridden to display the spaced title, rather than simply the title by adding the following to config.php:%0a $EnableLinkPlusTitlespaced = 1;%0a%0a%0a>>faq%3c%3c [[#faq]]%0a%0aQ: How do I create a link that will open as a new window?%0a%0aA: Use the [@%25newwin%25@] wikistyle, as in:%0a(:markup class=horiz:) [=%25newwin%25 https://example.com/ %25%25=]%0a%0aQ: How do I create a link that will open a new window, and configure that new window?%0a%0aA: This requires javascript. See [[Cookbook:PopupWindow]].%0a%0aQ: How do I place a mailing address in a page?%0a%0aA: Use the [@mailto:@] markup, as in one of the following:%0a%0a(:markup class="horiz":)%0a* mailto:myaddress@example.com%0a* [[mailto:myaddress@example.com]]%0a* [[mailto:myaddress@example.com | email me]]%0a* [[mailto:myaddress@example.com?subject=Some subject | email me]]%0a(:markupend:)%0aThe markup @@[=[[mailto:me@example.=]com?%25red%25cc=%25%25someoneelse@example.com%25red%25&bcc=%25%25else@example.com%25red%25&subject=%25%25Pre-set Subject%25red%25&body=%25%25Pre-set body | display text]]@@ lets you specify more parameters like the message body and more recipients (may not work in all browsers and e-mail clients).%0a%0aSee also [[Cookbook:DeObMail]] for information on protecting email addresses from spammers.%0a%0aQ: How can I enable links to other protocols, such as nntp:, ssh:, xmpp:, etc?%0a%0aA: See [[Cookbook:Add Url schemes]] {Cookbook.AddUrlSchemes$:Summary}%0a%0aQ: How do I make a WikiWord link to an external page instead of a WikiPage?%0a%0aA: Use link markup. There are two formats:%0a%0a->%25pmhlt%25[@[[https://example.com/ | WikiWord]]%0a[[WikiWord -> https://example.com/]]@]%0a%0aQ: How do I find all of the pages that link to another page (i.e., backlinks)?%0a%0aA: In the wiki search form, use @@link=Group.Page@@ to find all pages linking to Group.Page.%0a%0aA: Use the %25pmhlt%25[@link=@] option of the [[[@(:pagelist:)@] directive -> PmWiki/PageLists#pagelistlink]], as in%0a%0a->%25pmhlt%25[@(:pagelist link=SomePage list=all:) -- show all links to SomePage%0a(:pagelist link={$FullName} list=all:) -- show all links to the current page@]%0a%0aNote that (with a few exceptions) includes, conditionals, pagelists, searchresults, wikitrails, and redirects are not evaluated for Wikilinks, and so any links they put on the page will not be found as backlinks. All other directives and markup, for example links brought to the page by (:pmform:), will be found.%0a%0aQ: What link schemes does PmWiki support?%0aA: See [[PmWiki:Link schemes]] {PmWiki.LinkSchemes$:Summary}%0a%0aQ: How do I open external links in a new window or mark them with an icon?%0aA: See [[Cookbook:External links]] {Cookbook.ExternalLinks$:Summary}%0a%0aQ: How can I use an image as a link?%0aA: Use [=[[Page| Attach:image.jpg ]] or [[ https://site | https://site/image.jpg ]]=] See [[PmWiki/Images#links]]%0a%0aQ: Why my browser does not follow local file:// links?%0aA: For security reasons, most browsers will only enable file:// links if the page containing the link is itself on the local drive. In other words, most browsers do not allow links to file:// from pages that were fetched using https:// such as in a PmWiki site. See also Cookbook:DirList for a workaround.%0a%0aQ: How links to the first existed page ? for example [@ [[Group1.Page Group2.Page|Page]] @]%0aA: See [[PmWiki/ConditionalMarkup]]%0a->%25pmhlt%25[@(:if exists Group1.Page:)%0a [[Group1.Page|Page]]%0a(:elseif exists Group2.Page:)%0a [[Group2.Page|Page]]%0a(:ifend:)@]%0a%0aQ: How do I make [[#reference|Reference]] links also show up on the bottom of the page like Wikipedia? Or, how do I list all links on a page?%0a%0aA: See Cookbook:Footnotes.
-time=1666755651
+text=(:Summary:Multiple mechanisms for creating links:)%0a(:Audience: authors (basic) :)%0aA key feature of [[wiki(WikiWeb)]]-based systems is the ease of creating %25newwin%25[[Wikipedia:Hyperlink|hyperlinks]]%25%25 (or short '''links''') in the text of a document. %0aPmWiki provides multiple mechanisms for creating such links.%0a%0a!! [[#links]]Links to other pages in the wiki%0a%0aTo create an internal link to another page, simply enclose the name of the page inside double square brackets, as in %25pmhlt%25[@[[wiki sandbox]]@] or %25pmhlt%25[@[[installation]]@]. This results in links to [[wiki sandbox]] and [[installation]], respectively.%0a%0aPmWiki creates a link by using the text inside the double brackets. It does this by removing spaces between the words, and automatically capitalizing the first letter of each word following spaces or other punctuation (like ~). Thus %25pmhlt%25[@[[Wiki Sandbox]]@], [@[[wiki sandbox]]@], and [@[[WikiSandbox]]@] all display differently but create the same link to the page titled [@WikiSandbox@].%0aOr in other words, PmWiki will automatically create the "link path name" using the page name in ''CamelCase'', but the "link text" will display in the format you have entered it.%0a%0aSome PmWiki sites (default not) will recognize words written in CamelCase, called a [[WikiWord]], automatically as a link to a page of the same name.%0a%0a!!! [[#othertext]]Links with different link text%0a%0aThere are three ways to get a different link text:%0a%0a#'''Hide link text'''. Link text within (parentheses) will not be not displayed, so that %25pmhlt%25[@[[(wiki) sandbox]]@] links to ''[=WikiSandbox=]'' but displays as [[(wiki) sandbox]]. For addresses actually containing parentheses, use %2528 and %2529 [[https://www.example.com/linkwith%2528parenthese%2529]].%0a%0a#'''Change link text'''. You can specify another link text after a vertical brace, as in %25pmhlt%25[@[[WikiSandbox | a play area]]@], or you can use an arrow ([@->@]) to reverse the order of the link text and the target, as in [@[[a play area -> WikiSandbox]]@]. Both links displays as [[a play area -> WikiSandbox]].%0a%0a# %25item pmhlt%25 '''Show page title instead of page name'''. The use of special characters in the page name is not a problem for PmWiki, but on some servers it may be better to use only plain A-Z letters for the page "name" (which is also a filename), and set the page "title" to the extended or international characters with the [@(:title PageTitle:)@] directive within the page. The page title can be shown instead of the page name with the [@[[PageName|+]]@] link markup, e.g. page [@BasicEditing@] contains the directive @@[=(:title=] {BasicEditing$Title}:)@@ with the result that a link written as [@[[BasicEditing|+]]@] will display as [[BasicEditing|+]]. [-See also $EnableLinkPlusTitlespaced.-]\\%0aSince PmWiki version 2.2.14 this works also for those technical pages that have an entry in the XLPage, without the need to add the [=(:title PageTitleName:)=] directive within that page (for more details see [[(PmWikiHome:Localization.)Localization]]).%0a%0aOn top of above ways, a suffix can be added to the end of a link, which becomes part of the link text but not of the target page name.\\%0a'''Note:''' This feature works with the %25pmhlt%25[@[[PageName|+]]@] markup only since Version 2.2.90.%0a%0a[[#markupheaders]]%0a(:table class='markup horiz' align='center':)%0a(:cellnr class='markup1':)%0a[-'''What to type'''-]%0a(:cell class='markup2':)%0a[-'''What it looks like'''-]%0a(:tableend:)%0a[[#markupheadersend]]%0a%0a(:markup class=horiz:)%0a* [[(wiki) sandbox]]%0a* [[(wiki) sandbox]]es%0a* [[WikiSandbox | wiki sandbox]]%0a* [[WikiSandbox | wiki sandbox]]es%0a* [[BasicEditing | +]]%0a(:markupend:)%0a%0a!!! [[#tooltiptitle]] Links with tool tip%0aFrom version 2.2.14 PmWiki can show tooltip titles with the following format:%0a: '''external link''' : %25pmhlt%25[@[[https://pmwiki.org"external tool tip title" | external link ]]@], eg [[https://pmwiki.org"external tool tip title" | external link ]] or [[https://pmwiki.org"external tool tip title" ]]%0a: '''internal link''': %25pmhlt%25[@[[Links"internal tool tip title" | internal link ]]@], eg [[Links"internal tool tip title" | internal link ]] or [[Links"internal tool tip title" ]]%0a: '''[[#anchors|Anchor links]]''': %25pmhlt%25[@[[#name"anchor tool tip title"|anchor link text]]@] (since Version 2.2.48), eg [[#name"anchor tool tip title"|anchor link text]] or [[#name"anchor tool tip title"]]%0a: '''[[InterMap]] link''' : %25pmhlt%25[@[[Wikipedia:Wiki"tool tip title"| InterMap link ]]@], eg [[Wikipedia:Wiki"tool tip title"| InterMap link ]] or [[Wikipedia:Wiki"tool tip title" ]]%0a%0a %0a!!! [[#nonexistent]]Links to nonexistent pages%0a%0aLinks to [[nonexistent pages]] are displayed specially, to invite others to create the page.%0aSee [[Creating new pages]] to learn more.%0a%0a!!! [[#othergroup]]Links to pages in other wiki groups%0a%0aLinks as written above are links between pages of the same group. To create a link to a page in another group, add the name of that other group together with a dot or slash as prefix to the page name. For example, links to %25pmhlt%25[@Main/WikiSandbox@] could be written as:%0a%0a(:include {$FullName}#markupheaders#markupheadersend:)%0a%0a(:markup class=horiz:)%0a* [[Main.WikiSandbox]]%0a* [[Main/WikiSandbox]]%0a* [[(Main.Wiki)Sandbox]]%0a* [[Main.WikiSandbox | link text]]%0a* [[Main.WikiSandbox | +]]%0a(:markupend:)%0a%0aTo link to the "default home page" of a group, the name of the page can be omitted:%0a%0a(:markup class=horiz:)%0a* [[Main.]]%0a* [[Main/]]%0a(:markupend:)%0a%0aSee [[Wiki Group]] to learn more about PmWiki groups.%0a%0a!!! [[#categories]]Category links%0a%0aCategories are a way to organize and find related pages. The idea is that every page that falls into a particular subject area should have a link to a shared page containing links to other pages on that subject. These ''shared pages'' are created in the special group [@Category@], and thus these subject areas are called "categories".%0a%0aAdding a page to the category [@Subject@] is simple by adding the %25pmhlt%25[@[[!Subject]]@] markup somewhere on that page. This will create a link to the page [@Category.Subject@]. So [@[[!Subject]]@] is a kind of link shortcut to the page [@Category.Subject@]. See [[Categories]] to learn more.%0a%0a!!! [[#profiles]]User page links -- "signatures"%0a%0aSimilar is %25pmhlt%25[@[[~Author]]@] a link shortcut to the page [@Author@] in the special group [@Profiles@]. PmWiki automatically creates this type of link for the ''current author'', when it encounters three tilde characters ([@~@]) in a row (@@~~[==]~@@) in the page text. The current author is the name found in the "Author" field, when you create or modify a page. The current date and time is appended when four tilde characters in a row are encountered (@@~~[==]~~@@).%0a%0aSo, when the Author field contains "Author":\\%0a%25pmhlt%25@@~~[==]~@@ markup will be replaced by: [[~Author]]\\%0a%25pmhlt%25@@~~[==]~~@@ markup will be replaced by: [[~Author]] October 10, 2010, at 04:50 PM%0a%0aTime format can be modified in local configuration with $CurrentTime.%0a%0a!!! [[#linkshortcuts]]Link shortcuts%0a%0a%25pmhlt%25[@[[PageName|#]]@] creates a [[#reference|reference]] link as shown below'^[[#reference|#]]^'.%0a%0a!!! [[#anchors]]Links to specific locations within a page -- "anchors"%0a%0aTo define a location, or bookmark, within a page to which you may jump directly, use the markup %25pmhlt%25[@[[#name]]@]. This creates an "[[https://www.w3.org/TR/html4/struct/links.html#h-12.2.1|anchor]]" that uniquely identifies that location in the page. Then to have a link jump directly to that anchor, use one of%0a%0a* %25pmhlt%25[@[[#name|link text]]@] within the same page, or%0a* %25pmhlt%25[@[[PageName#name]]@] or [@[[PageName#name|link text]]@] for a location on another page%0a* %25pmhlt%25The form [@[[PageName(#name)]]@] may be useful for hiding the anchor text in a link. %0a%0aFor example, here's a link to the [[#intermaps | Intermaps]] section, below. %0a%0aNotes:%0a* %25red%25The anchor itself [[https://www.w3.org/TR/html4/types.html#type-name|must]] begin with a letter%25%25, '''not a number'''.%0a* %25green%25Valid characters for anchor names%25%25 are letters, digits, dash (-), underscore (_), and the period (.).%0a* A link to an anchor must have the '''same capitalization as the anchor''' itself. %0a* %25pmhlt%25Spaces are not allowed in an anchor: "[@[[#my anchor]]@]" won't work, "[@[[#myanchor]]@]" will.%0a* All anchor names in a page should be unique.%0a%0a%0a!!! [[#sections]]Sections%0aWhile in HTML the purpose of [[#anchors|anchors]] is mostly for jumping to a position in the text, in PmWiki they serve an internal purpose, too: Each anchor also creates a section, because sections are defined as the part of the page between their start anchor and the next anchor. %0aFor more details, see [[PmWiki:Page Sections|Page Sections]].%0a%0a%0a!!! [[#actions]]Links to actions%0a%0aTo link to a specific action for the current page use %25pmhlt%25[@[[{$FullName}?action=actionname|link text]]@].%0a%0aExamples:%0a* %25pmhlt%25[@[[{$FullName}?action=edit|Edit]]@] for editing%0a* %25pmhlt%25[@[[{$FullName}?action=diff|History]]@] for history.%0a%0a!! Links outside the wiki%0a[[#externallinks]]%0a!!! Links to external sites ([=URLs=])%0a%0aLinks to external sites simply begin with a prefix such as 'https:', 'ftp:', etc. Thus %25pmhlt%25[@https://google.com/@] and [@[[https://google.com/]]@] both link to Google. As with the above, an author can specify the link text by using the vertical brace or arrow syntax, as in [@[[https://google.com/ | Google]]@] and [@[[Google -> https://google.com]]@].%0a%0aIf the external link includes (parentheses), escape these using [=%2528=] for "(" and [=%2529=] for ")" : %0a(:markup:)%0a[[https://en.wikipedia.org/wiki/Wiki_%2528disambiguation%2529 | link to "Wiki (disambiguation)" ]]%0a(:markupend:)%0a%0aThe recipe Cookbook:FixURL makes it easy to encode parentheses and other special characters in link addresses.%0a%0a!!! [[#escaped]] Links with special characters%0aTo have any special characters, including quotes, spaces, parentheses and pipes in link addresses escape them using %25pmhlt%25[@[=link address=]@].%0a%0a!!! [[#path]] Links from the wiki to resources on the same website%0a%0aYou can use the %25pmhlt%25[@Path:@] prefix to add links outside of the wiki but on the same website.%0a%0aUse @@[=Path:=]%25blue%25/path/to/resource%25%25@@ with a leading slash for links relative to the website document root as in @@www.example.com%25blue%25/path/to/resource%25%25@@.%0a%0aYou can also define a custom [[InterMap]] prefix to a specific path on your website and use it as a shortcut, for example:%0a%0a Pictures: /assets/pictures/$1%0a%0aThen in a wiki page, use %25pmhlt%25[@Pictures:photo.jpg@] instead of [@Path:/assets/pictures/photo.jpg@] or [@https://www.example.com/assets/pictures/photo.jpg@]%0a%0aSee [[InterMap]] for more information.%0a%0a!!! Links to intranet (local) files%0a%0a'''Not all browsers will follow such links''' (some Internet Explorer versions reportedly follow them). You can link to a file system by including the prefix %25pmhlt%25[@'file:///'@]. So [@file:///S:\ProjPlan.mpp@] and [@[[Shared S drive->file:///S:\]]@] are both valid links. On a Windows file system you may want to use network locations (eg [@file:///\\server1\rootdirectory\subdirectory@]) rather than drive letters which may not be consistent across all users. Not all browsers will follow such links, Internet Explorer does allow them.%0a%0aSee also Cookbook:DirList.%0a%0a!! Link characteristics%0a!!! [[#reference]]Links as References%0a%0aLinks may also be specified as '''References''', so the target appears as an anonymous ''numeric'' reference rather than a ''textual'' reference. The following markup is provided to produce sequential reference numbering within a PmWiki page:%0a%0aFormatting the link as: %25pmhlt%25[@[[https://google.com |#]]@] produces: [[https://google.com |#]] as the link.%0a%0aSubsequent occurrence of the reference link format on the same page will be incremented automatically as per the following example: Entering %25pmhlt%25[@[[https://pmwiki.com |#]]@] produces [[https://pmwiki.com |#]], [@[[#intermaps |#]]@] produces [[#intermaps |#]], and so on for further reference links.%0a%0aBut, it should be noticed that the feature is deliberately kept simple and doesn't work as bibliographic references: this supplemental link %25pmhlt%25[@[[https://pmwiki.com |#]]@] would produces [[https://pmwiki.com |#]] and not reuse the first link definition.%0a%0a!!! [[#intermaps]]Intermaps%0a%0a[[Inter Map]] links are also supported (see [[Inter Map]]). In particular, the %25pmhlt%25[@Path:@] InterMap entry can be used to create links using relative or absolute paths on the current site (e.g., [@Path:../../somedir/foo.html@] or [@Path:/dir/something.gif@]).%0a%0a!!! Links that open a new browser window%0a%0aTo have a link open in another window, use %25pmhlt%25[@%25newwin%25...%25%25@]:%0a%0a* %25pmhlt%25[@%25newwin%25 https://pmichaud.com %25%25@] produces %25newwin%25 https://pmichaud.com %25%25%0a* %25pmhlt%25[@%25newwin%25 [[https://google.com/ | Google]] %25%25@] produces %25newwin%25 [[https://google.com/ | Google]]%25%25%0a* %25pmhlt%25[@%25newwin%25 [[Main.WikiSandbox]] %25%25@] produces %25newwin%25 [[Main.WikiSandbox]]%25%25%0a%0aYou can also specify that links should open in a new window via the %25pmhlt%25[@%25target=_blank%25...%25%25@] attribute:%0a%0a(:markup class=horiz:)%0aThe following link %25target=_blank%25 https://pmichaud.com %25%25%0awill open in a new window.%0a(:markupend:)%0a%0a!!! [[#robots]]Links that are not followed by [[(PmWiki:)robots]]%0a%0aPrefix a link with [=%25rel=nofollow%25=] to advise %25newwin rel=nofollow%25[[https://robotstxt.org/|robots]] and [[https://validator.w3.org/checklink|link checkers]]%25%25 not to follow it.%0a%0a%0a!! Links and CSS classes%0a%0aPmWiki automatically gives classes to several types of links. Among other things, this enables you to format each type differently.%0a%0aNote: This may be an incomplete list.%0a:.selflink:A link to the current page. Useful in sidebars to show "you are here".%0a:.wikilink:A link to another page within the wiki.%0a:.urllink:A link to a page outside the wiki.%0a%0a!! Notes%0a%0a'''Note:''' The default behavior of "+" above can be overridden to display the spaced title, rather than simply the title by adding the following to config.php:%0a $EnableLinkPlusTitlespaced = 1;%0a%0a%0a>>faq%3c%3c [[#faq]]%0a%0aQ: How do I create a link that will open as a new window?%0a%0aA: Use the [@%25newwin%25@] wikistyle, as in:%0a(:markup class=horiz:) [=%25newwin%25 https://example.com/ %25%25=]%0a%0aQ: How do I create a link that will open a new window, and configure that new window?%0a%0aA: This requires javascript. See [[Cookbook:PopupWindow]].%0a%0aQ: How do I place a mailing address in a page?%0a%0aA: Use the [@mailto:@] markup, as in one of the following:%0a%0a(:markup class="horiz":)%0a* mailto:myaddress@example.com%0a* [[mailto:myaddress@example.com]]%0a* [[mailto:myaddress@example.com | email me]]%0a* [[mailto:myaddress@example.com?subject=Some subject | email me]]%0a(:markupend:)%0aThe markup @@[=[[mailto:me@example.=]com?%25red%25cc=%25%25someoneelse@example.com%25red%25&bcc=%25%25else@example.com%25red%25&subject=%25%25Pre-set Subject%25red%25&body=%25%25Pre-set body | display text]]@@ lets you specify more parameters like the message body and more recipients (may not work in all browsers and e-mail clients).%0a%0aSee also [[Cookbook:DeObMail]] for information on protecting email addresses from spammers.%0a%0aQ: How can I enable links to other protocols, such as nntp:, ssh:, xmpp:, etc?%0a%0aA: See [[Cookbook:Add Url schemes]] {Cookbook.AddUrlSchemes$:Summary}%0a%0aQ: How do I make a WikiWord link to an external page instead of a WikiPage?%0a%0aA: Use link markup. There are two formats:%0a%0a->%25pmhlt%25[@[[https://example.com/ | WikiWord]]%0a[[WikiWord -> https://example.com/]]@]%0a%0aQ: How do I find all of the pages that link to another page (i.e., backlinks)?%0a%0aA: In the wiki search form, use @@link=Group.Page@@ to find all pages linking to Group.Page.%0a%0aA: Use the %25pmhlt%25[@link=@] option of the [[[@(:pagelist:)@] directive -> PmWiki/PageLists#pagelistlink]], as in%0a%0a->%25pmhlt%25[@(:pagelist link=SomePage list=all:) -- show all links to SomePage%0a(:pagelist link={$FullName} list=all:) -- show all links to the current page@]%0a%0aNote that (with a few exceptions) includes, conditionals, pagelists, searchresults, wikitrails, and redirects are not evaluated for Wikilinks, and so any links they put on the page will not be found as backlinks. All other directives and markup, for example links brought to the page by (:pmform:), will be found.%0a%0aQ: What link schemes does PmWiki support?%0aA: See [[PmWiki:Link schemes]] {PmWiki.LinkSchemes$:Summary}%0a%0aQ: How do I open external links in a new window or mark them with an icon?%0aA: See [[Cookbook:External links]] {Cookbook.ExternalLinks$:Summary}%0a%0aQ: How can I use an image as a link?%0aA: Use [=[[Page| Attach:image.jpg ]] or [[ https://site | https://site/image.jpg ]]=] See [[PmWiki/Images#links]]%0a%0aQ: Why my browser does not follow local file:// links?%0aA: For security reasons, most browsers will only enable file:// links if the page containing the link is itself on the local drive. In other words, most browsers do not allow links to file:// from pages that were fetched using https:// such as in a PmWiki site. See also Cookbook:DirList for a workaround.%0a%0aQ: How links to the first existed page ? for example [@ [[Group1.Page Group2.Page|Page]] @]%0aA: See [[PmWiki/ConditionalMarkup]]%0a->%25pmhlt%25[@(:if exists Group1.Page:)%0a [[Group1.Page|Page]]%0a(:elseif exists Group2.Page:)%0a [[Group2.Page|Page]]%0a(:ifend:)@]%0a%0aQ: How do I make [[#reference|Reference]] links also show up on the bottom of the page like Wikipedia? Or, how do I list all links on a page?%0a%0aA: See Cookbook:Footnotes.
+time=1714140268
diff --git a/wikilib.d/PmWiki.MarkupExpressions b/wikilib.d/PmWiki.MarkupExpressions
index 0cfff7f2..0d1de071 100644
--- a/wikilib.d/PmWiki.MarkupExpressions
+++ b/wikilib.d/PmWiki.MarkupExpressions
@@ -1,10 +1,10 @@
-version=pmwiki-2.3.31 ordered=1 urlencoded=1
-author=MFWolff
+version=pmwiki-2.3.33 ordered=1 urlencoded=1
+author=Petko
charset=UTF-8
-csum=typo (+0)
+csum=[[#ftimeformatsend]] (+39)
ctime=1176718061
name=PmWiki.MarkupExpressions
-rev=112
+rev=113
targets=Cookbook.LocalTimes,PmWiki.BasicVariables,PmWiki.LayoutVariables,PmWiki.WikiStyles,PmWiki.PageListTemplates,PmWiki.PageLists,PmWiki.ConditionalMarkup,Cookbook.MarkupExpressionSamples,Cookbook.MarkupExprPlus
-text=(:Summary:String and formatting operations:)%0a(:Audience: authors (advanced) :)%0aThe %25pmhlt%25[@{(...)}@] "expression markup" allows for a variety of string and formatting operations to be performed from within markup. Operations defined by this recipe include ''[[#substr|substr]]'', ''[[#ftime|ftime]]'', ''[[#strlen|strlen]]'', ''[[#rand|rand]]'', ''[[#mod|mod]]'', ''[[#to|toupper / tolower]]'', ''[[#ucfirst|ucfirst]]'', ''[[#ucwords|ucwords]]'', ''[[#pagename|pagename]]'' and ''[[#asspaced|asspaced]]''.%0aMarkup expressions can be [[#nesting|nested]], using the markup [@{(...(...)...)}@].%0a%0a[[#substr]]%0a!! ''substr''%0a%0aThe "substr" expression extracts portions of a string. The arguments are%0a# the string to be processed. Always quote the string to be processed.%0a# the initial position of the substring. Note that the initial position argument is zero-based (i.e., the first character is referenced via a "0").%0a# the number of characters to extract%0a(:markup class="horiz":)%0a {(substr "PmWiki" 2 3)}%0a {(substr "PmWiki" 2)}%0a {(substr "{*$Group}" 2)}%0a {(substr "PmWiki" 0 1)}%0a {(substr "PmWiki" 0 -3)}%0a {(substr "PmWiki" -3)}%0a(:markupend:)%0a%0aTo obtain the last n characters of a string use %25pmhlt%25[@{(substr "string" -n)}@]%0a[[%3c%3c]]%0aTo truncate the last n characters of a string use %25pmhlt%25[@{(substr "string" 0 -n)}@]%0a%0a[[#ftime]]%0a!! ''ftime''%0a%0a"Ftime" expressions are used for date and time formatting. The generic form is%0a%0a->%25pmhlt%25[@{(ftime "fmt" "when")}@]%0a->%25pmhlt%25[@{(ftime fmt="fmt" when="when" tz="tz" locale="locale")}@]%0a%0awhere ''fmt'' is a formatting string and ''when'' is the time to be formatted. The arguments can be in either order and may use the optional "fmt=" and "when=" labels. %0a%0aThe "tz" (time zone) argument allows the setting of a different time zone, only available on installations running PHP 5.1 or newer. See [[https://www.php.net/timezones|the list of supported time zones]], any value not found there will be silently ignored.%0a%0aThe "locale" (language locale) argument allows the time format to be printed in a different language for names of weekdays and months, as long as that language locale is available on the server. You can set different locales to try, separated with commas or spaces, for example "fr_FR.utf8,fr_FR,fr". If none of the listed locales is available, the argument is silently ignored. %0a%0aWith international locales, if you see weird characters, try adding or removing the ".utf8" or ".UTF-8" part of the locale, e.g. try both "fr_FR.utf8" and "fr_FR" to see which one works for you. Wikis with UTF-8 enabled are more likely to need the ".utf8" part.%0a%0aExamples:%0a(:markup class="horiz":)%0a {(ftime)}%0a {(ftime fmt="%25F %25H:%25M")}%0a {(ftime %25Y)}%0a {(ftime fmt=%25T)}%0a {(ftime when=tomorrow)}%0a {(ftime fmt="%25Y-%25m-%25d" yesterday)}%0a {(ftime "+1 week" %25F)}%0a {(ftime fmt=%25D "+1 month")}%0a {(ftime fmt="%25a%25e %25b" when="next week")}%0a {(ftime fmt="%25A, %25d %25B %25Y, %25Hh%25M" locale=fr_FR.utf8 tz=Europe/Paris)}%0a(:markupend:)%0a%0aThe ''fmt'' parameter is whatever is given by "fmt=", the first parameter containing a '%25', or else the site's default. The formatting codes are described at PHP's %25newwin%25 [[https://www.php.net/manual/en/function.strftime.php | strftime]] function. In addition to those, '[=%25o=]' produces the ordinal suffix ("st" for 1st), '[=%25F=]' produces ISO-8601 dates like 2022-10-30, '[=%25s=]' produces Unix timestamps, and '[=%25L=]' produces a format like %25pmhlt%25[@@2022-10-30T01:27:34Z@] which can be displayed in the timezone of the visitor per Cookbook:LocalTimes.%0a%0aSome common formatting strings:%0a%0a [= %25F =] # ISO-8601 dates "{(ftime %25F)}"%0a [= %25s =] # Unix timestamp "{(ftime %25s)}"%0a [= %25H:%25M:%25S =] # time as hh:mm:ss "{(ftime %25H:%25M:%25S)}"%0a [= %25m/%25d/%25Y =] # date as mm/dd/yyyy "{(ftime %25m/%25d/%25Y)}"%0a [= "%25A, %25B %25e%25o, %25Y"=] # in words "{(ftime "%25A, %25B %25e%25o, %25Y")}"%0a%0a(:details summary="All formats, click to toggle":)%0a|| class="simpletable filterable"%0a||! Category ||! Format ||!Description ||!Example ||%0a|| Day || [@%25a@] ||An abbreviated textual representation of the day ||@@Sun@@ through @@Sat@@ ||%0a|| Day || [@%25A@] ||A full textual representation of the day ||@@Sunday@@ through @@Saturday@@ ||%0a|| Day || [@%25d@] ||Two-digit day of the month (with leading zeros) ||@@01@@ to @@31@@ ||%0a|| Day || [@%25e@] ||Day of the month, with a space preceding single digits. ||"@@ 1@@" to "@@31@@" ||%0a|| Day || [@%25j@] ||Day of the year, 3 digits with leading zeros ||@@001@@ to @@366@@ ||%0a|| Day || [@%25u@] ||ISO-8601 numeric representation of the day of the week ||@@1@@ (for Monday) through @@7@@ (for Sunday) ||%0a|| Day || [@%25w@] ||Numeric representation of the day of the week ||@@0@@ (for Sunday) through @@6@@ (for Saturday) ||%0a|| Day || %25red%25[@%25o@]%25%25 ||Ordinal suffix of the date (PmWiki-specific)||@@st@@ in January 1st ||%0a|| Week || [@%25U@] ||Week number of the given year, starting with the first Sunday as the first week ||@@13@@ (for the 13th full week of the year) ||%0a|| Week || [@%25V@] ||ISO-8601:1988 week number of the given year, starting with the first week of the year with at least 4 weekdays, with Monday being the start of the week ||@@01@@ through @@53@@ (where @@53@@ accounts for an overlapping week) ||%0a|| Week || [@%25W@] ||A numeric representation of the week of the year, starting with the first Monday as the first week ||@@46@@ (for the 46th week of the year beginning with a Monday) ||%0a|| Month || [@%25b@] ||Abbreviated month name, based on the locale ||@@Jan@@ through @@Dec@@ ||%0a|| Month || [@%25B@] ||Full month name, based on the locale ||@@January@@ through @@December@@ ||%0a|| Month || [@%25h@] ||Abbreviated month name, based on the locale (an alias of [@%25b@]) ||@@Jan@@ through @@Dec@@ ||%0a|| Month || [@%25m@] ||Two digit representation of the month ||@@01@@ (for January) through @@12@@ (for December) ||%0a|| Year || [@%25C@] ||Two digit representation of the century (year divided by 100, truncated to an integer) ||@@19@@ for the 20th Century ||%0a|| Year || [@%25g@] ||Two digit representation of the year going by ISO-8601:1988 standards (see [@%25V@]) ||@@09@@ for the week of January 6, 2009 ||%0a|| Year || [@%25G@] ||The full four-digit version of [@%25g@] ||%25red%25@@2008@@%25%25 for the week of January 3, %25red%252009%25%25 ||%0a|| Year || [@%25y@] ||Two digit representation of the year ||@@09@@ for 2009, @@79@@ for 1979 ||%0a|| Year || [@%25Y@] ||Four digit representation for the year ||@@2038@@ ||%0a|| Time || [@%25H@] ||Two digit representation of the hour in 24-hour format ||@@00@@ through @@23@@ ||%0a|| Time || [@%25k@] ||Hour in 24-hour format, with a space preceding single digits ||"@@ 0@@" through "@@23@@" ||%0a|| Time || [@%25I@] ||(Uppercase 'i') Two digit representation of the hour in 12-hour format ||@@01@@ through @@12@@ ||%0a|| Time || [@%25l@] ||(Lowercase 'L') Hour in 12-hour format, with a space preceding single digits ||"@@ 1@@" through "@@12@@" ||%0a|| Time || [@%25M@] ||Two digit representation of the minute ||@@00@@ through @@59@@ ||%0a|| Time || [@%25p@] ||UPPER-CASE 'AM' or 'PM' based on the given time ||@@AM@@ for 00:31, PM for 22:23 ||%0a|| Time || [@%25P@] ||lower-case 'am' or 'pm' based on the given time ||@@am@@ for 00:31, pm for 22:23 ||%0a|| Time || [@%25r@] ||Same as "[@%25I:%25M:%25S %25p@]" ||@@09:34:17 PM@@ for 21:34:17 ||%0a|| Time || [@%25R@] ||Same as "[@%25H:%25M@]" ||@@00:35@@ for 12:35 AM, @@16:44@@ for 4:44 PM ||%0a|| Time || [@%25S@] ||Two digit representation of the second ||@@00@@ through @@59@@ ||%0a|| Time || [@%25T@] ||Same as "[@%25H:%25M:%25S@]" ||@@21:34:17@@ for 09:34:17 PM ||%0a|| Time || [@%25X@] ||Preferred time representation based on locale, without the date ||@@03:59:16@@ or @@15:59:16@@ ||%0a|| Time || [@%25z@] ||The time zone offset. ||@@-0500@@ for US Eastern Time ||%0a|| Time || [@%25Z@] ||The time zone abbreviation. ||@@EST@@ for Eastern Time ||%0a|| Date-Time || [@%25c@] ||Preferred date and time stamp based on locale ||@@Tue Feb 5 00:45:10 2009@@ for February 5, 2009 at 12:45:10 AM ||%0a|| Date-Time || [@%25D@] ||Same as "[@%25m/%25d/%25y@]" ||@@02/05/09@@ for February 5, 2009 ||%0a|| Date-Time || [@%25F@] ||Same as "[@%25Y-%25m-%25d@]" ||@@2009-02-05@@ for February 5, 2009 ||%0a|| Date-Time || [@%25s@] ||Unix Epoch Time timestamp ||@@305815200@@ for September 10, 1979 08:40:00 AM ||%0a|| Date-Time || [@%25x@] ||Preferred date representation based on locale, without the time ||@@02/05/09@@ for February 5, 2009 ||%0a|| Date-Time || %25red%25[@%25L@]%25%25 ||Human-readable UTC timestamp which will be displayed formatted either as $TimeFmt or in the local time zone of the visitor per $EnableLocalTimes (PmWiki-specific) ||%25pmhlt%25[@@2022-09-25T11:49:08Z@] ||%0a|| Miscellaneous || [@%25n@] ||A newline character ("@@\n@@") ||-- ||%0a|| Miscellaneous || [@%25t@] ||A Tab character ("@@\t@@") ||-- ||%0a|| Miscellaneous || [@%25%25@] ||A literal percentage character ("@@%25@@") ||-- ||%0a%0aThe "preferred" shortcut formats may show different values depending on whether the IntlDateFormatter PHP functions are enabled, or not -- for consistent results, use the full format you need. The names of months and days may be translated with the @@locale=@@ argument, if that locale is installed on the server.%0a%0a(:detailsend:)%0a%0aNote that if you use an undefined format string such as [@%25q@] or [@%25E@], it will be left unchanged by ''ftime'', but later PmWiki may process it as a [[WikiStyle(s)]] which may be unexpected.%0a%0aThe ''when'' parameter understands many different date %25newwin%25[[https://www.php.net/manual/en/datetime.formats.php|formats]]. The when parameter is whatever is given by "when=", or whatever parameter remains after determining the format parameter. Some examples:%0a%0a 2007-04-11 # ISO-8601 dates%0a 20070411 # dates without hyphens, slashes, or dots%0a 2007-03 # months%0a @1176304315 # Unix timestamps (seconds since 1-Jan-1970 00:00 UTC)%0a now # the current time%0a today # today @ 00:00:00%0a yesterday # yesterday @ 00:00:00%0a "next Monday" # relative dates%0a "last Thursday" # relative dates%0a "-3 days" # three days ago%0a "+2 weeks" # two weeks from now%0a%0a'''Note:''' If you want to convert a Unix timestamp you '''must''' prefix with the @. Thus, %25pmhlt%25[@"{(ftime "%25A, %25B %25d, %25Y" @1231116927)}"@].%0a%0aThe ''when'' parameter uses PHP's %25newwin%25[[https://www.php.net/strtotime | strtotime]] function to convert date strings according to the GNU [[https://www.gnu.org/software/tar/manual/html_node/Date-input-formats.html|date input formats]]; as of this writing it only understands English phrases in date specifications.%0a%0aThe variable $FTimeFmt can be used to override the default date format used by the "ftime" function. The default $FTimeFmt is $TimeFmt.%0a%0a[[#strlen]]%0a!! ''strlen''%0a%0aThe "strlen" expression returns the length of a string. The first argument is the string to be measured.%0a%0a(:markup class="horiz":)%0a {(strlen "{$:Summary}")}%0a(:markupend:)%0a%0a[[#rand]]%0a!! ''rand''%0a%0aThe "rand" expression returns a random integer. The first argument is the minimum number to be returned and the second argument is the maximum number to be returned. If called without the optional min, max arguments rand() returns a pseudo-random integer between 0 and RAND_MAX. If you want a random number between 5 and 15 (inclusive), for example, use (rand 5 15).%0a%0a(:markup class="horiz":)%0a {(rand)}%0a {(rand 1 99)}%0a(:markupend:)%0a%0a[[#mod]]%0a!! ''mod''%0a%0aThe advanced "mod" expression returns the modulo (remainder) of the division of two numbers. It may be used in advanced [[PageList templates]] together with %25pmhlt%25[@{$$PageCount}@] to insert markup every (modulo) entries, for example to create alternate styled "zebra" table rows, or to insert a line/row break. (See also [[PageLists]], [[WikiStyles]] and [[ConditionalMarkup]].)%0a%0a(:markup class="horiz":)[@%0a>>comment%3c%3c%0a%25define=bg1 item bgcolor=#f88%25%0a%25define=bg2 item bgcolor=#ff8%25%0a%25define=bg0 item bgcolor=#8f8%25[=%0a[[#altrows]]%0a* %25bg{(mod {$$PageCount} 3)}%25 {=$Name} ({$$PageCount})%0a[[#altrowsend]]=]%0a>>%3c%3c%0a(:pagelist fmt=#altrows group=PmWiki count=10:)%0a@]%0a%0a[[#to]]%0a!! ''toupper'' / ''tolower''%0a%0aThe "toupper" and "tolower" expressions convert a string into uppercase or lowercase. The first argument is the string to be processed.%0a%0a(:markup class="horiz":)%0a {(toupper "{$:Summary}")}%0a {(tolower "{$:Summary}")}%0a(:markupend:)%0a%0a[[#ucfirst]]%0a[[#ucwords]]%0a!!''ucfirst'' / ''ucwords''%0a%0aThe "ucfirst" expression converts to uppercase the first character of the string, and "ucwords", the first character of each word. The first argument is the string to be processed.%0a%0a(:markup class="horiz":)%0a {(ucfirst "{$:Summary}")}%0a {(ucwords "{$:Summary}")}%0a(:markupend:)%0a%0a%0a[[#pagename]]%0a!! ''pagename''%0a%0aThe "pagename" expression builds a pagename from a string. The first argument is the string to be processed.%0a%0a(:markup class="horiz":)%0a {(pagename "{$:Summary}")}%0a(:markupend:)%0a%0a[[#asspaced]]%0a!! ''asspaced''%0a%0aThe "asspaced" expression formats wikiwords. The first argument is the string to be processed.%0a%0a(:markup class="horiz":)%0a {(asspaced "{$FullName}")}%0a(:markupend:)%0a%0a[[#nesting]]%0a!! Nesting expressions%0a%0aMarkup expressions can be nested. Omit the curly braces for the inner expressions:%0a%0a(:markup class="horiz":)%0a {(tolower (substr "Hello World" 2))}%0a(:markupend:)%0a%0a[[#notes]] %0a!! Notes%0a%0a* For PmWikis version 2.2.33 or older, the string-processing expressions may not work properly on multibyte UTF-8 characters. Newer versions should work fine.%0a%0a!! See also%0a(:pagelist group=PmWiki name=PageVariables,PageTextVariables,ConditionalMarkup fmt=#titlesummary:)%0a* Cookbook:MarkupExpressionSamples — '-custom markup expression samples-'%0a* Cookbook:MarkupExprPlus
-time=1708761313
+text=(:Summary:String and formatting operations:)%0a(:Audience: authors (advanced) :)%0aThe %25pmhlt%25[@{(...)}@] "expression markup" allows for a variety of string and formatting operations to be performed from within markup. Operations defined by this recipe include ''[[#substr|substr]]'', ''[[#ftime|ftime]]'', ''[[#strlen|strlen]]'', ''[[#rand|rand]]'', ''[[#mod|mod]]'', ''[[#to|toupper / tolower]]'', ''[[#ucfirst|ucfirst]]'', ''[[#ucwords|ucwords]]'', ''[[#pagename|pagename]]'' and ''[[#asspaced|asspaced]]''.%0aMarkup expressions can be [[#nesting|nested]], using the markup [@{(...(...)...)}@].%0a%0a[[#substr]]%0a!! ''substr''%0a%0aThe "substr" expression extracts portions of a string. The arguments are%0a# the string to be processed. Always quote the string to be processed.%0a# the initial position of the substring. Note that the initial position argument is zero-based (i.e., the first character is referenced via a "0").%0a# the number of characters to extract%0a(:markup class="horiz":)%0a {(substr "PmWiki" 2 3)}%0a {(substr "PmWiki" 2)}%0a {(substr "{*$Group}" 2)}%0a {(substr "PmWiki" 0 1)}%0a {(substr "PmWiki" 0 -3)}%0a {(substr "PmWiki" -3)}%0a(:markupend:)%0a%0aTo obtain the last n characters of a string use %25pmhlt%25[@{(substr "string" -n)}@]%0a[[%3c%3c]]%0aTo truncate the last n characters of a string use %25pmhlt%25[@{(substr "string" 0 -n)}@]%0a%0a[[#ftime]]%0a!! ''ftime''%0a%0a"Ftime" expressions are used for date and time formatting. The generic form is%0a%0a->%25pmhlt%25[@{(ftime "fmt" "when")}@]%0a->%25pmhlt%25[@{(ftime fmt="fmt" when="when" tz="tz" locale="locale")}@]%0a%0awhere ''fmt'' is a formatting string and ''when'' is the time to be formatted. The arguments can be in either order and may use the optional "fmt=" and "when=" labels. %0a%0aThe "tz" (time zone) argument allows the setting of a different time zone, only available on installations running PHP 5.1 or newer. See [[https://www.php.net/timezones|the list of supported time zones]], any value not found there will be silently ignored.%0a%0aThe "locale" (language locale) argument allows the time format to be printed in a different language for names of weekdays and months, as long as that language locale is available on the server. You can set different locales to try, separated with commas or spaces, for example "fr_FR.utf8,fr_FR,fr". If none of the listed locales is available, the argument is silently ignored. %0a%0aWith international locales, if you see weird characters, try adding or removing the ".utf8" or ".UTF-8" part of the locale, e.g. try both "fr_FR.utf8" and "fr_FR" to see which one works for you. Wikis with UTF-8 enabled are more likely to need the ".utf8" part.%0a%0aExamples:%0a(:markup class="horiz":)%0a {(ftime)}%0a {(ftime fmt="%25F %25H:%25M")}%0a {(ftime %25Y)}%0a {(ftime fmt=%25T)}%0a {(ftime when=tomorrow)}%0a {(ftime fmt="%25Y-%25m-%25d" yesterday)}%0a {(ftime "+1 week" %25F)}%0a {(ftime fmt=%25D "+1 month")}%0a {(ftime fmt="%25a%25e %25b" when="next week")}%0a {(ftime fmt="%25A, %25d %25B %25Y, %25Hh%25M" locale=fr_FR.utf8 tz=Europe/Paris)}%0a(:markupend:)%0a%0aThe ''fmt'' parameter is whatever is given by "fmt=", the first parameter containing a '%25', or else the site's default. The formatting codes are described at PHP's %25newwin%25 [[https://www.php.net/manual/en/function.strftime.php | strftime]] function. In addition to those, '[=%25o=]' produces the ordinal suffix ("st" for 1st), '[=%25F=]' produces ISO-8601 dates like 2022-10-30, '[=%25s=]' produces Unix timestamps, and '[=%25L=]' produces a format like %25pmhlt%25[@@2022-10-30T01:27:34Z@] which can be displayed in the timezone of the visitor per Cookbook:LocalTimes.%0a%0aSome common formatting strings:%0a%0a [= %25F =] # ISO-8601 dates "{(ftime %25F)}"%0a [= %25s =] # Unix timestamp "{(ftime %25s)}"%0a [= %25H:%25M:%25S =] # time as hh:mm:ss "{(ftime %25H:%25M:%25S)}"%0a [= %25m/%25d/%25Y =] # date as mm/dd/yyyy "{(ftime %25m/%25d/%25Y)}"%0a [= "%25A, %25B %25e%25o, %25Y"=] # in words "{(ftime "%25A, %25B %25e%25o, %25Y")}"%0a%0a[[#ftimeformats]]%0a(:details summary="All formats, click to toggle":)%0a|| class="simpletable filterable"%0a||! Category ||! Format ||!Description ||!Example ||%0a|| Day || [@%25a@] ||An abbreviated textual representation of the day ||@@Sun@@ through @@Sat@@ ||%0a|| Day || [@%25A@] ||A full textual representation of the day ||@@Sunday@@ through @@Saturday@@ ||%0a|| Day || [@%25d@] ||Two-digit day of the month (with leading zeros) ||@@01@@ to @@31@@ ||%0a|| Day || [@%25e@] ||Day of the month, with a space preceding single digits. ||"@@ 1@@" to "@@31@@" ||%0a|| Day || [@%25j@] ||Day of the year, 3 digits with leading zeros ||@@001@@ to @@366@@ ||%0a|| Day || [@%25u@] ||ISO-8601 numeric representation of the day of the week ||@@1@@ (for Monday) through @@7@@ (for Sunday) ||%0a|| Day || [@%25w@] ||Numeric representation of the day of the week ||@@0@@ (for Sunday) through @@6@@ (for Saturday) ||%0a|| Day || %25red%25[@%25o@]%25%25 ||Ordinal suffix of the date (PmWiki-specific)||@@st@@ in January 1st ||%0a|| Week || [@%25U@] ||Week number of the given year, starting with the first Sunday as the first week ||@@13@@ (for the 13th full week of the year) ||%0a|| Week || [@%25V@] ||ISO-8601:1988 week number of the given year, starting with the first week of the year with at least 4 weekdays, with Monday being the start of the week ||@@01@@ through @@53@@ (where @@53@@ accounts for an overlapping week) ||%0a|| Week || [@%25W@] ||A numeric representation of the week of the year, starting with the first Monday as the first week ||@@46@@ (for the 46th week of the year beginning with a Monday) ||%0a|| Month || [@%25b@] ||Abbreviated month name, based on the locale ||@@Jan@@ through @@Dec@@ ||%0a|| Month || [@%25B@] ||Full month name, based on the locale ||@@January@@ through @@December@@ ||%0a|| Month || [@%25h@] ||Abbreviated month name, based on the locale (an alias of [@%25b@]) ||@@Jan@@ through @@Dec@@ ||%0a|| Month || [@%25m@] ||Two digit representation of the month ||@@01@@ (for January) through @@12@@ (for December) ||%0a|| Year || [@%25C@] ||Two digit representation of the century (year divided by 100, truncated to an integer) ||@@19@@ for the 20th Century ||%0a|| Year || [@%25g@] ||Two digit representation of the year going by ISO-8601:1988 standards (see [@%25V@]) ||@@09@@ for the week of January 6, 2009 ||%0a|| Year || [@%25G@] ||The full four-digit version of [@%25g@] ||%25red%25@@2008@@%25%25 for the week of January 3, %25red%252009%25%25 ||%0a|| Year || [@%25y@] ||Two digit representation of the year ||@@09@@ for 2009, @@79@@ for 1979 ||%0a|| Year || [@%25Y@] ||Four digit representation for the year ||@@2038@@ ||%0a|| Time || [@%25H@] ||Two digit representation of the hour in 24-hour format ||@@00@@ through @@23@@ ||%0a|| Time || [@%25k@] ||Hour in 24-hour format, with a space preceding single digits ||"@@ 0@@" through "@@23@@" ||%0a|| Time || [@%25I@] ||(Uppercase 'i') Two digit representation of the hour in 12-hour format ||@@01@@ through @@12@@ ||%0a|| Time || [@%25l@] ||(Lowercase 'L') Hour in 12-hour format, with a space preceding single digits ||"@@ 1@@" through "@@12@@" ||%0a|| Time || [@%25M@] ||Two digit representation of the minute ||@@00@@ through @@59@@ ||%0a|| Time || [@%25p@] ||UPPER-CASE 'AM' or 'PM' based on the given time ||@@AM@@ for 00:31, PM for 22:23 ||%0a|| Time || [@%25P@] ||lower-case 'am' or 'pm' based on the given time ||@@am@@ for 00:31, pm for 22:23 ||%0a|| Time || [@%25r@] ||Same as "[@%25I:%25M:%25S %25p@]" ||@@09:34:17 PM@@ for 21:34:17 ||%0a|| Time || [@%25R@] ||Same as "[@%25H:%25M@]" ||@@00:35@@ for 12:35 AM, @@16:44@@ for 4:44 PM ||%0a|| Time || [@%25S@] ||Two digit representation of the second ||@@00@@ through @@59@@ ||%0a|| Time || [@%25T@] ||Same as "[@%25H:%25M:%25S@]" ||@@21:34:17@@ for 09:34:17 PM ||%0a|| Time || [@%25X@] ||Preferred time representation based on locale, without the date ||@@03:59:16@@ or @@15:59:16@@ ||%0a|| Time || [@%25z@] ||The time zone offset. ||@@-0500@@ for US Eastern Time ||%0a|| Time || [@%25Z@] ||The time zone abbreviation. ||@@EST@@ for Eastern Time ||%0a|| Date-Time || [@%25c@] ||Preferred date and time stamp based on locale ||@@Tue Feb 5 00:45:10 2009@@ for February 5, 2009 at 12:45:10 AM ||%0a|| Date-Time || [@%25D@] ||Same as "[@%25m/%25d/%25y@]" ||@@02/05/09@@ for February 5, 2009 ||%0a|| Date-Time || [@%25F@] ||Same as "[@%25Y-%25m-%25d@]" ||@@2009-02-05@@ for February 5, 2009 ||%0a|| Date-Time || [@%25s@] ||Unix Epoch Time timestamp ||@@305815200@@ for September 10, 1979 08:40:00 AM ||%0a|| Date-Time || [@%25x@] ||Preferred date representation based on locale, without the time ||@@02/05/09@@ for February 5, 2009 ||%0a|| Date-Time || %25red%25[@%25L@]%25%25 ||Human-readable UTC timestamp which will be displayed formatted either as $TimeFmt or in the local time zone of the visitor per $EnableLocalTimes (PmWiki-specific) ||%25pmhlt%25[@@2022-09-25T11:49:08Z@] ||%0a|| Miscellaneous || [@%25n@] ||A newline character ("@@\n@@") ||-- ||%0a|| Miscellaneous || [@%25t@] ||A Tab character ("@@\t@@") ||-- ||%0a|| Miscellaneous || [@%25%25@] ||A literal percentage character ("@@%25@@") ||-- ||%0a%0aThe "preferred" shortcut formats may show different values depending on whether the IntlDateFormatter PHP functions are enabled, or not -- for consistent results, use the full format you need. The names of months and days may be translated with the @@locale=@@ argument, if that locale is installed on the server.%0a%0a(:detailsend:)%0a[[#ftimeformatsend]]%0a%0aNote that if you use an undefined format string such as [@%25q@] or [@%25E@], it will be left unchanged by ''ftime'', but later PmWiki may process it as a [[WikiStyle(s)]] which may be unexpected.%0a%0aThe ''when'' parameter understands many different date %25newwin%25[[https://www.php.net/manual/en/datetime.formats.php|formats]]. The when parameter is whatever is given by "when=", or whatever parameter remains after determining the format parameter. Some examples:%0a%0a 2007-04-11 # ISO-8601 dates%0a 20070411 # dates without hyphens, slashes, or dots%0a 2007-03 # months%0a @1176304315 # Unix timestamps (seconds since 1-Jan-1970 00:00 UTC)%0a now # the current time%0a today # today @ 00:00:00%0a yesterday # yesterday @ 00:00:00%0a "next Monday" # relative dates%0a "last Thursday" # relative dates%0a "-3 days" # three days ago%0a "+2 weeks" # two weeks from now%0a%0a'''Note:''' If you want to convert a Unix timestamp you '''must''' prefix with the @. Thus, %25pmhlt%25[@"{(ftime "%25A, %25B %25d, %25Y" @1231116927)}"@].%0a%0aThe ''when'' parameter uses PHP's %25newwin%25[[https://www.php.net/strtotime | strtotime]] function to convert date strings according to the GNU [[https://www.gnu.org/software/tar/manual/html_node/Date-input-formats.html|date input formats]]; as of this writing it only understands English phrases in date specifications.%0a%0aThe variable $FTimeFmt can be used to override the default date format used by the "ftime" function. The default $FTimeFmt is $TimeFmt.%0a%0a[[#strlen]]%0a!! ''strlen''%0a%0aThe "strlen" expression returns the length of a string. The first argument is the string to be measured.%0a%0a(:markup class="horiz":)%0a {(strlen "{$:Summary}")}%0a(:markupend:)%0a%0a[[#rand]]%0a!! ''rand''%0a%0aThe "rand" expression returns a random integer. The first argument is the minimum number to be returned and the second argument is the maximum number to be returned. If called without the optional min, max arguments rand() returns a pseudo-random integer between 0 and RAND_MAX. If you want a random number between 5 and 15 (inclusive), for example, use (rand 5 15).%0a%0a(:markup class="horiz":)%0a {(rand)}%0a {(rand 1 99)}%0a(:markupend:)%0a%0a[[#mod]]%0a!! ''mod''%0a%0aThe advanced "mod" expression returns the modulo (remainder) of the division of two numbers. It may be used in advanced [[PageList templates]] together with %25pmhlt%25[@{$$PageCount}@] to insert markup every (modulo) entries, for example to create alternate styled "zebra" table rows, or to insert a line/row break. (See also [[PageLists]], [[WikiStyles]] and [[ConditionalMarkup]].)%0a%0a(:markup class="horiz":)[@%0a>>comment%3c%3c%0a%25define=bg1 item bgcolor=#f88%25%0a%25define=bg2 item bgcolor=#ff8%25%0a%25define=bg0 item bgcolor=#8f8%25[=%0a[[#altrows]]%0a* %25bg{(mod {$$PageCount} 3)}%25 {=$Name} ({$$PageCount})%0a[[#altrowsend]]=]%0a>>%3c%3c%0a(:pagelist fmt=#altrows group=PmWiki count=10:)%0a@]%0a%0a[[#to]]%0a!! ''toupper'' / ''tolower''%0a%0aThe "toupper" and "tolower" expressions convert a string into uppercase or lowercase. The first argument is the string to be processed.%0a%0a(:markup class="horiz":)%0a {(toupper "{$:Summary}")}%0a {(tolower "{$:Summary}")}%0a(:markupend:)%0a%0a[[#ucfirst]]%0a[[#ucwords]]%0a!!''ucfirst'' / ''ucwords''%0a%0aThe "ucfirst" expression converts to uppercase the first character of the string, and "ucwords", the first character of each word. The first argument is the string to be processed.%0a%0a(:markup class="horiz":)%0a {(ucfirst "{$:Summary}")}%0a {(ucwords "{$:Summary}")}%0a(:markupend:)%0a%0a%0a[[#pagename]]%0a!! ''pagename''%0a%0aThe "pagename" expression builds a pagename from a string. The first argument is the string to be processed.%0a%0a(:markup class="horiz":)%0a {(pagename "{$:Summary}")}%0a(:markupend:)%0a%0a[[#asspaced]]%0a!! ''asspaced''%0a%0aThe "asspaced" expression formats wikiwords. The first argument is the string to be processed.%0a%0a(:markup class="horiz":)%0a {(asspaced "{$FullName}")}%0a(:markupend:)%0a%0a[[#nesting]]%0a!! Nesting expressions%0a%0aMarkup expressions can be nested. Omit the curly braces for the inner expressions:%0a%0a(:markup class="horiz":)%0a {(tolower (substr "Hello World" 2))}%0a(:markupend:)%0a%0a[[#notes]] %0a!! Notes%0a%0a* For PmWikis version 2.2.33 or older, the string-processing expressions may not work properly on multibyte UTF-8 characters. Newer versions should work fine.%0a%0a!! See also%0a(:pagelist group=PmWiki name=PageVariables,PageTextVariables,ConditionalMarkup fmt=#titlesummary:)%0a* Cookbook:MarkupExpressionSamples — '-custom markup expression samples-'%0a* Cookbook:MarkupExprPlus
+time=1714124964
diff --git a/wikilib.d/PmWiki.PmWikiPhilosophy b/wikilib.d/PmWiki.PmWikiPhilosophy
index 9ce9155c..6601def5 100644
--- a/wikilib.d/PmWiki.PmWikiPhilosophy
+++ b/wikilib.d/PmWiki.PmWikiPhilosophy
@@ -1,9 +1,9 @@
-version=pmwiki-2.2.39 ordered=1 urlencoded=1
-author=Anomen
+version=pmwiki-2.3.33 ordered=1 urlencoded=1
+author=simon
charset=UTF-8
-csum=
+csum=update link, size (+107)
name=PmWiki.PmWikiPhilosophy
-rev=62
-targets=PmWiki.PatrickMichaud,PmWiki.Audiences,PmWiki.WikiWikiWeb,PmWiki.CustomMarkup
-text=(:Summary:This page describes some of the ideas that guide the design and implementation of PmWiki:)%0aThis page describes some of the ideas that guide the design and implementation of PmWiki. [[Patrick Michaud]] doesn't claim that anything listed below is an original idea; these are just what drive the development of PmWiki. You're welcome to express your disagreement with anything listed below. [[PmWiki.Audiences]] also describes much of the reasoning behind the ideas given below.%0a%0a[[#favorwriters]]%0a:''1. Favor writers over readers'':At its heart, PmWiki is a collaborative authoring system for hyperlinked documents. It's hard enough to get people (including Pm) to contribute written material; making authors deal with HTML markup and linking issues places more obstacles to active contribution. So, PmWiki aims to make it easier to author documents, even if doing so limits the types of documents being authored.%0a%0a[[#nothtml]]%0a:''2. Don't try to replace HTML'':PmWiki doesn't make any attempt to do everything that can be done in HTML. There are good reasons that people don't use web browsers to edit HTML--it's just not very effective. If you need to be writing lots of funky HTML in a web page, then PmWiki is not what you should be using to create it. What PmWiki does try to do is make it easy to link PmWiki to other "non-wiki" web documents, to embed PmWiki pages inside of complex web pages, and to allow other web documents to easily link to PmWiki.%0a%0a: :This principle also follows from the "favor writers over readers" principle above--every new feature added to PmWiki requires some sort of additional markup to support it. Pretty soon the source document looks pretty ugly and we'd all be better off just writing HTML. %0a%0a: :Another reason for avoiding arbitrary HTML is that ill-formed HTML can cause pages to stop displaying completely, and arbitrary HTML can be a security risk--more so when pages can be created anonymously. See http://www.cert.org/advisories/CA-2000-02.html for more information. %0a%0a[[#avoidfeaturecreep]]%0a:''3. Avoid gratuitous features (or "creeping featurism")'':In general PmWiki features are implemented in response to specific needs, rather than because someone identifies something that "might be useful". In any sort of useful system, it's hard to change a poorly designed feature once people have built a lot of structure based on it. (Need an example? Look at MS-DOS or Windows.) One way to avoid poor design is to resist the temptation to implement something until you have a clearer idea of how it will be used. %0a%0a[[#collaborativemaintenance]]%0a:''4. Support collaborative maintenance of public web pages'':Although this wasn't at all the original intent of PmWiki, it became quickly obvious that [[WikiWikiWeb]] principles could be used to make it easier for groups to collaboratively design and maintain a public web site presence. PmWiki allows individual pages to be password protected, and a couple of local customizations makes it easy to protect large sections of PmWiki pages. Furthermore, in many ways PmWiki provides "style sheets on steroids": you can quickly change the headers, footers, and other elements on a large group of pages without ever having to touch the individual page contents. Finally, it's relatively easy to add [[custom markup]] for specialized applications.%0a%0a[[#easy]]%0a:''5. Be easy to install, configure, and maintain'': With a gzip-compressed file size of just around 400K, uploading PmWiki to your server is a speedy operation. Do a chmod or two, update a few settings in config.php and you should be up and running. PmWiki stores all data in flat files, so there is no need for `MySQL or other utilities. Upgrading is usually a simple matter of copying the latest version's files over the files of your existing PmWiki installation. (One of the biggest reasons for the creation of PmWiki was that other wiki engines at the time required modifications to the distribution files, so admins ended up losing their customizations on every upgrade.)%0a%0a
-time=1340896619
+rev=78
+targets=PmWiki.DesignNotes,PmWiki.PatrickMichaud,PmWiki.Audiences,PmWiki.GroupHeaders,PmWiki.WikiWikiWeb,PmWiki.CustomMarkup,PmWiki.Installation,PmWiki.InitialSetupTasks,PmWiki.Upgrades
+text=(:Summary:This page describes some of the ideas that guide the design and implementation of PmWiki:)%0aThis page describes some of the ideas that guide the [[DesignNotes | design]] and implementation of PmWiki. [[Patrick Michaud]] doesn't claim that anything listed below is an original idea; these are just what drive the development of PmWiki. You're welcome to express your disagreement with anything listed below. [[PmWiki.Audiences]] also describes much of the reasoning behind the ideas given below.%0a%0a[[#favorwriters]]%0a:''1. Favor writers over readers'':At its heart, PmWiki is a collaborative authoring system for hyperlinked documents. It's hard enough to get people (including Pm) to contribute written material; making authors deal with HTML markup and linking issues places more obstacles to active contribution. So, PmWiki aims to make it easier to author documents, even if doing so limits the types of documents being authored.%0a%0a[[#nothtml]]%0a:''2. Don't try to replace HTML'':PmWiki doesn't make any attempt to do everything that can be done in HTML. There are good reasons that people don't use web browsers to edit HTML--it's just not very effective. If you need to be writing lots of funky HTML in a web page, then PmWiki is not what you should be using to create it. What PmWiki does try to do is make it easy to link PmWiki to other "non-wiki" web documents, to embed PmWiki pages inside of complex web pages, and to allow other web documents to easily link to PmWiki.%0a%0a: :This principle also follows from the "favor writers over readers" principle above--every new feature added to PmWiki requires some sort of additional markup to support it. Pretty soon the source document looks pretty ugly and we'd all be better off just writing HTML. %0a%0a: :Another reason for avoiding arbitrary HTML is that ill-formed HTML can cause pages to stop displaying completely, and arbitrary HTML can be a security risk--more so when pages can be created anonymously. See the archived [[https://insights.sei.cmu.edu/library/2000-cert-advisories/ | CERT Advisory for 2000-02]] for more information. %0a%0a[[#avoidfeaturecreep]]%0a:''3. Avoid gratuitous features (or "creeping featurism")'':In general PmWiki features are implemented in response to specific needs, rather than because someone identifies something that "might be useful". In any sort of useful system, it's hard to change a poorly designed feature once people have built a lot of structure based on it. One way to avoid poor design is to resist the temptation to implement something until you have a clearer idea of how it will be used. %0a%0a[[#collaborativemaintenance]]%0a:''4. Support collaborative maintenance of public web pages'':Although this wasn't at all the original intent of PmWiki, it became quickly obvious that [[WikiWikiWeb]] principles could be used to make it easier for groups to collaboratively design and maintain a public web site presence. PmWiki allows individual pages to be password protected, and a couple of local customizations makes it easy to protect large sections of PmWiki pages. Furthermore, in many ways PmWiki provides "style sheets on steroids": you can quickly change the [[GroupHeaders | headers, footers]], and other elements on a large group of pages without ever having to touch the individual page contents. Finally, it's relatively easy to add [[custom markup]] for specialized applications.%0a%0a[[#easy]]%0a:''5. Be easy to install, configure, and maintain'': With a gzip-compressed file size of just around 600K, uploading PmWiki to your server is a speedy operation. Do a chmod or two, [[Installation | update a few settings]] in [[InitialSetupTasks | @@config.php@@]] and you should be up and running. PmWiki stores all data in flat files, so there is no need for `MySQL or other utilities. [[Upgrades | Upgrading]] is usually a simple matter of copying the latest version's files over the files of your existing PmWiki installation. (One of the biggest reasons for the creation of PmWiki was that other wiki engines at the time required modifications to the distribution files, so admins ended up losing their customizations on every upgrade.)%0a%0a
+time=1714158346