rah / rah_function
每个PHP函数和方法都是一个Textpattern CMS模板标签
Requires
- php: >=5.6.0
- textpattern/installer: *
- textpattern/lock: >=4.7.0
Requires (Dev)
- rah/mtxpc: ^0.9.0
- squizlabs/php_codesniffer: 3.*
README
每个 PHP 函数和方法都是一个 Textpattern CMS 模板标签。
安装
使用 Composer
$ composer require rah/rah_function
或 下载 安装程序包。
基础
<rah::fn function thing parameter1="value" parameter2="value">
Contained statement
</rah::fn>
该插件向Textpattern的标签库中引入了 <rah::fn />
标签。这是一个多用途标签,允许使用公共 PHP 函数和方法作为Textpattern标签。
Rah_function 几乎就像PHP和Textpattern标签语法的桥梁。它允许将几乎任何 PHP 函数作为Textpattern标签调用。想要编码什么?你可以。想要使用PHP的字符串函数截断、计数或以其他方式弯曲字符串?你可以。所有这些都不需要为新的标签编写任何代码或在页面模板中添加原始 PHP 块。
标签接受一个 call
属性,该属性设置由标签调用的函数。如果省略,则使用第一个布尔属性名称作为调用函数。除了 thing
之外,标签中使用的所有属性都按给定顺序作为其参数传递给调用 PHP 函数。然后标签处理请求并返回结果。
属性
<rah::fn />
的属性如下所示
call
您想要与标签一起使用的函数或类方法的名称。如果多个,则用逗号分隔。如果省略,则将第一个布尔属性用作调用函数。
示例:call="base64_encode"
默认:""
thing
定义容器标签包含语句的参数位置。如果 thing
是标签中定义的最后一个属性,则将包含语句用作最后一个参数,用于 PHP 函数。如果 thing
未定义,则将包含语句用作第一个参数。
示例:foo="bar" thing bar="foo"
默认:未定义。
_is
将标签转换为 条件标签。如果设置,则将标签的结果与 _is
属性的值进行比较。如果它们匹配,则显示标签的包含语句。
示例:_is="FALSE"
默认:未定义。
_assign
创建一个包含标签返回值的 变量。值用作变量的名称。
示例:_assign="variable"
默认:未定义。
parameter1="" , parameter2="" , parameter3="",[..]
传递给调用函数作为参数的零个或多个参数。参数按在标签中定义的顺序分配给函数。这些额外的标签属性可以命名任何名称。有效的属性名称可以包含字母(A-z)和数字(0-9)。thing
和 call
名称是保留的。
示例:foo2="bar" foo1="bar" foo4="bar"
默认值:未定义。
函数参数
除了标签本身的保留属性,包括 thing
和 call
,所有属性都按定义的顺序作为参数传递给被调用的函数。如果没有使用额外的属性,则直接使用不带参数的调用 PHP 函数。
在调用 md5 时,第一个属性将用作计算哈希的字符串。
<rah::fn md5 str="apple" />
上述代码返回 1f3870be274f6c49b3e31a0c6728957f
,这是苹果的 MD5 哈希。
容器和自闭合标签
Rah_function 支持容器和自闭合标签的单标签使用。
作为容器标签
该标签支持容器和自闭合用法。当将标签作为容器标签使用时,包含的语句将用作标签的 thing
属性指定的参数位置。如果 thing
属性未定义,则包含的语句将用作 PHP 函数的第一个参数。
<rah::fn str_replace from="Hello" to="Hi" thing>
Hello World!
</rah::fn>
在上面的代码片段中,包含的语句 Hi World!
被用作 str_replace 函数的第三个参数,因为这是 thing
的顺序位置。代码片段返回 Hello World!
,符合预期。如果没有使用 thing
属性,则包含的语句将作为第一个参数应用,从而导致不同的结果。
<rah::fn str_replace from="Hello" to="Hi">
Hello World!
</rah::fn>
看起来几乎一样,但与上一个使用 thing
的例子不同,现在标签返回 Hello
。而不是使用 to
属性,包含的语句将用作 str_replace 中的搜索针。
作为自闭合标签
容器可以无缝转换为单个自闭合标签。包含的语句就像标签属性一样是函数参数,因此可以用标签属性替换。下面的代码与之前的 str_replace 使用容器的例子完全一样。
<rah::fn str_replace from="Hi" to="Hello" string="Hi World!"/>
这两个 htmlspecialchars 代码片段给出了相同的结果,但使用了不同的语法。作为一个自闭合标签,字符串将被作为标签属性传递给函数。
<rah::fn htmlspecialchars string="<p class=""msg"">Hello World!</p>" />
但是,这个字符串也可以作为包含的语句传递。由于字符串是 htmlspecialchars 函数的第一个参数,因此标签不需要 thing
属性。
<rah::fn htmlspecialchars>
<p class="msg">Hello World!</p>
</rah::fn>
提供了一种相对可读的格式化,并避免了标签属性带来的 引号转义 问题。
条件语句
通过应用 _is
属性,rah_function 标签可以转换为条件语句。当使用 _is
时,标签的结果与属性的值进行比较。如果匹配,则显示标签的包含语句。如果不匹配,如果定义了 else 语句,则显示。
<rah::fn cs name="theme" _is="blue">
Theme is set as blue.
<txp:else/>
No blue?
</rah::fn>
上面的代码片段检查名为 theme
的 HTTP Cookie 是否设置为 blue
。
同时调用多个函数
从版本 0.5 开始,单个标签可以调用多个函数。这允许进一步处理函数返回的输出,以便使用第二个或更多函数进行处理。通过在 call
属性中使用逗号分隔(,
)的函数列表,可以同时使用单个标签实例调用多个函数。
<rah::fn call="strip_tags, trim">
<p>Some markup to <strong>strip</strong> and surrounding white-space to trim.</p>
</rah::fn>
指定的函数从左到右处理。在上面的代码片段中,首先运行 strip_tags,然后将其输出传递给 trim。
列表中的第一个函数作为主函数。其输出通过引用传递给后续的函数,所有标签属性仅适用于它。第二个或后续的函数不会传递任何属性,第一个函数的输出被分配为后续函数的第一个参数。
调用多个函数仅当后续的函数期望单个参数时才有效。如果它们需要超过一个参数,则需要多个 <rah::fn />
标签。
同时调用 str_replace 和 substr 需要两个标签,因为这两个函数都需要两个或更多的参数。
<rah::fn str_replace from="Hi" to="Hello">
<rah::fn substr string="Hello World!" start="0" end="7"/>
</rah::fn>
返回值和合法类型
由于 Textpattern 的模板语言和 PHP 的工作方式,并不是每个函数的输出都可以以原始格式返回到模板中。这种限制以 类型 的形式存在。
整数、浮点数和字符串
Textpattern 的标记语言期望字符串,这就是我们必须给出的。Rah_function 以其真正的表现形式返回 整数、浮点数 和 字符串 类型的值到模板中,期望 Textpattern 将返回的类型转换为字符串。
布尔值
标量中的最后一个,布尔值,被转换为大写字符串 TRUE
或 FALSE
。这是为了区分空字符串 (""
)、数字 1
、0
和布尔值,否则在 Textpattern 的模板上下文中,你将无法知道哪个是哪个。
例如,PHP 的 strpos 函数在没有找到匹配项时返回从零开始的整数或布尔值 FALSE
。当输出被转换为字符串时,零和 FALSE 变得相同,将无法知道是否找到了任何匹配项。
<rah::fn strpos value="ABC, zero or false?" search="A"/>
如果没有进行转换,上面的代码将返回零/空,但这样会表现得好像没有找到匹配项。通过转换,位置和布尔值是可区分的。
<rah::fn strpos value="ABC, zero or false?" search="A" _assign="matches"/>
<txp:if_variable name="matches" value="FALSE"> No matches. <txp:else /> First match at <txp:variable name="matches"/> </txp:if_variable>
数组
返回的 数组 将被转换为 JSON 表示形式。以下代码片段会将值的列表拆分为一个数组。
<rah::fn explode delimiter=", " values="value1, value2, value3" />
explode 返回的数字数组将被转换为字面量 JavaScript 数组。
["value1","value2","value3"]
丢弃
其余类型,包括对象、资源、NULL 和可调用函数将被丢弃,并发出通知。丢弃是为了防止问题。不返回的类型不转换为标记语言,也不能在字符串上下文中使用。因此,它们不会被返回。虽然非法输出将不会返回,但函数仍然会执行。例如,一个返回对象的类方法仍然可以很好地通过 rah_function 执行。只是除了无害的、信息性的错误消息外,不会有任何输出。
类型转换和特殊属性前缀
<rah::fn _boolAttr="boolean" _nullAttr="NULL" _intAttr="integer" _arrayAttr="array"/>
为了克服模板语言类型转换的限制,rah_function 包含几个特殊的属性前缀。这些前缀可以添加到标签属性名称之前,允许在将属性作为参数传递给被调用的函数之前将值转换为不同的类型。这些特殊属性前缀是 _bool
、_null
、_int
和 _array
。
_bool
如果标签属性以 _bool
前缀开头,则值将被转换为布尔类型。如果值是空的 (""
)、0
或大写字符串 FALSE
,则将其转换为 FALSE
。如果它是一切其他东西,它变为 TRUE
。
<rah::fn function _boolsilent="I become TRUE" _boolfalse="FALSE"/>
_null
_null
前缀将值转换为 NULL,无论提供的值是什么。
<rah::fn function _nullvalue="Always NULL, no matter what"/>
_int
_int
前缀将值转换为整数,确保值是一个安全有效的整数。数值将被四舍五入到零,非数值字符串将根据字符串的开头部分进行转换。如果属性值以有效的数值数据开头,则将使用该数据作为值。否则,值变为 0
(零)。
<rah::fn function _intid="I will be zero" _intnumericval="247"/>
_array
_array
前缀用于生成和传递数组。带有 _array
前缀的属性接受一个 JSON 字符串(JavaScript 对象表示法)并将其转换为 PHP 的数组。
<rah::fn implode _arrayValue="[1, 2, 3]"/>
安全相关功能
考虑到插件的本质,它包含一些选项来限制其访问。限制扩展到 rah_function 标签可以做什么以及标签可以使用的位置。该插件具有白名单选项,仅启用某些功能,并遵循 Textpattern 的 PHP 评估规则和用户权限,这些规则与 php 标签相同。
文章中的权限
用户组权限限制哪些用户可以在文章中使用 <rah::fn/>
标签。只有获得访问 article.php
资源权限的用户组才能在文章正文、自定义字段或摘录中使用这些标签。默认情况下,只有两个最高级别的组,出版商和管理编辑(ID 为 1 和 2 的组)有权访问 article.php
,并将能够使用插件标签发布文章。
高级 PHP 首选项
Rah_function 遵循 Textpattern 的 首选项 面板中可找到的两个 PHP 选项,即 允许页面中的 PHP 和 允许文章中的 PHP。当禁用 允许页面中的 PHP 选项时,rah_function 标签不能在页面模板或表单部分中使用。当禁用 允许文章中的 PHP 选项时,rah_function 标签不能在文章中使用。无论文章作者的权限如何,标签都不会执行。
函数白名单
为了增加可选的安全性,可以明确地将某些函数列入白名单。如果定义了白名单选项,则只有列入白名单的函数可以与 rah_function 标签一起调用。
白名单选项可以从 Textpattern 的 config.php
文件中设置。Rah_function 期望一个名为 rah_function_whitelist
的常量,其中包含以逗号分隔的函数名称列表。函数名称和类方法的格式应与在 rah_function 标签的 call
属性中使用的方式相同。
define('rah_function_whitelist', 'gps, ps, htmlspecialchars, str_replace, Class::StaticMethod, Class->Method');
其中 gps
、ps
、htmlspecialchars
、str_replace
、Class::StaticMethod
和 Class::Method
将是允许的函数和类方法。
此白名单选项完全可选,无需配置。它仅应在您想为增加安全性启用某些函数时使用。
示例
在单标签模式下使用 str_replace 替换内容
<rah::fn str_replace search="Hello" replace="Hi" subject="Hello world!"/>
返回:Hi world!
使用 str_replace 和容器替换内容
包含的语句用作 str_replace 的 主题 参数。通过在标签中使用 thing
将包装的内容定位到正确的位置。
<rah::fn str_replace search="Hello" replace="Hi" thing>
Hello world!
</rah::fn>
返回:Hi world!
清理并返回 HTTP GET 值
通过单个 rah_function 标签实例使用插件的多功能调用功能,可以返回 GET/POST 值并清理输出。首先,我们会使用 Textpattern 的 gps
函数获取特定的值,例如 theme
,然后通过将 HTML 的特殊字符转换为实体来为页面模板准备它,使用 htmlspecialchars。
<rah::fn call="gps, htmlspecialchars" name="theme" />
上述代码将返回名为 theme
的 HTTP GET/POST 参数的值。如果请求的值是 ?theme=I<3TXP
,则上述代码将返回一个安全的字符串 I<3TXP
。
获取和检查网站首选项
可以使用 Textpattern 的 get_pref()
函数来返回网站的偏好设置。以下代码将返回网站的生产状态。
<rah::fn get_pref name="production_status" />
以上代码可以用作条件语句,通过应用 _is
属性。
<rah::fn get_pref name="production_status" _is="debug">
Site is in debugging mode.
<txp:else />
Either in Testing or Live.
</rah::fn>
移除、追加和前缀空格或其他字符
PHP 提供了几个有用的函数来从字符串的开始和结束处移除空格和其他字符:trim、ltrim 和 rtrim。Trim 会从两端移除字符,而 ltrim 只影响开始,rtrim() 则想要完全正确。所有三个函数最多可以接受两个参数。第一个参数是要修剪的字符串,第二个参数是要移除的字符列表。如果没有指定字符,则移除空白字符。
从开始处移除零
包装的内容传递给 ltrim,设置为零 (0
) 从字符串的开始处移除。原始值 000150
转换为 150
。
<rah::fn ltrim strip="0">000150</rah::fn>
从开始和结束处移除空格
当不提供任何额外参数给 trim 时,它将从开始和结束处移除任何空白字符。
<rah::fn trim>
Hello World!
</rah::fn>
返回没有缩进或行结束符的 Hello World!
。
生成有效的 JavaScript 数组
以下示例从一个逗号分隔的值列表生成一个有效的 JavaScript Array。代码使用 do_list() 将值分割到 PHP 数组中,由于函数返回数组,因此 rah_function 编码并返回为有效的 JSON 表示。Rah_function 将任何数组作为 JSON 返回。
<rah::fn do_list>
value1, value2, value3
</rah::fn>
以上返回 ["value1","value2","value3"]
。
生成有效的 JavaScript 字符串
与前面的示例一样,编码非数组也是可能的。有几个方法可以实现,如果你需要一个有效且安全的 JavaScript 字符串。一个选项是调用 escape_js()
,另一个是 json_encode()
。第一个选项严格返回有效的 JavaScript,而后者考虑了 JSON 规范。
<rah::fn escape_js>
Soon to be valid JavaScript string.
</rah::fn>
或者对于 JSON
<rah::fn json_encode>
Soon to be valid for JSON.
</rah::fn>
使用 safe_strftime() 返回时间
<rah::fn safe_strftime>
%Y
</rah::fn>
返回:2009
。
使用 fetch() 函数从数据库中获取单个字段
<rah::fn fetch what="last_access" from="txp_users" where="user_id" is="1" />
返回:具有用户 ID 1 的网站管理员的最后访问时间。
计算文章数量
使用 Textpattern 的 safe_count()
函数进行计数。
<rah::fn safe_count table="textpattern" where="Status IN(4, 5)" />
返回:文章数量。
变更日志
版本 0.8.1 – 2023/02/25
- PHP >= 8.0 兼容性。在 PHP 8.0 或更高版本中,标签属性会作为命名参数传递给函数。如果名称不匹配,这会导致致命错误。为了减轻这个问题,此版本将回滚到 8.0 之前的旧行为,即根据属性顺序而不是参数名称来传递属性。
版本 0.8.0 – 2019/04/07
- 注册标签以支持 Textpattern >= 4.7.0 兼容性。
- 如果省略了
call
,可以通过第一个布尔属性设置被调用函数的名称。 - 支持将布尔属性作为参数。
- 现在需要 Textpattern 4.7.0 或更高版本。
版本 0.7.2 – 2014/03/20
- 修复:修复了 composer.json 文件中的错误,防止插件通过 Composer 安装。
版本 0.7.1 – 2013/05/06
- 变更:将 Composer 包更新为使用 textpattern/installer。
版本 0.7.0 – 2013/04/25
- 新增:
_constant
属性前缀。 - 新增:
_assign
属性。 - 作为 composer 包 发布。
版本 0.6 – 2012/07/19
- 更新:帮助文件(readme)。感谢 Ralitza。
版本 0.5 – 2012/07/19
- 新增:可以调用类方法(
call="Class->Method"
和call="Class::StaticMethod"
)。 - 新增:单个标签实例可以调用多个函数(
call="func1, func2, func3"
)。输出从函数到函数通过引用传递。列表中的第一个函数被视为主要函数,并且仅将其属性应用于它。 - 新增:数组作为 JSON 字符串返回,并且可以从一个标签实例传递到另一个。可以使用 JSON 作为值,方法是在使用标签属性名称前加上
_array
。 - 新增:将返回的布尔值转换为大写字符串,
TRUE
和FALSE
。这使得识别整数和布尔值(例如 strpos)成为可能。 - 新增:函数白名单选项。
- 改进:防止将非标量传递到模板。
- 改进:远离净化和
eval()
。现在使用回调。 - 改进:在需要时显示一些错误信息。
- 更新:帮助文件(readme)。感谢 Tye 提供的帮助。
版本 0.4 – 2011/12/16
- 改进:在函数调用中不使用属性的真正名称,而是使用一个临时数组。确保无论 Textpattern 的解析器传递给插件什么,属性都得到解析为有效的变量。
版本 0.3 – 2011/07/08
- 修复:现在可以使用一个空字符串作为容器模式的包装语句。
- 新增:现在确保在执行任何操作之前,被调用的函数确实已经定义。
版本 0.2 – 2009/11/28
- 新增属性:
thing
。感谢 Ruud 提出的建议。
版本 0.1.1 – 2009/11/21
- 新增
has_privs()
和allow_scripting
检查。
版本 0.1 – 2009/11/21
- 首次发布