Server.php 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. <?php
  2. /**
  3. * Magento-specific SOAP server.
  4. *
  5. * Copyright © Magento, Inc. All rights reserved.
  6. * See COPYING.txt for license details.
  7. */
  8. namespace Magento\Webapi\Model\Soap;
  9. use Magento\Framework\Webapi\Request;
  10. /**
  11. * SOAP Server
  12. *
  13. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  14. */
  15. class Server
  16. {
  17. const SOAP_DEFAULT_ENCODING = 'UTF-8';
  18. /**#@+
  19. * Path in config to Webapi settings.
  20. */
  21. const CONFIG_PATH_SOAP_CHARSET = 'webapi/soap/charset';
  22. /**#@-*/
  23. const REQUEST_PARAM_SERVICES = 'services';
  24. const REQUEST_PARAM_WSDL = 'wsdl';
  25. const REQUEST_PARAM_LIST_WSDL = 'wsdl_list';
  26. /**
  27. * @var \Magento\Framework\App\AreaList
  28. */
  29. protected $_areaList;
  30. /**
  31. * @var \Magento\Framework\Config\ScopeInterface
  32. */
  33. protected $_configScope;
  34. /**
  35. * @var Request
  36. */
  37. protected $_request;
  38. /**
  39. * @var \Magento\Store\Model\StoreManagerInterface
  40. */
  41. protected $_storeManager;
  42. /**
  43. * @var \Magento\Webapi\Model\Soap\ServerFactory
  44. */
  45. protected $_soapServerFactory;
  46. /**
  47. * @var \Magento\Framework\Reflection\TypeProcessor
  48. */
  49. protected $_typeProcessor;
  50. /**
  51. * @var \Magento\Framework\App\Config\ScopeConfigInterface
  52. */
  53. protected $_scopeConfig;
  54. /**
  55. * @var Wsdl\Generator
  56. */
  57. private $wsdlGenerator;
  58. /**
  59. * Initialize dependencies, initialize WSDL cache.
  60. *
  61. * @param \Magento\Framework\App\AreaList $areaList
  62. * @param \Magento\Framework\Config\ScopeInterface $configScope
  63. * @param Request $request
  64. * @param \Magento\Store\Model\StoreManagerInterface $storeManager
  65. * @param \Magento\Webapi\Model\Soap\ServerFactory $soapServerFactory
  66. * @param \Magento\Framework\Reflection\TypeProcessor $typeProcessor
  67. * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
  68. * @param Wsdl\Generator $wsdlGenerator
  69. * @throws \Magento\Framework\Webapi\Exception
  70. */
  71. public function __construct(
  72. \Magento\Framework\App\AreaList $areaList,
  73. \Magento\Framework\Config\ScopeInterface $configScope,
  74. Request $request,
  75. \Magento\Store\Model\StoreManagerInterface $storeManager,
  76. \Magento\Webapi\Model\Soap\ServerFactory $soapServerFactory,
  77. \Magento\Framework\Reflection\TypeProcessor $typeProcessor,
  78. \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
  79. \Magento\Webapi\Model\Soap\Wsdl\Generator $wsdlGenerator
  80. ) {
  81. if (!extension_loaded('soap')) {
  82. throw new \Magento\Framework\Webapi\Exception(
  83. __('SOAP extension is not loaded.'),
  84. 0,
  85. \Magento\Framework\Webapi\Exception::HTTP_INTERNAL_ERROR
  86. );
  87. }
  88. $this->_areaList = $areaList;
  89. $this->_configScope = $configScope;
  90. $this->_request = $request;
  91. $this->_storeManager = $storeManager;
  92. $this->_soapServerFactory = $soapServerFactory;
  93. $this->_typeProcessor = $typeProcessor;
  94. $this->_scopeConfig = $scopeConfig;
  95. $this->wsdlGenerator = $wsdlGenerator;
  96. }
  97. /**
  98. * Handle SOAP request. Response is sent by SOAP server.
  99. *
  100. * @return void
  101. */
  102. public function handle()
  103. {
  104. $rawRequestBody = file_get_contents('php://input');
  105. $this->_checkRequest($rawRequestBody);
  106. $options = ['encoding' => $this->getApiCharset(), 'soap_version' => SOAP_1_2];
  107. $soapServer = $this->_soapServerFactory->create($this->getWsdlLocalUri(), $options);
  108. $soapServer->handle($rawRequestBody);
  109. }
  110. /**
  111. * Get WSDL local URI
  112. *
  113. * Local WSDL URI is used to be able to pass wsdl schema to SoapServer without authorization
  114. *
  115. * @return string
  116. */
  117. private function getWsdlLocalUri()
  118. {
  119. $wsdlBody = $this->wsdlGenerator->generate(
  120. $this->_request->getRequestedServices(),
  121. $this->_request->getScheme(),
  122. $this->_request->getHttpHost(),
  123. $this->generateUri()
  124. );
  125. return 'data://text/plain;base64,'.base64_encode($wsdlBody);
  126. }
  127. /**
  128. * Retrieve charset used in SOAP API.
  129. *
  130. * @return string
  131. */
  132. public function getApiCharset()
  133. {
  134. $charset = $this->_scopeConfig->getValue(
  135. self::CONFIG_PATH_SOAP_CHARSET,
  136. \Magento\Store\Model\ScopeInterface::SCOPE_STORE
  137. );
  138. return $charset ? $charset : self::SOAP_DEFAULT_ENCODING;
  139. }
  140. /**
  141. * Get SOAP endpoint URL.
  142. *
  143. * @param bool $isWsdl
  144. * @return string
  145. */
  146. public function generateUri($isWsdl = false)
  147. {
  148. $params = [self::REQUEST_PARAM_SERVICES => $this->_request->getParam(self::REQUEST_PARAM_SERVICES)];
  149. if ($isWsdl) {
  150. $params[self::REQUEST_PARAM_WSDL] = true;
  151. }
  152. $query = http_build_query($params, '', '&');
  153. return $this->getEndpointUri() . '?' . $query;
  154. }
  155. /**
  156. * Generate URI of SOAP endpoint.
  157. *
  158. * @return string
  159. */
  160. public function getEndpointUri()
  161. {
  162. $storeCode = $this->_storeManager->getStore()->getCode() === \Magento\Store\Model\Store::ADMIN_CODE
  163. ? \Magento\Webapi\Controller\PathProcessor::ALL_STORE_CODE
  164. : $this->_storeManager->getStore()->getCode();
  165. return $this->_storeManager->getStore()->getBaseUrl()
  166. . $this->_areaList->getFrontName($this->_configScope->getCurrentScope())
  167. . '/' . $storeCode;
  168. }
  169. /**
  170. * Generate exception if request is invalid.
  171. *
  172. * @param string $soapRequest
  173. * @throws \Magento\Framework\Webapi\Exception With invalid SOAP extension
  174. * @return $this
  175. */
  176. protected function _checkRequest($soapRequest)
  177. {
  178. $dom = new \DOMDocument();
  179. if (strlen($soapRequest) == 0 || !$dom->loadXML($soapRequest)) {
  180. throw new \Magento\Framework\Webapi\Exception(
  181. __('Invalid XML'),
  182. 0,
  183. \Magento\Framework\Webapi\Exception::HTTP_INTERNAL_ERROR
  184. );
  185. }
  186. foreach ($dom->childNodes as $child) {
  187. if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) {
  188. throw new \Magento\Framework\Webapi\Exception(
  189. __('Invalid XML: Detected use of illegal DOCTYPE'),
  190. 0,
  191. \Magento\Framework\Webapi\Exception::HTTP_INTERNAL_ERROR
  192. );
  193. }
  194. }
  195. return $this;
  196. }
  197. }