1--TEST-- 2registerPHPFunctionNS() function - legit cases 3--EXTENSIONS-- 4xsl 5--SKIPIF-- 6<?php 7require __DIR__.'/skip_upstream_issue113.inc'; 8?> 9--FILE-- 10<?php 11 12class TrampolineClass { 13 public static function __callStatic(string $name, array $arguments): mixed { 14 var_dump($name, $arguments); 15 return "foo"; 16 } 17} 18 19class StatefulClass { 20 public array $state = []; 21 22 public function __call(string $name, array $arguments): mixed { 23 $this->state[] = [$name, $arguments[0]]; 24 return $arguments[0]; 25 } 26} 27 28function createProcessor($inputs) { 29 $xsl = new DomDocument(); 30 $xsl->loadXML('<?xml version="1.0" encoding="iso-8859-1" ?> 31 <xsl:stylesheet version="1.0" 32 xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 33 xmlns:foo="urn:foo" 34 xmlns:bar="urn:bar"> 35 <xsl:template match="//a">' 36 . implode('', array_map(fn($input) => '<xsl:value-of select="' . $input . '" />', $inputs)) . 37 '</xsl:template> 38 </xsl:stylesheet>'); 39 40 $proc = new XSLTProcessor(); 41 $proc->importStylesheet($xsl); 42 return $proc; 43} 44 45$inputdom = new DomDocument(); 46$inputdom->loadXML('<?xml version="1.0" encoding="iso-8859-1"?><a href="https://php.net">hello</a>'); 47 48echo "--- Legit cases: none ---\n"; 49 50$proc = createProcessor(["foo:var_dump(string(@href))"]); 51try { 52 // Note: since libxml2 commit aca16fb3d45e0b2c45364ffc1cea8eb4abaca87d this only outputs 1 warning. This seems intentional. 53 // Easiest workaround is silencing the warnings 54 @$proc->transformToXml($inputdom); 55} catch (Error $e) { 56 echo $e->getMessage(), "\n"; 57} 58 59echo "--- Legit cases: global function callable ---\n"; 60 61$proc = createProcessor(["foo:var_dump(string(@href))"]); 62$proc->registerPHPFunctionNS('urn:foo', 'var_dump', var_dump(...)); 63$proc->transformToXml($inputdom); 64 65echo "--- Legit cases: global string callable ---\n"; 66 67$proc = createProcessor(["foo:var_dump(string(@href))"]); 68$proc->registerPHPFunctionNS('urn:foo', 'var_dump', 'var_dump'); 69$proc->transformToXml($inputdom); 70 71echo "--- Legit cases: trampoline callable ---\n"; 72 73$proc = createProcessor(["foo:trampoline(string(@href))"]); 74$proc->registerPHPFunctionNS('urn:foo', 'trampoline', TrampolineClass::test(...)); 75var_dump($proc->transformToXml($inputdom)); 76 77echo "--- Legit cases: instance class method callable ---\n"; 78 79$state = new StatefulClass; 80$proc = createProcessor(["foo:test(string(@href))"]); 81$proc->registerPHPFunctionNS('urn:foo', 'test', $state->test(...)); 82var_dump($proc->transformToXml($inputdom)); 83var_dump($state->state); 84 85echo "--- Legit cases: multiple namespaces ---\n"; 86 87$proc = createProcessor(["foo:test(string(@href))", "bar:test(string(@href))"]); 88$proc->registerPHPFunctionNS('urn:foo', 'test', strrev(...)); 89$proc->registerPHPFunctionNS('urn:bar', 'test', strtoupper(...)); 90var_dump($proc->transformToXml($inputdom)); 91 92?> 93--EXPECTF-- 94--- Legit cases: none --- 95--- Legit cases: global function callable --- 96string(15) "https://php.net" 97--- Legit cases: global string callable --- 98string(15) "https://php.net" 99--- Legit cases: trampoline callable --- 100string(4) "test" 101array(1) { 102 [0]=> 103 string(15) "https://php.net" 104} 105string(26) "<?xml version="1.0"?> 106foo 107" 108--- Legit cases: instance class method callable --- 109string(38) "<?xml version="1.0"?> 110https://php.net 111" 112array(1) { 113 [0]=> 114 array(2) { 115 [0]=> 116 string(4) "test" 117 [1]=> 118 string(15) "https://php.net" 119 } 120} 121--- Legit cases: multiple namespaces --- 122string(53) "<?xml version="1.0"?> 123ten.php//:sptthHTTPS://PHP.NET 124" 125