Php 流\u上下文\u使用基于域名的HTTP选项创建
如何告诉使用Php 流\u上下文\u使用基于域名的HTTP选项创建,php,xml,xslt,cookies,Php,Xml,Xslt,Cookies,如何告诉使用stream\u context\u create()创建的streamContext根据请求URI的域名使用不同的HTTP头? 我使用XSL在服务器端(PHP)转换XML 为此,我首先创建一个带有一些选项的流上下文,并将此流应用于libxml: $streamContextOptions = array( 'http' =>array( 'header'=>$clientHeadersString /* HTTP header */ )
stream\u context\u create()
创建的streamContext根据请求URI的域名使用不同的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)
是否有方法告诉XSLTProcessor根据
document()
函数请求的域更改流选项?也许您可以代理请求?即文档('//mydomain/?doc=origin doc')
通过这种方式,您可以根据需要修改请求(例如使用cURL)。doc参数可用于有条件地修改请求。对于流上下文选项,您无法区分不同的主机,因为通过流I/O操作,已分配了上下文-没有根据主机名进行差异的空间(对于PHP中的流,这也是不可能的。至少是AFAIK) 因此,您需要为URI分配适当的流选项 在您的场景中,在DOM设置之后但在转换之前,通过创建能够根据主机名不同的上下文选项,我认为这是最容易做到的:
...
$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也不起作用,因此我只能进行部分测试,但就我所能验证的而言,这应该是可行的
您可能需要在外部实体加载器函数中有更多不同之处,因为您可能会加载其他不应同等处理的实体。但是我想您可以找到答案。您的外部资源不是依赖于请求头吗?Imho资源应该是静态和可缓存的。@RolandFranssen否,因为XML资源可能是用户的配置文件数据(用户名、化身、邮件…)。所以用户必须先登录才能检索这种XML。返回的XML也可以基于本地化数据的
Accept Language
。libxml\u set\u external\u entity\u loader()
是否适用于XSL内部的document()
调用?或者我必须在XML中切换并使用实体
,而不是在XSL中使用document()
?它适用于XSL中的document()
调用,否则我不会建议这样做。在我的测试中,我可以为XSL文件中document()
内的两个不同URI中的两个不同主机名创建两个不同的流上下文。因此,使用代理,当在客户端解析XSL时,浏览器将发送mydomain
凭据(并代理到otherDomain
),而不是使用正确的凭据直接调用otherDomain
。我知道服务器端的mydomain
不会有otherDomain
凭据,但我希望otherDomain
在服务器端被称为无凭据,在客户端被称为完全凭据。实际上,由于Chrome(webkit?)不接受XML/XSL文档的CORS,我将使用这种方式,并坚持使用本地URI(整个XSL只有一个流上下文)如果需要,由服务器提供。
$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*/
)
);
...
$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);
...