通过 apache 服务器内部的服务器端过滤,在 SVG 中动态包含 JavaScript

Dynamic inclusion of javascript in SVG by means of server side filtering inside apache server

本文关键字:SVG 动态 JavaScript 包含 过滤 服务器 apache 内部 服务器端 通过      更新时间:2023-09-26

几年前,我编写了一些代码来自动将一些javascript代码包含在http服务器提供的html页面中。该方法记录在博客条目和此 StackOverflow 问题中。在过去的几年里,这个解决方案对我很有帮助。

两句话的方法:

  • 对于 HTTP 服务器提供的每个完整 HTML 页面,通过服务器端替换将一些占位符添加到页面底部
  • 该占位符再次替换为要通过服务器端包含的 JavaScript 代码

现在,我想扩展该解决方案,并将相同的逻辑应用于基于 SVG 而不是 HTML 作为文档格式的页面。注意:不是 html 页面中包含的 SVG,而是通过链接直接引用的 SVG 格式的页面。

扩展本身不是问题,javascript代码包含在SVG标记中。问题是代码未执行。不幸的是,我对 SVG 中的脚本知之甚少,这就是为什么我有些迷茫的原因。也许有人可以给我一个提示,这里出了什么问题:-)

各种 apache vhosts 定义中包含的过滤器链:

# ----------
# internal requests to include the piwik tracking code at the bottom of every html page
FilterDeclare PIWIK_token
FilterProvider PIWIK_token SUBSTITUTE resp=Content-Type $text/html
SUBSTITUTE 's|^'s*</body>|<!--#include virtual="/piwik"--></body>|iq'
FilterProvider PIWIK_token SUBSTITUTE resp=Content-Type $image/svg+xml
SUBSTITUTE 's|^'s*</svg>|<!--#include virtual="/piwik"--></svg>|iq'
FilterDeclare PIWIK_code
FilterProvider PIWIK_code INCLUDES resp=Content-Type $text/html
FilterProvider PIWIK_code INCLUDES resp=Content-Type $image/svg+xml
FilterChain PIWIK_token PIWIK_code
# map virtual request to the file system
Alias /piwik /srv/www/internal/piwik.php
# all that is left for the virtual host is to do two things:
#        SetEnv PIWIK_ID 15
#        Include /etc/apache2/vhosts.d/_internal.inc
# note: the '15' above is an example piwik site id

要包含的 javascript 代码是 piwik 跟踪代码段的略微修改版本:

<?php
define('piwikBase','https://some.domain.xxx/stats/');
define('piwikSite',apache_getenv('PIWIK_ID'));
if(is_numeric(piwikSite)){
?>
<script type="text/javascript">
  var _paq = _paq || [];
  _paq.push(["trackPageView"]);
  _paq.push(["enableLinkTracking"]);
  (function() {
    var u="<?= piwikBase ?>";
    _paq.push(["setTrackerUrl", u+"piwik.php"]);
    _paq.push(["setSiteId", "<?= piwikSite ?>"]);
    var d=document, g=d.createElement("script"), s=d.getElementsByTagName("script")[0]; g.type="text/javascript";
    g.defer=true; g.async=true; g.src=u+"piwik.js"; s.parentNode.insertBefore(g,s);
  })();
</script>
<?php } else { ?>
<!-- invalid piwik site id: <?php echo piwikSite;?> -->
<?php } ?>

如前所述:扩展有效,javascript代码成功包含在SVG文档中。但是它显然没有被激活,我没有看到原因......

交付的最终 SVG 如下所示:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:cc="http://creativecommons.org/ns#"
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:svg="http://www.w3.org/2000/svg"
    xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    version="1.2"
    width="100%"
    height="100%"
    viewBox="0 0 640 400"
    docname="somedocument.svg">
[... content of the SVG ...]
<script type="text/javascript">
  var _paq = _paq || [];
  _paq.push(["trackPageView"]);
  _paq.push(["enableLinkTracking"]);
  (function() {
    var u="https://some.domain.xxx/stats/";
    _paq.push(["setTrackerUrl", u+"piwik.php"]);
    _paq.push(["setSiteId", "15"]);
    var d=document, g=d.createElement("script"), s=d.getElementsByTagName("script")[0]; g.type="text/javascript";
    g.defer=true; g.async=true; g.src=u+"piwik.js"; s.parentNode.insertBefore(g,s);
  })();
</script>
</svg>

只是猜测,但我会尝试更改代码,以便将动态脚本注入替换为带有 xlink:href 的内联脚本标签(我已经测试过动态执行此操作,就像您的代码使用看似"更正确"createAttibuteNS('xlink','href','...')但结果也没有执行)

生成的代码如下所示(尚未在真实环境中测试,因此拼写错误):

<?php
define('piwikBase','https://some.domain.xxx/stats/');
define('piwikSite',apache_getenv('PIWIK_ID'));
if(is_numeric(piwikSite)){
?>
<script type="text/javascript"><![CDATA[
  var _paq = _paq || [];
  _paq.push(["trackPageView"]);
  _paq.push(["enableLinkTracking"]);
  _paq.push(["setTrackerUrl", "<?= piwikBase ?>piwik.php"]);
  _paq.push(["setSiteId", "<?= piwikSite ?>"]);    
]]></script>
<script type="text/javascript"
 xmlns:xlink="http://www.w3.org/1999/xlink"
 xlink:href="<?= piwikBase ?>piwik.js"
 defer="defer" async="async"></script>
<?php } else { ?>
<!-- invalid piwik site id: <?php echo piwikSite;?> -->
<?php } ?>

我不确定那些deferasync的东西,它是否在 SVG 中有任何影响。我已经用简单的datauri示例对此进行了测试,它似乎运行良好。

笔记:

  • 脚本或其某些父级xmlns:xlink="http://www.w3.org/1999/xlink"是必要的,但很可能您的 SVG 已经拥有它
  • 在这种情况下,CDATA不是必需的,但是如果您打算将来使用<&...你知道吗。

不能使用 创建 SVG 脚本元素

g=d.createElement("script")

你需要写

g=d.createElementNS("http://www.w3.org/2000/svg", "script")