This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * curlsoapclient - SoapClient with ext-curl. - |
||
4 | * |
||
5 | * @author aaharu |
||
6 | * @copyright Copyright (c) 2014 aaharu |
||
7 | * @license MIT License |
||
8 | */ |
||
9 | |||
10 | namespace Aaharu\Soap; |
||
11 | |||
12 | use SoapClient; |
||
13 | use SoapFault; |
||
14 | |||
15 | /** |
||
16 | * @see https://github.com/php/php-src/tree/master/ext/soap |
||
17 | */ |
||
18 | class CurlSoapClient extends SoapClient |
||
19 | { |
||
20 | protected $curl = null; ///< cURL handle |
||
21 | protected $redirect_max; ///< max redirect counts |
||
22 | protected $curl_timeout; ///< cURL request time-out seconds |
||
23 | protected $proxy_type = CURLPROXY_HTTP; ///< proxy_type such as http, socks4, socks5 |
||
24 | private $redirect_count = 0; |
||
25 | |||
26 | 13 | public function __construct($wsdl, array $options) |
|
27 | { |
||
28 | 13 | parent::__construct($wsdl, $options); |
|
29 | 13 | $this->redirect_max = 5; |
|
30 | 13 | if (isset($options['redirect_max'])) { |
|
31 | 1 | $this->redirect_max = (int)$options['redirect_max']; |
|
32 | } |
||
33 | 13 | $this->curl_timeout = 30; |
|
34 | 13 | if (isset($options['curl_timeout'])) { |
|
35 | 1 | $this->curl_timeout = (int)$options['curl_timeout']; |
|
36 | } |
||
37 | 13 | if (isset($options['proxy_type']) && |
|
38 | 13 | in_array($options['proxy_type'], ['http', 'socks4', 'socks5'], true)) { |
|
39 | $this->proxy_type = $options['proxy_type']; |
||
40 | } |
||
41 | 13 | $this->curl = curl_init(); |
|
42 | 13 | $this->_cookies = []; |
|
43 | 13 | } |
|
44 | |||
45 | 13 | public function __destruct() |
|
46 | { |
||
47 | 13 | if (isset($this->curl)) { |
|
48 | 13 | curl_close($this->curl); |
|
49 | } |
||
50 | 13 | } |
|
51 | |||
52 | 1 | public function ___curlSetOpt($option, $value) |
|
53 | { |
||
54 | 1 | curl_setopt($this->curl, $option, $value); |
|
55 | 1 | } |
|
56 | |||
57 | 1 | public function __getCookies() |
|
58 | { |
||
59 | 1 | return $this->_cookies; |
|
60 | } |
||
61 | |||
62 | 1 | public function __setCookie($name, $value = null) |
|
63 | { |
||
64 | 1 | if (!isset($value)) { |
|
65 | 1 | unset($this->_cookies[$name]); |
|
66 | 1 | return; |
|
67 | } |
||
68 | 1 | $this->_cookies[$name] = (array)$value; |
|
69 | 1 | } |
|
70 | |||
71 | /** |
||
72 | * Execute SOAP requests. |
||
73 | * |
||
74 | * @param string $request SOAP request |
||
75 | * @param string $location SOAP address |
||
76 | * @param string $action SOAP action |
||
77 | * @param int $version SOAP version |
||
78 | * @param int $one_way |
||
79 | * @throws \Exception |
||
80 | * @throws \SoapFault |
||
81 | * @return string|object (string) SOAP response / (object) SoapFault object |
||
82 | */ |
||
83 | 13 | public function __doRequest($request, $location, $action, $version, $one_way = 0) |
|
84 | { |
||
85 | 13 | curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, true); |
|
86 | 13 | curl_setopt($this->curl, CURLOPT_HEADER, true); |
|
87 | 13 | curl_setopt($this->curl, CURLOPT_POSTFIELDS, $request); |
|
88 | 13 | if (isset($this->trace) && $this->trace) { |
|
89 | 3 | curl_setopt($this->curl, CURLINFO_HEADER_OUT, true); |
|
90 | } |
||
91 | |||
92 | 13 | $this->___configHeader($action, $version); |
|
93 | 13 | $this->___configCompression(); |
|
94 | 13 | $this->___configTimeout(); |
|
95 | 13 | if (!$this->___isEmptyExtProperty('_user_agent')) { |
|
96 | 1 | curl_setopt($this->curl, CURLOPT_USERAGENT, $this->_user_agent); |
|
97 | } |
||
98 | 13 | $this->___configHttpAuthentication(); |
|
99 | 13 | $this->___configProxy(); |
|
100 | 13 | if (!$this->___isEmptyExtProperty('_ssl_method')) { |
|
101 | 1 | switch ($this->_ssl_method) { |
|
102 | 1 | case SOAP_SSL_METHOD_SSLv2: |
|
103 | curl_setopt($this->curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_SSLv2); |
||
104 | break; |
||
105 | 1 | case SOAP_SSL_METHOD_SSLv3: |
|
106 | curl_setopt($this->curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_SSLv3); |
||
107 | break; |
||
108 | default: |
||
109 | 1 | curl_setopt($this->curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_DEFAULT); |
|
110 | 1 | break; |
|
111 | } |
||
112 | } |
||
113 | |||
114 | try { |
||
115 | 13 | $response = $this->___curlCall($location); |
|
116 | 7 | } catch (SoapFault $fault) { |
|
117 | 7 | if (isset($this->_exceptions) && empty($this->_exceptions)) { |
|
118 | // if exceptions option is false, return SoapFault object |
||
119 | 1 | return $fault; |
|
120 | } |
||
121 | 6 | throw $fault; |
|
122 | } |
||
123 | |||
124 | 6 | if ($one_way) { |
|
125 | return ''; |
||
126 | } |
||
127 | |||
128 | 6 | return $response; |
|
129 | } |
||
130 | |||
131 | /** |
||
132 | * set CURLOPT_HTTPHEADER. |
||
133 | * |
||
134 | * @param string $action SOAP action |
||
135 | * @param int $version SOAP version |
||
136 | */ |
||
137 | 13 | private function ___configHeader($action, $version) |
|
138 | { |
||
139 | 13 | $header = []; |
|
140 | 13 | if (isset($this->_keep_alive) && empty($this->_keep_alive)) { |
|
141 | 1 | $header[] = 'Connection: close'; |
|
142 | } else { |
||
143 | 12 | $header[] = 'Connection: Keep-Alive'; |
|
144 | } |
||
145 | 13 | if ($version === SOAP_1_2) { |
|
146 | 1 | $header[] = "Content-Type: application/soap+xml; charset=utf-8; action=\"{$action}\""; |
|
147 | } else { |
||
148 | 12 | $header[] = 'Content-Type: text/xml; charset=utf-8'; |
|
149 | 12 | $header[] = "SOAPAction: \"{$action}\""; |
|
150 | } |
||
151 | 13 | curl_setopt($this->curl, CURLOPT_HTTPHEADER, $header); |
|
152 | 13 | } |
|
153 | |||
154 | /** |
||
155 | * set CURLOPT_ENCODING. |
||
156 | */ |
||
157 | 13 | private function ___configCompression() |
|
158 | { |
||
159 | 13 | if (!isset($this->compression)) { |
|
160 | 10 | return; |
|
161 | } |
||
162 | 3 | if ($this->compression & SOAP_COMPRESSION_ACCEPT) { |
|
163 | 1 | curl_setopt($this->curl, CURLOPT_ENCODING, ''); |
|
164 | 2 | } elseif ($this->compression & SOAP_COMPRESSION_DEFLATE) { |
|
165 | 1 | curl_setopt($this->curl, CURLOPT_ENCODING, 'deflate'); |
|
166 | } else { |
||
167 | 1 | curl_setopt($this->curl, CURLOPT_ENCODING, 'gzip'); |
|
168 | } |
||
169 | 3 | } |
|
170 | |||
171 | /** |
||
172 | * set CURLOPT_CONNECTTIMEOUT and CURLOPT_TIMEOUT. |
||
173 | */ |
||
174 | 13 | private function ___configTimeout() |
|
175 | { |
||
176 | 13 | $connection_timeout = 10; // default |
|
177 | 13 | if (!$this->___isEmptyExtProperty('_connection_timeout')) { |
|
178 | 1 | $connection_timeout = $this->_connection_timeout; |
|
179 | } |
||
180 | 13 | curl_setopt($this->curl, CURLOPT_CONNECTTIMEOUT, $connection_timeout); |
|
181 | 13 | curl_setopt($this->curl, CURLOPT_TIMEOUT, $this->curl_timeout); |
|
182 | 13 | } |
|
183 | |||
184 | /** |
||
185 | * set CURLOPT_USERPWD and CURLOPT_HTTPAUTH. |
||
186 | */ |
||
187 | 13 | private function ___configHttpAuthentication() |
|
188 | { |
||
189 | 13 | if ($this->___isEmptyExtProperty('_login') || $this->___isEmptyExtProperty('_password')) { |
|
190 | 11 | return; |
|
191 | } |
||
192 | 2 | curl_setopt($this->curl, CURLOPT_USERPWD, $this->_login . ':' . $this->_password); |
|
193 | 2 | View Code Duplication | if (property_exists($this, '_digest')) { |
0 ignored issues
–
show
|
|||
194 | 1 | curl_setopt($this->curl, CURLOPT_HTTPAUTH, CURLAUTH_ANYSAFE); |
|
195 | } else { |
||
196 | 1 | curl_setopt($this->curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY); |
|
197 | } |
||
198 | 2 | } |
|
199 | |||
200 | /** |
||
201 | * set proxy options. |
||
202 | */ |
||
203 | 13 | private function ___configProxy() |
|
204 | { |
||
205 | 13 | if ($this->___isEmptyExtProperty('_proxy_host')) { |
|
206 | 12 | return; |
|
207 | } |
||
208 | 1 | curl_setopt($this->curl, CURLOPT_PROXY, $this->_proxy_host); |
|
209 | 1 | if (!$this->___isEmptyExtProperty('_proxy_port')) { |
|
210 | 1 | curl_setopt($this->curl, CURLOPT_PROXYPORT, $this->_proxy_port); |
|
211 | } |
||
212 | 1 | if (!$this->___isEmptyExtProperty('_proxy_login') && !$this->___isEmptyExtProperty('_proxy_password')) { |
|
213 | 1 | curl_setopt($this->curl, CURLOPT_PROXYUSERPWD, $this->_proxy_login . ':' . $this->_proxy_password); |
|
214 | } |
||
215 | 1 | View Code Duplication | if (property_exists($this, '_digest')) { |
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
216 | curl_setopt($this->curl, CURLOPT_PROXYAUTH, CURLAUTH_ANYSAFE); |
||
217 | } else { |
||
218 | 1 | curl_setopt($this->curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY); |
|
219 | } |
||
220 | 1 | if ($this->proxy_type === 'socks5') { |
|
221 | curl_setopt($this->curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5); |
||
222 | 1 | } elseif ($this->proxy_type === 'socks4') { |
|
223 | curl_setopt($this->curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4); |
||
224 | 1 | } elseif ($this->proxy_type === 'http') { |
|
225 | // @see http://stackoverflow.com/questions/12288956/what-is-the-curl-option-curlopt-httpproxytunnel-means |
||
226 | curl_setopt($this->curl, CURLOPT_HTTPPROXYTUNNEL, true); |
||
227 | } |
||
228 | 1 | } |
|
229 | |||
230 | /** |
||
231 | * Request cURL. |
||
232 | * |
||
233 | * @param string $location SOAP address |
||
234 | * @param string $location |
||
235 | * @throws \SoapFault |
||
236 | * @return mixed response body |
||
237 | */ |
||
238 | 13 | private function ___curlCall($location) |
|
239 | { |
||
240 | 13 | curl_setopt($this->curl, CURLOPT_URL, $location); |
|
241 | |||
242 | 13 | if (!empty($this->_cookies)) { |
|
243 | 1 | $cookies = []; |
|
244 | 1 | foreach ($this->_cookies as $cookie_name => $cookie_value) { |
|
245 | 1 | $cookies[] = $cookie_name . '=' . $cookie_value[0]; |
|
246 | } |
||
247 | 1 | curl_setopt($this->curl, CURLOPT_COOKIE, implode('; ', $cookies)); |
|
248 | } |
||
249 | |||
250 | 13 | $response = curl_exec($this->curl); |
|
251 | 13 | if ($response === false) { |
|
252 | 2 | throw new SoapFault( |
|
253 | 2 | 'HTTP', |
|
254 | 2 | 'Error Fetching http, ' . curl_error($this->curl) . ' (' . curl_errno($this->curl) . ')' |
|
255 | ); |
||
256 | } |
||
257 | |||
258 | 11 | $header_size = curl_getinfo($this->curl, CURLINFO_HEADER_SIZE); |
|
259 | 11 | $response_header = substr($response, 0, $header_size); |
|
260 | 11 | $response_body = substr($response, $header_size); |
|
261 | 11 | $http_code = curl_getinfo($this->curl, CURLINFO_HTTP_CODE); |
|
262 | |||
263 | 11 | if (isset($this->trace) && $this->trace) { |
|
264 | 3 | $this->__last_request_headers = curl_getinfo($this->curl, CURLINFO_HEADER_OUT); |
|
265 | 3 | $this->__last_response_headers = $response_header; |
|
266 | } |
||
267 | |||
268 | 11 | if ($http_code >= 300 && $http_code < 400) { |
|
269 | 4 | $tmp = stristr($response_header, 'Location:'); |
|
270 | 4 | $line_end = strpos($tmp, "\n"); // "\r" will be trimmed |
|
271 | 4 | if ($line_end === false) { |
|
272 | 1 | throw new SoapFault('HTTP', 'Error Redirecting, No Location'); |
|
273 | } |
||
274 | 3 | $new_location = trim(substr($tmp, 9, $line_end - 9)); |
|
275 | 3 | $url = parse_url($new_location); |
|
276 | 3 | if ($url === false || |
|
277 | 3 | empty($url['scheme']) || |
|
278 | 3 | preg_match('/^https?$/i', $url['scheme']) !== 1 |
|
279 | ) { |
||
280 | 1 | throw new SoapFault('HTTP', 'Error Redirecting, Invalid Location'); |
|
281 | } |
||
282 | 2 | if (++$this->redirect_count > $this->redirect_max) { |
|
283 | 1 | throw new SoapFault('HTTP', 'Redirection limit reached, aborting'); |
|
284 | } |
||
285 | 2 | return $this->___curlCall($new_location); |
|
286 | } |
||
287 | |||
288 | 8 | if ($http_code >= 400 && $this->___isErrorResponse($response_body)) { |
|
289 | 2 | $string_http_code = (string)$http_code; |
|
290 | 2 | $code_position = strpos($response_header, $string_http_code); |
|
291 | 2 | $tmp = substr($response_header, $code_position + strlen($string_http_code)); |
|
292 | 2 | $http_message = trim(strstr($tmp, "\n", true)); |
|
293 | 2 | throw new SoapFault('HTTP', $http_message); |
|
294 | } |
||
295 | |||
296 | 6 | return $response_body; |
|
297 | } |
||
298 | |||
299 | /** |
||
300 | * check body is XML or not |
||
301 | * |
||
302 | * @param string $response_body server response body |
||
303 | * @return boolean |
||
304 | */ |
||
305 | 4 | private function ___isErrorResponse($response_body) |
|
306 | { |
||
307 | 4 | $response_length = strlen($response_body); |
|
308 | 4 | if ($response_length === 0) { |
|
309 | 1 | return true; |
|
310 | } |
||
311 | 3 | $content_type = curl_getinfo($this->curl, CURLINFO_CONTENT_TYPE); |
|
312 | 3 | if (!empty($content_type)) { |
|
313 | 3 | $tmp = explode(';', $content_type, 2); |
|
314 | 3 | $content_type = $tmp[0]; |
|
315 | } |
||
316 | 3 | if ($content_type === 'text/xml' || $content_type === 'application/soap+xml') { |
|
317 | 1 | return false; |
|
318 | } |
||
319 | 2 | $str = ltrim($response_body); |
|
320 | 2 | if (strncmp($str, '<?xml', 5)) { |
|
321 | 1 | return true; |
|
322 | } |
||
323 | 1 | return false; |
|
324 | } |
||
325 | |||
326 | |||
327 | /** |
||
328 | * SoapClient property util |
||
329 | * |
||
330 | * @param string $property property name |
||
331 | * @return boolean |
||
332 | */ |
||
333 | 13 | private function ___isEmptyExtProperty($property) |
|
334 | { |
||
335 | 13 | if (!isset($this->{$property})) { |
|
336 | 13 | return true; |
|
337 | } |
||
338 | 4 | if (is_string($this->{$property})) { |
|
339 | 3 | return strlen($this->{$property}) === 0; |
|
340 | } |
||
341 | |||
342 | 3 | return false; |
|
343 | } |
||
344 | } |
||
345 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.