diff --git a/src/BeSimple/SoapClient/SoapClient.php b/src/BeSimple/SoapClient/SoapClient.php index 19d5be9..79d7e31 100644 --- a/src/BeSimple/SoapClient/SoapClient.php +++ b/src/BeSimple/SoapClient/SoapClient.php @@ -241,19 +241,17 @@ class SoapClient extends \SoapClient */ private function loadWsdl($wsdl, array $options) { - // option to resolve xsd includes - $resolveXsdIncludes = true; - if (isset($options['resolve_xsd_includes'])) - { - $resolveXsdIncludes = $options['resolve_xsd_includes']; + // option to resolve wsdl/xsd includes + $resolveRemoteIncludes = true; + if (isset($options['resolve_wsdl_remote_includes'])) { + $resolveRemoteIncludes = $options['resolve_wsdl_remote_includes']; } // option to enable cache $wsdlCache = WSDL_CACHE_DISK; - if (isset($options['cache_wsdl'])) - { + if (isset($options['cache_wsdl'])) { $wsdlCache = $options['cache_wsdl']; } - $wsdlDownloader = new WsdlDownloader($this->curl, $resolveXsdIncludes, $wsdlCache); + $wsdlDownloader = new WsdlDownloader($this->curl, $resolveRemoteIncludes, $wsdlCache); try { $cacheFileName = $wsdlDownloader->download($wsdl); } catch (\RuntimeException $e) { diff --git a/src/BeSimple/SoapClient/WsdlDownloader.php b/src/BeSimple/SoapClient/WsdlDownloader.php index 540c801..1894269 100644 --- a/src/BeSimple/SoapClient/WsdlDownloader.php +++ b/src/BeSimple/SoapClient/WsdlDownloader.php @@ -54,23 +54,23 @@ class WsdlDownloader private $curl; /** - * Resolve XSD includes. + * Resolve WSDl/XSD includes. * * @var boolean */ - protected $resolveXsdIncludes = true; + protected $resolveRemoteIncludes = true; /** * Constructor. * - * @param \BeSimple\SoapClient\Curl $curl Curl instance - * @param boolean $resolveXsdIncludes XSD include enabled? - * @param boolean $cacheWsdl Cache constant + * @param \BeSimple\SoapClient\Curl $curl Curl instance + * @param boolean $resolveRemoteIncludes WSDL/XSD include enabled? + * @param boolean $cacheWsdl Cache constant */ - public function __construct(Curl $curl, $resolveXsdIncludes = true, $cacheWsdl = WSDL_CACHE_DISK) + public function __construct(Curl $curl, $resolveRemoteIncludes = true, $cacheWsdl = WSDL_CACHE_DISK) { $this->curl = $curl; - $this->resolveXsdIncludes = $resolveXsdIncludes; + $this->resolveRemoteIncludes = $resolveRemoteIncludes; // get current WSDL caching config $this->cacheEnabled = (bool)ini_get('soap.wsdl_cache_enabled'); if ($this->cacheEnabled === true @@ -96,7 +96,7 @@ class WsdlDownloader // download and cache remote WSDL files or local ones where we want to // resolve remote XSD includes $isRemoteFile = $this->isRemoteFile($wsdl); - if ($isRemoteFile === true || $this->resolveXsdIncludes === true) { + if ($isRemoteFile === true || $this->resolveRemoteIncludes === true) { $cacheFile = $this->cacheDir . DIRECTORY_SEPARATOR . 'wsdl_' . md5($wsdl) . '.cache'; if ($this->cacheEnabled === false || !file_exists($cacheFile) @@ -107,8 +107,8 @@ class WsdlDownloader // get content if ($responseSuccessfull === true) { $response = $this->curl->getResponseBody(); - if ($this->resolveXsdIncludes === true) { - $this->resolveXsdIncludes($response, $cacheFile, $wsdl); + if ($this->resolveRemoteIncludes === true) { + $this->resolveRemoteIncludes($response, $cacheFile, $wsdl); } else { file_put_contents($cacheFile, $response); } @@ -117,7 +117,7 @@ class WsdlDownloader } } elseif (file_exists($wsdl)) { $response = file_get_contents($wsdl); - $this->resolveXsdIncludes($response, $cacheFile); + $this->resolveRemoteIncludes($response, $cacheFile); } else { throw new \ErrorException("SOAP-ERROR: Parsing WSDL: Couldn't load from '" . $wsdl ."'"); } @@ -149,20 +149,38 @@ class WsdlDownloader } /** - * Resolves remote XSD includes within the WSDL files. + * Resolves remote WSDL/XSD includes within the WSDL files. * * @param string $xml * @param string $cacheFile * @param unknown_type $parentIsRemote * @return string */ - private function resolveXsdIncludes($xml, $cacheFile, $parentFile = null) + private function resolveRemoteIncludes($xml, $cacheFile, $parentFile = null) { $doc = new \DOMDocument(); $doc->loadXML($xml); $xpath = new \DOMXPath($doc); $xpath->registerNamespace(Helper::PFX_XML_SCHEMA, Helper::NS_XML_SCHEMA); - $query = './/' . Helper::PFX_XML_SCHEMA . ':include'; + $xpath->registerNamespace('wsdl', 'http://schemas.xmlsoap.org/wsdl/'); // TODO add to Helper + // WSDL include/import + $query = './/wsdl:include | .//wsdl:import'; + $nodes = $xpath->query($query); + if ($nodes->length > 0) { + foreach ($nodes as $node) { + $location = $node->getAttribute('location'); + if ($this->isRemoteFile($location)) { + $location = $this->download($location); + $node->setAttribute('location', $location); + } elseif (!is_null($parentFile)) { + $location = $this->resolveRelativePathInUrl($parentFile, $location); + $location = $this->download($location); + $node->setAttribute('location', $location); + } + } + } + // XML schema include/import + $query = './/' . Helper::PFX_XML_SCHEMA . ':include | .//' . Helper::PFX_XML_SCHEMA . ':import'; $nodes = $xpath->query($query); if ($nodes->length > 0) { foreach ($nodes as $node) { diff --git a/tests/BeSimple/Tests/SoapClient/Fixtures/wsdl_include.wsdl b/tests/BeSimple/Tests/SoapClient/Fixtures/wsdl_include.wsdl new file mode 100644 index 0000000..775240a --- /dev/null +++ b/tests/BeSimple/Tests/SoapClient/Fixtures/wsdl_include.wsdl @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/tests/BeSimple/Tests/SoapClient/Fixtures/wsdlinclude/wsdlinctest_absolute.xml b/tests/BeSimple/Tests/SoapClient/Fixtures/wsdlinclude/wsdlinctest_absolute.xml new file mode 100644 index 0000000..dae033e --- /dev/null +++ b/tests/BeSimple/Tests/SoapClient/Fixtures/wsdlinclude/wsdlinctest_absolute.xml @@ -0,0 +1,5 @@ + + + wsdlincludetest + + diff --git a/tests/BeSimple/Tests/SoapClient/Fixtures/wsdlinclude/wsdlinctest_relative.xml b/tests/BeSimple/Tests/SoapClient/Fixtures/wsdlinclude/wsdlinctest_relative.xml new file mode 100644 index 0000000..8148e60 --- /dev/null +++ b/tests/BeSimple/Tests/SoapClient/Fixtures/wsdlinclude/wsdlinctest_relative.xml @@ -0,0 +1,5 @@ + + + wsdlincludetest + + diff --git a/tests/BeSimple/Tests/SoapClient/WsdlDownloaderTest.php b/tests/BeSimple/Tests/SoapClient/WsdlDownloaderTest.php index f294a8b..14ac58a 100644 --- a/tests/BeSimple/Tests/SoapClient/WsdlDownloaderTest.php +++ b/tests/BeSimple/Tests/SoapClient/WsdlDownloaderTest.php @@ -115,6 +115,63 @@ class WsdlDownloaderTest extends \PHPUnit_Framework_TestCase $this->assertFalse($method->invoke($wd, '../dir/test.html')); } + public function testResolveWsdlIncludes() + { + $this->startPhpWebserver(); + + $curl = new Curl(); + $wd = new WsdlDownloader($curl); + + $class = new \ReflectionClass($wd); + $method = $class->getMethod('resolveRemoteIncludes'); + $method->setAccessible(true); + + $cacheDir = ini_get('soap.wsdl_cache_dir'); + if (!is_dir($cacheDir)) { + $cacheDir = sys_get_temp_dir(); + $cacheDirForRegExp = preg_quote( $cacheDir ); + } + + $remoteUrlAbsolute = 'http://localhost:8000/wsdlinclude/wsdlinctest_absolute.xml'; + $remoteUrlRelative = 'http://localhost:8000/wsdlinclude/wsdlinctest_relative.xml'; + $tests = array( + 'localWithAbsolutePath' => array( + 'source' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/wsdlinclude/wsdlinctest_absolute.xml', + 'cacheFile' => $cacheDir.'/cache_local_absolute.xml', + 'remoteParentUrl' => null, + 'assertRegExp' => '~.*'.$cacheDirForRegExp.'\\\wsdl_.*\.cache.*~', + ), + 'localWithRelativePath' => array( + 'source' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/wsdlinclude/wsdlinctest_relative.xml', + 'cacheFile' => $cacheDir.'/cache_local_relative.xml', + 'remoteParentUrl' => null, + 'assertRegExp' => '~.*\.\./wsdl_include\.wsdl.*~', + ), + 'remoteWithAbsolutePath' => array( + 'source' => $remoteUrlAbsolute, + 'cacheFile' => $cacheDir.'/cache_remote_absolute.xml', + 'remoteParentUrl' => $remoteUrlAbsolute, + 'assertRegExp' => '~.*'.$cacheDirForRegExp.'\\\wsdl_.*\.cache.*~', + ), + 'remoteWithAbsolutePath' => array( + 'source' => $remoteUrlRelative, + 'cacheFile' => $cacheDir.'/cache_remote_relative.xml', + 'remoteParentUrl' => $remoteUrlRelative, + 'assertRegExp' => '~.*'.$cacheDirForRegExp.'\\\wsdl_.*\.cache.*~', + ), + ); + + foreach ($tests as $name => $values) { + $wsdl = file_get_contents( $values['source'] ); + $method->invoke($wd, $wsdl, $values['cacheFile'],$values['remoteParentUrl']); + $result = file_get_contents($values['cacheFile']); + $this->assertRegExp($values['assertRegExp'],$result,$name); + unlink($values['cacheFile']); + } + + $this->stopPhpWebserver(); + } + public function testResolveXsdIncludes() { $this->startPhpWebserver(); @@ -123,7 +180,7 @@ class WsdlDownloaderTest extends \PHPUnit_Framework_TestCase $wd = new WsdlDownloader($curl); $class = new \ReflectionClass($wd); - $method = $class->getMethod('resolveXsdIncludes'); + $method = $class->getMethod('resolveRemoteIncludes'); $method->setAccessible(true); $cacheDir = ini_get('soap.wsdl_cache_dir');