Joomla 远程 SQL 调用






4.20/5 (3投票s)
这是一个 Joomla 组件,它允许通过 HTTP 使用 XML 消息远程执行 SQL。
目录
本文的第二部分,包含 VB.NET 客户端,现已发布。 第二部分
引言
这是两篇文章中的第一篇,介绍了一种自动化 Joomla 任务或基于 Joomla 的应用程序的方法。
我经常处理托管的 Joomla 网站,并且很多时候我不得不将一个或多个公司应用程序与之集成。
一个真实的例子是公司 ERP 与 Virtuemart(一个基于 Joomla 的电子商务解决方案)的集成:每天有数百种产品需要在线发布,并且每天有数百种产品会多次更改价格。
此外,处理托管网站通常意味着无法直接访问数据库。
我创建了一个 Joomla 组件,该组件可以接收远程命令并将其发行到底层数据库,并支持事务。
架构
架构很简单;我创建了一个 Joomla 组件,该组件发布了一个处理 XML 格式入站消息的页面。它执行 XML 消息中包含的命令,并发送回一个 message
响应。
消息交换不应用任何标准;没有 SOAP 也没有其他 RPC 协议。我创建了一个专有的基于 HTTP 的协议。
安全
该页面是公开的。因此,如果没有安全检查,它可能会造成严重的安全漏洞。为此,我引入了一个基于密钥交换的简单安全机制。
组件安装后,它会生成一个唯一的安全令牌。此安全令牌必须存在于请求参数中才能被服务器接受。
看点
Joomla 组件同时实现了管理面板和站点部分。
管理面板显示必须使用的安全密钥,而站点页面仅处理 XML 请求。
我不解释如何创建 Joomla 组件,因为已经有很多关于此主题的教程(您可以从 此处 开始)。
有趣的点是使用安装后脚本生成唯一的安全密钥以及处理 XML 请求的站点页面。
安装后脚本
在 Joomla 安装包中,名为 “component.xml” 的 XML 文件包含了所有安装说明。指令 <scriptfile>script.php</scriptfile>
指示安装过程在安装包根文件夹中找到名为 component_name
InstallerScript
的类,该类位于 script.php 文件中。
此类的一些明确定义的 public
方法会在安装过程中被调用
function install($parent)
在安装过程中被调用。在这里,您可以指定在此阶段执行的附加步骤,function uninstall($paent)
在卸载过程中被调用function update($parent)
在更新过程中被调用function preflight($type, $parent)
在安装和更新之前被调用function postflight($type, $parent)
在安装和更新之后被调用
您可以 在此处 找到更多信息。
我使用 postflight
函数来编写一个包含安全令牌的 XML 文件
function postflight($type, $parent)
{
$string = '<sec><token>'.md5(uniqid(rand(), true)).'</token></sec>';
$xml = new SimpleXMLElement($string);
$xml->asXML(JPATH_SITE.'/components/com_sqlxml/sec.xml');
}
站点部分
站点部分由一个只处理 XML 输出的控制器管理。请求必须指定 URL 参数 “format=xml
”。
它注册了一个名为 “cmdep.execcmd
” 的函数,该函数处理请求并准备要发送回的 XML 响应。
该函数的第一步是安全检查。如果令牌不匹配,它会回复错误。
安全令牌验证后,该函数读取请求的内容,并为指定的每个命令执行所需的操作。
让我们看看消息结构
<?xml version="1.0" encoding="utf-16"?>
<msg-req xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<commands>
<command type="sql" action="select"
mandatory="false"><![CDATA[]]></command>
<command type="sql" action="select"
mandatory="false"><![CDATA[]]></command>
</commands>
</msg-req>
如您所见,msg-req
包含一个 commands
集合,然后是一个或多个 command
。
所有过程都包含在一个事务中;每个 command
都可以指定是否参与事务。
一个 command
(现在只能是 SQL 语句)可以指定一些参数
- “mandatory” 参数指示
command
是否必须成功终止才能完成事务。如果设置为true
且命令失败,则事务将回滚。 - “
action
” 参数指示要执行的 SQL 语句的类型。
支持的类型有 “INSERT
”、“UPDATE
”、“DELETE
”、“SELECT
”、“CALL
”。
参数值与命令的实际内容之间没有语义检查,此参数仅管理 SQL 命令的执行方式及其结果的返回方式。因此,“INSERT
” 命令将返回最后插入的自动生成 ID,而 “UPDATE
” 或 “DELETE
” 命令将返回受影响的行数。 - “
save
” 参数用于指定一个变量名,在该变量名中临时保存返回值,以便在下一个命令中使用。
看下面的例子
“TABLE1
” 有 3 个字段:“ID
” 是一个自动生成的数字字段,也是主键,后跟两个文本字段 “FIELD1
” 和 “FIELD2
”。
“TABLE2
” 也有 3 个字段:一个自动生成的 “ID
”、“REF_ID
”(引用 “TABLE1
” 中的 “ID
” 字段)和一个文本类型的 “FIELD1
”。
如果您需要在这些表中插入相关记录,您需要创建 2 个 INSERT
命令(mandatory,以便只有当两个命令都成功执行时,事务才提交),第一个命令将返回值保存在名为 “SAVED_ID
” 的变量中,第二个命令在下一个 SQL 语句中以 “$[SAVED_ID]
” 的形式引用该变量。
<command type="sql" action="insert" mandatory="true"
save="ID"><![CDATA[INSERT INTO TABLE1 (FIELD1, FIELD2)
VALUES ('VALUE1', 'VALUE2')]]></command>
<command type="sql" action="insert"
mandatory="true"><![CDATA[INSERT INTO TABLE2
(REF_ID, FIELD1) VALUES ($[SAVED_ID], 'VALUE2')]]></command>
当第二个命令执行时,所有形式为 $[...]
的参数都将替换为相应的值。因此,$[SAVED_ID]
的值已被第一个语句中保存的值替换。
在 PHP 中,通过使用关联数组实现了此参数替换的管理。
返回值保存在一个全局数组中,使用 “saved” 参数的值作为键。
$res_values = array();
$cmd_attr = $cmd->attributes(); //xml message command attributes
$save = (string)$cmd_attr['save'];
if ($save!=null)
$res_values[$save]=$query_result[0];
然后,通过查询数组来替换 SQL 语句中所有匹配 $[…]
的参数。
$tmp = (string)$cmd; //Use a temp string to store the sql command
//use a regular expression to find all $[…] parameters.
//the first matching group is the complete parameter string "$[named_param]"
//the second matching group is the parater name only "named_param"
$ct = preg_match_all("/\\$\[((?:\[\S*\]|[^\[])*)\]/", $tmp, $arr);
//for each parameter found proceed with values substitution.
for($i=0; $i<$ct; $i++){
$tmp = str_replace($arr[0][$i], $res_values[$arr[1][$i]], $tmp);
}
结论
当您无法直接访问托管数据库时,此组件非常有用。
您可以使用任何编程语言利用事务管理来自动化您的 Joomla 任务。
在下一篇文章中,我将展示一个 VB.NET 客户端,该客户端将探索该组件的一些功能。
更新
2015/09/09 - 发布了文章的第二部分。 第二部分