stream_context_create,带有基于域名的HTTP选项

时间:2014-06-15 08:25:33

标签: php xml xslt cookies

如何根据请求的URI的域名告诉使用stream_context_create()创建的streamContext使用不同的HTTP标头?

我使用XSL在服务器端(PHP)上转换XML。

为此,我首先创建一个包含一些选项的流上下文,并将此流应用于libxml

$streamContextOptions = array(
    'http' =>array(
        'header'=>$clientHeadersString /* HTTP header */
    )
);
$streamContext = stream_context_create($streamContextOptions);
libxml_set_streams_context($streamContext);

然后我加载XML,XSL并进行转换

// Load the XML
$xmlDocument = new DOMDocument();
$xmlDocument->load($xmlURI);

// Load the XSL into
$xslDocument = new DOMDocument();
$xslDocument->load($xslURI);
$xslProcessor = new XSLTProcessor();
$xslProcessor->importStylesheet($xslDocument);

// Apply the XSL
$htmlDocument = $xslProcessor->transformToDoc($xmlDocument);

在XSL中,我有一些document()调用,因此PHP服务器使用流上下文调用指定的URI。但我在这些document()电话中有不同的域名(让我们说我有www.foo.com和www.bar.com)。

<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" encoding="utf-8" indent="yes"/>

    <xsl:template match="/">
        <xsl:value-of select="document('http://www.foo.com/with-user-agent.xml.php')/root"/>
        <xsl:value-of select="document('http://www.bar.com/with-accept-language.php')/root"/>
    </xsl:template>
</xsl:stylesheet>    

我想要的是更改libxml在XSL内进行document()调用时使用的HTTP头,这样我就可以将[cookies + user-agent]发送到foo.com,以及[其他cookie +当在XSL document()电话中请求时,bar.com接受语言。

我不想发送太多&#34;标题为foo.com(也就是说,我不想发送Accept-Language到foo.com),也不是bar.com,我也不想把cookie混在一起(cookies发送到foo) .com不得发送到bar.com)。

不知何故,如:

$streamContextOptions = array(
    'http-for-foo' =>array(
        'header'=>$clientHeadersStringForFoo /* HTTP header only when document() calls for foo.com*/
    ),
    'http-for-bar' =>array(
        'header'=>$clientHeadersStringForBar /* HTTP header only when document() calls for bar.com*/
    )
);

有没有办法告诉XSLTProcessor根据document()函数请求的域更改streamOptions?

2 个答案:

答案 0 :(得分:1)

您不能告诉流上下文选项的不同主机,因为使用流I / O操作,已分配上下文 - 根据主机名,libxml_set_streams_context没有空间不同(也适用于PHP中的流)这也是不可能的。至少AFAIK)。

因此,您需要为URI分配适当的流选项。

在您的方案中,我觉得在 DOM设置之后最容易完成 转换之前通过创建your own external entity loader来实现基于主机名的上下文选项:

...

$xslProcessor->importStylesheet($xslDocument);

$httpOptions       = [
    'timeout' => 1,
    'header'  => "User-Agent: Godzilla Gabba Gandalf Client 42.4 - Lord of the XSLT Weed Edition"
];
$httpOptionsByHost = [
    'www.foo.com' => [
        'header' => "X-Secret-Debug-Request-Flag: verbose-verbose-verbose"
    ],
    'www.bar.com' => [
        'header' => "User-Agent: 1' OR TRUE"
    ]
];

libxml_set_external_entity_loader(
    function ($public, $system, $context) use ($httpOptions, $httpOptionsByHost) {

        $url = new Net_URL2($system);
        $url->normalize();
        $host = $url->getHost();

        $options['http'] = [];

        if (isset($httpOptionsByHost[$host])) {
            $options['http'] = $httpOptionsByHost[$host];
        }

        $options['http'] += $httpOptions;

        $context = stream_context_create($options);

        return fopen($url, 'r', false, $context);
    }
);

// Apply the XSL
$htmlDocument = $xslProcessor->transformToDoc($xmlDocument);

...

你没有在你的问题中提供XML,也没有外部URI工作,所以我只能部分测试,但据我可以验证,这应该有效。

您可能需要在外部实体加载程序功能方面有所不同,因为您可能需要加载其他其他实体,而这些实体不应该被平等处理。但我认为你可以解决这个问题。

答案 1 :(得分:0)

也许您可以代理请求?即document('//mydomain/?doc=origin-doc')

这样您就可以根据需要修改请求(例如使用cURL)。 doc参数可用于有条件地修改请求。