h1. rah_function
"Download":https://github.com/gocom/rah_function/releases | "Packagist":https://packagist.org/packages/rah/rah_function | "Issues":https://github.com/gocom/rah_function/issues
Every PHP function and method is a "Textpattern CMS":https://textpattern.com template tag.
h2. Install
Using "Composer":https://getcomposer.org:
bc. $ composer require rah/rah_function
Or "download":https://github.com/gocom/rah_function/releases an installer package.
h2. Basics
bc.
Contained statement
</rah::fn>
The plugin introduces a @@ tag to Textpattern's arsenal. It's a multi-purpose tag that enables using public PHP functions and methods as Textpattern tags.
Rah_function is almost like a bridge between PHP and Textpattern's tag syntax. It allows calling almost any PHP function as a Textpattern tag. Want to encode something? You can. Want use PHP's string functions to truncate, count or otherwise bend strings at your will? You can. All without needing to write any code for new tags or add raw PHP blocks in page templates.
The tag takes a @call@ attribute which sets the function that is called by the tag. If omitted, the first boolean attribute name is used the called function. Apart from a @thing@, all attributes used in a tag are passed to the called PHP function as its arguments in the given order. The tag then processes the request and returns the results.
h2. Attributes
Attributes for @@ are as follows:
call
Name of the function or the class method you want to use with the tag. Comma-separated if multiple. If omitted, the fist boolean attribute is used as the called function instead.
Example: @call="base64_encode"@ Default: @""@
thing
Defines the argument position of a container tag's contained statement. If a @thing@ is the last defined attribute in the tag, then the contained statement is used as the last argument too for the PHP function. If @thing@ is left undefined, the contained statement is used as the first argument.
Example: @foo="bar" thing bar="foo"@ Default: undefined.
_is
Converts the tag into a "conditional":https://docs.textpattern.com/tags/tag-basics/conditional-tags. If set, the tag's results are compared against the value of the @_is@ attribute. If they match, the tag's contained statement is shown.
Example: @_is="FALSE"@ Default: undefined.
_assign
Creates a "variable":https://docs.textpattern.com/tags/variable containing the tag's returned value. The value is used as the variable's name.
Example: @_assign="variable"@ Default: undefined.
parameter1="" , parameter2="" , parameter3="",[..]
Zero or more parameters passed to the called function as arguments. Parameters are assigned to the function in the order they are defined in the tag. These additional tag attributes can be named anything. A valid attribute name can contain letters (A-z) and numbers (0-9). The names @thing@ and @call@ are reserved.
Example: @foo2="bar" foo1="bar" foo4="bar"@ Default: undefined.
h2. Function parameters
Apart from the tag's own reserved attributes, including @thing@ and @call@, all attributes are passed to the called function as arguments in the order in which they are defined. If no additional attributes are used, then the called PHP function is used as is without arguments.
When calling "md5":https://secure.php.net/manual/en/function.md5.php, the first attribute would be used as the string from which a hash is calculated.
bc.
Above returns @1f3870be274f6c49b3e31a0c6728957f@, a MD5 hash of an apple.
h2. Containers and self-closing tags
Rah_function supports both container and self-closing, single tag use.
h3. As a container tag
The tag supports both a container and self-closing usage. When using the tag as a container tag, the contained statement is used in the parameter position specified by the tag's @thing@ attribute. If the @thing@ attribute is undefined, the contained statement is used as the first parameter of the PHP function.
bc.
Hello World!
</rah::fn>
In the snippet above, the contained statement @Hi World!@ is used as the third parameter of the "str_replace":https://secure.php.net/manual/en/function.str-replace.php function because that is where the @thing@ is ordered. The snippet returns @Hello World!@, as expected. If @thing@ attribute wasn't used, the contained statement would be applied as first argument, leading to different results.
bc.
Hello World!
</rah::fn>
Still looks pretty much the same, but unlike the previous example where @thing@ was used, now the tag returns @Hello@. Instead of the @to@ attribute, the contained statement would be used as the searched needle in str_replace.
h3. As a self-closing tag
A container translates seamlessly to a singular self-closing tag. The contained statement is a function parameter just like tag attributes, and as such, can be substituted with a tag attribute. The following does exactly same thing as the previous str_replace examples that used containers.
bc.
These two "htmlspecialchars":http://php.net/manual/en/function.htmlspecialchars.php snippets give the same results, but do it with different syntaxes. As a self-closing tag, a string would be passed to the function as a tag attribute.
bc. <rah::fn htmlspecialchars string="<p class=""msg"">Hello World!
" />
But that string can also be passed as a contained statement. Since the string is htmlspecialchars function's first parameter, the tag doesn't need a @thing@ attribute.
bc.
Hello World!
</rah::fn>
Gives a relatively readable formatting and avoids "quote escaping":https://docs.textpattern.com/tags/tag-basics/parsing-tag-attributes that comes with tag attributes.
h2. Conditionals
A rah_function tag can transform into a conditional by applying the @_is@ attribute. When @_is@ is used, the tag's results are compared against the attribute's value. If they match, the tag's contained statement is shown. If compared values do not match, an "else":https://docs.textpattern.com/tags/else statement is shown, if defined.
bc.
Theme is set as blue.
No blue?
</rah::fn>
The above snippet checks if an HTTP cookie named @theme@ is set as @blue@.
h2. Calling multiple functions at once
Since version 0.5, a single tag can call multiple functions. This allows to further process output returned by a function with a second or more functions. Calling multiple functions with a single tag instance is done by simply using comma-separated (@,@) list of functions in the @call@ attribute.
bc.
Some markup to strip and surrounding white-space to trim.
</rah::fn>
Specified functions are processed from left to right. In the above snippet, "strip_tags":https://secure.php.net/manual/en/function.strip-tags.php is ran first and its output is then passed on to "trim":https://secure.php.net/manual/en/function.trim.php.
The first function in the list acts as the primary one. Its output is passed by reference to the following functions and all tag attributes apply only to it. The second or later functions do not get passed any attributes and the output from the first function is assigned as the consecutive functions' first parameter.
Calling multiple functions works only if the following functions expect a single parameter. If they require more than a one parameter, more than one @@ tag is needed.
Calling both "str_replace":https://secure.php.net/manual/en/function.str-replace.php and "substr":https://secure.php.net/manual/en/function.substr.php would require two tags as both require two or more parameters.
bc.
</rah::fn>
h2. Returned values and legal types
Due to how Textpattern's template language and PHP work, not every function's output can be returned to the template in its original format. The limitation comes in the form of "types":https://secure.php.net/manual/en/language.types.php.
h3. Integers, floats and strings
Textpattern's markup language expects strings, and that is what we must give it. Rah_function returns values of types integer, float and string to the template as is, in their true presentation, with the expectation that the returned type is converted to a string by Textpattern.
h3. Booleans
The last from the scalars, boolean, is converted to an uppercase string @TRUE@ or @FALSE@. This is to allow differentiating an empty string (@""@), numbers @1@, @0@ and booleans from one another, otherwise in Textpattern's template context you would have no idea which is which.
For instance, PHP's "strpos":https://secure.php.net/manual/en/function.strpos.php returns an integer starting from zero or a boolean @FALSE@ when no matches are found. When the output gets converted to a string, that zero and FALSE become the same, and there would be no way of knowing whether there were any matches.
bc.
If no conversion was done, the above would return a zero/empty, but so it would act as if there were no matches. Through the conversion, the position and boolean are distinguishable.
bc..
No matches.
First match at
h3. Arrays
Returned "arrays":https://secure.php.net/manual/en/language.types.array.php will be converted to "JSON":https://secure.php.net/manual/en/function.json-encode.php representations. The following snippet would split the list of values into an array.
bc.
The numeric array returned by "explode":https://secure.php.net/manual/en/function.explode.php would be converted and returned as a literal JavaScript array.
bc. ["value1","value2","value3"]
h3. Discarded
The rest of types, including object, resource, NULL and callable will be discarded and a notice will be issued. Discarding is done to prevent issues. The types that are not returned do not translate to the markup language and are not usable in string context. Thus, they are not returned. While the illegal output will not be returned, the functions will still be executed. For instance, a class method that returns an object can still be executed just fine with rah_function. There just won't be any output apart from a harmless, informative error message.
h2. Type casting and special attribute prefixes
bc.
To get around template language's type juggling limitations, rah_function packs a couple special attribute prefixes. These prefixes can be added before tag attribute names, allowing to cast values to different types before passing the attributes to the called function as arguments. These special attribute prefixes are @_bool@, @_null@, @_int@ and @_array@.
h3. _bool
If a tag attribute is prefixed with @_bool@, the value is converted to a boolean type. The value is converted to @FALSE@ if it is empty (@""@), @0@ or uppercase string @FALSE@. If it's anything else, it becomes @TRUE@.
bc.
h3. _null
The @_null@ prefix converts the value to NULL, no matter what the supplied value is.
bc.
h3. _int
The @_int@ prefix converts the value to integer, ensuring that the value is a safe, valid integer. Numeric values will be rounded towards zero and non-numerical strings will be converted based on the initial portion of the string. If the attribute value starts with valid numeric data, this will be used as the value. Otherwise, the value becomes @0@ (zero).
bc.
h3. _array
The @_array@ prefix is used to generate and pass arrays. An attribute prefixed with an @_array@ takes a "JSON":https://json.org/ string (JavaScript Object Notation) and converts it to a PHP's array.
bc.
h2. Security related features
Considering the plugin's nature, it comes with few options to limit its access. Limiting extends to both what a rah_function tag can do and where the tag can be used. The plugin has a whitelisting option for enabling only certain functions, and it follows Textpattern's PHP evaluation rules and user privileges, the same rules that affect "php":https://docs.textpattern.com/tags/php tags.
h3. Privileges in articles
User group privileges limit which users can use @
@ tags within articles. Only user-groups that have privileges granted access to @article.php@ resource can use the tags in an article body, custom fields or excerpt. By default only the two highest groups, Publishers and Managing Editors (groups with ID 1 and 2) have access to @article.php@ and will be able to publish articles with the plugin's tags in them.
h3. Advanced PHP preferences
Rah_function follows the two PHP options that can be found from Textpattern's "Preferences":https://docs.textpattern.com/administration/preferences-panel panel, *Allow PHP in pages* and *Allow PHP in articles*. When *Allow PHP in pages* option is disabled, a rah_function tag can not be used in a page template or a form partial. When *Allow PHP in articles* option is disabled, rah_function tag can not be used in articles. The tags won't be executed, no matter what permissions the article's author has.
h3. Function whitelisting
For added optional security, certain functions can be explicitly whitelisted. If the whitelisting option is defined, then only those whitelisted functions can be called with a rah_function tag.
Whitelisting options can be set from Textpattern's @config.php@ file. Rah_function expects a constant named @rah_function_whitelist@, populated with a comma-separated list of function names. Function names and class methods should be formatted in the same way as when used in a rah_function tag's @call@ attribute.
bc. define('rah_function_whitelist', 'gps, ps, htmlspecialchars, str_replace, Class::StaticMethod, Class->Method');
Where @gps@, @ps@, @htmlspecialchars@, @str_replace@, @Class::StaticMethod@ and @Class::Method@ would be the allowed functions and class methods.
This whitelisting option is completely optional, and it doesn't need to be configured. It should only be used if you want to enable certain functions for added security.
h2. Examples
h3. Replacing content using str_replace in a single tag mode
bc.
Returns: @Hi world!@
h3. Replacing content using str_replace and containers
A contained statement is used as "str_replace":https://secure.php.net/manual/en/function.str-replace.php's _subject_ parameter. Wrapped content is positioned to the correct location by using @thing@ in the tag.
bc.
Hello world!
Returns: @Hi world!@
h3. Sanitizing and returning HTTP GET value
Returning GET/POST values and sanitizing the output can be done with a single rah_function tag instance by using the plugin's multi-function call feature. First we would use Textpattern's @gps@ function to get a specific value, e.g. @theme@, and then prepare it for the page template by converting HTML's special characters to entities with "htmlspecialchars":https://secure.php.net/manual/en/function.htmlspecialchars.php.
bc.
The above would return HTTP GET/POST param's, named @theme@, value. If the requested value is @?theme=I<3TXP@, the above would return a safe string of @I<3TXP@.
h3. Getting and checking site preferences
Textpattern's @get_pref()@ function can be used to return site's preference settings. Following would return site's production status.
bc.
The above can be used as a conditional by applying @_is@ attribute:
bc.
Site is in debugging mode.
Either in Testing or Live.
h3. Removing, appending and prepending whitespace or other characters
PHP comes with a couple useful functions for removing whitespace and other characters from the beginning and end of a string: "trim":https://secure.php.net/manual/en/function.trim.php, "ltrim":https://secure.php.net/manual/en/function.ltrim.php and "rtrim.":https://secure.php.net/manual/en/function.rtrim.php Trim removes characters from both ends, while ltrim only touches the beginning and rtrim() wants to be all rightful. All three can take up to two arguments. The first one is the string which will be trimmed, and the second, a list of characters that are stripped. If no characters are specified, white-space is stripped.
h4. Stripping zeros from the beginning
Wrapped content is passed to ltrim, which is set to strip zeros (@0@) from the beginning of the string. The original value @000150@ is converted to @150@.
bc.
000150
h4. Stripping whitespace from the beginning and the end
When no extra arguments are given to trim, it will strip any whitespace from the beginning and the end.
bc.
Hello World!
Returns @Hello World!@ without the indentation or linefeed at the end.
h3. Generating a valid JavaScript array
The following example generates a valid "Javascript Array":https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array from a comma-separated list of values. The code splits the values to a PHP array using do_list(). Since the function returns array, rah_function encodes and returns as a valid JSON presentation. Rah_function returns any array as a JSON.
bc.
value1, value2, value3
The above returns @["value1","value2","value3"]@.
h3. Generating a valid JavaScript string
Like in the previous example, encoding non-arrays is possible too. There are couple ways of doing it, if you want an valid and safe JavaScript string. One option is calling @escape_js()@ and other is @json_encode()@. The first one strictly returns valid JavaScript while the latter takes JSON specifications into account.
bc.
Soon to be valid JavaScript string.
Or for JSON:
bc.
Soon to be valid for JSON.
h3. Returning time using safe_strftime()
bc.
%Y
Returns: @2009@.
h3. Fetching a single field from the database with fetch() function
bc.
Returns: Last access time for site admin with user ID of 1.
h3. Counting number of articles
Counting is done with Textpattern's @safe_count()@ function.
bc.
Returns: number of articles.
h2. Changelog
h3. Version 0.8.1 - 2023/02/25
* PHP >= 8.0 compatibility. In PHP 8.0 or greater, the tag attributes would be passed down as named arguments to functions. This would cause fatal error in cases where the names did not match. To mitigate the issue, this release reverts back to pre-8.0 behaviour where the attributes are passed based on their order rather than argument name.
h3. Version 0.8.0 - 2019/04/07
* Register the tag for Textpattern >= 4.7.0 compatibility.
* Called function name can be set with the first boolean attribute if @call@ is omitted.
* Supports boolean attributes as arguments.
* Now requires Textpattern 4.7.0 or newer.
h3. Version 0.7.2 - 2014/03/20
* Fixed: error in composer.json file that prevented the plugin from being installed with Composer.
h3. Version 0.7.1 - 2013/05/06
* Changed: Updated the Composer package to use "textpattern/installer":https://github.com/gocom/textpattern-installer.
h3. Version 0.7.0 - 2013/04/25
* Added: @_constant@ attribute prefix.
* Added: @_assign@ attribute.
* Released as a "composer package":https://packagist.org/packages/rah/rah_function.
h3. Version 0.6 - 2012/07/19
* Updated: Help file (readme). Thanks you, "Ralitza":http://www.inkscar.de/en/.
h3. Version 0.5 - 2012/07/19
* Added: Ability to call class methods (@call="Class->Method"@ and @call="Class::StaticMethod"@).
* Added: Multiple functions can be called with a single tag instance (@call="func1, func2, func3"@). Output is passed by reference from function to function. First function in the list is treated as the primary and given tag attributes only apply to it.
* Added: Arrays are returned as JSON string and can be passed from one tag instance to other. JSON can be used as a value by prefixing used tag attribute name with @_array@.
* Added: Converts returned booleans to uppercase strings, @TRUE@ and @FALSE@. This makes it possible to identify integers from booleans (e.g. strpos).
* Added: Function whitelisting option.
* Improved: Prevent passing non-scalars to the template.
* Improved: Moved away from sanitization and @eval()@. Now uses callbacks.
* Improved: Show some error messages when needed.
* Updated: Help file (readme). Thanks to "Tye":https://github.com/aguatye for help.
h3. Version 0.4 - 2011/12/16
* Improved: Do not use attributes real names in the function call, but use an temp array. Makes sure attributes get resolved as valid variables no matter what is passed by Textpattern's parser to the plugin.
h3. Version 0.3 - 2011/07/08
* Fixed: Now an empty, nothing-at-all string can be used as the container-mode's wrapped statement.
* Added: Now makes sure that the called function is really defined before executing anything.
h3. Version 0.2 - 2009/11/28
* Added attribute: @thing@. Thanks you "Ruud":http://forum.textpattern.com/viewtopic.php?pid=220042#p220042 for the suggestion.
h3. Version 0.1.1 - 2009/11/21
* Added @has_privs()@ and @allow_scripting@ checks.
h3. Version 0.1 - 2009/11/21
* First release