Edit report at https://bugs.php.net/bug.php?id=49853&edit=1
ID: 49853 Updated by: dmi...@php.net Reported by: rumana024 at yahoo dot com Summary: Soap Client stream context header option ignored -Status: Assigned +Status: Closed Type: Bug Package: SOAP related Operating System: Windows XP PHP Version: 5.2SVN-2009-10-12 (SVN) Assigned To: dmitry Block user comment: N Private report: N New Comment: This bug has been fixed in SVN. Snapshots of the sources are packaged every three hours; this change will be in the next snapshot. You can grab the snapshot at http://snaps.php.net/. For Windows: http://windows.php.net/snapshots/ Thank you for the report, and for helping us make PHP better. Previous Comments: ------------------------------------------------------------------------ [2011-11-11 23:30:39] michaelclark at zagg dot com So, here's an SVN diff against trunk, seems to be working for the test case I posted. This patch should apply cleanly against anything dating back to the current release, PHP 5.3.8. This patch follows the simple mitigation strategy proposed above. There was an error in the trunk for one of the soap test cases, but it was there even after reverting the patch. Index: ext/soap/php_sdl.c =================================================================== --- ext/soap/php_sdl.c (revision 319075) +++ ext/soap/php_sdl.c (working copy) @@ -3270,7 +3270,7 @@ ZVAL_DOUBLE(http_version, 1.1); php_stream_context_set_option(context, "http", "protocol_version", http_version); zval_ptr_dtor(&http_version); - smart_str_appendl(&headers, "Connection: close", sizeof("Connection: close")-1); + smart_str_appendl(&headers, "Connection: close\r\n", sizeof("Connection: close\r\n")-1); } if (headers.len > 0) { @@ -3278,6 +3278,8 @@ if (!context) { context = php_stream_context_alloc(TSRMLS_C); + } else if (php_stream_context_get_option(context, "http", "header", &tmp) != FAILURE) { + smart_str_appendl(&headers, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp)); } smart_str_0(&headers); ------------------------------------------------------------------------ [2011-11-04 21:15:55] michaelclark at zagg dot com In the TESTCASE, please replace the last line with unlink(ini_get('soap.wsdl_cache_dir').DIRECTORY_SEPARATOR.'wsdl-'.get_current_user().'-'.md5($wsdl)); if you need something a little bit more portable, or to change the WSDL location. ------------------------------------------------------------------------ [2011-11-04 19:00:21] michaelclark at zagg dot com I suspect that my problem is the same as the submitter, so I'm adding this as a comment instead of as a new issue. Again, this has to do with SoapClient, stream_context_create, and custom http headers. Simple TESTCASE: #!/usr/bin/php <?php $wsdl = 'http://www.w3schools.com/webservices/tempconvert.asmx?WSDL'; $apikey = 'this-must-still-be-here'; $c = stream_context_create(array( 'http' => array( 'header' => "apikey: this-must-still-be-here", ) )); var_dump(stream_context_get_options($c)); $soap = new SoapClient($wsdl, array('stream_context' => $c)); var_dump(stream_context_get_options($soap->_stream_context)); unlink('/tmp/wsdl-'.get_current_user().'-d4e1ad3ff31424862843f4814eade4a8'); ?> As you can see from running the code, if the SoapClient needs to download a new WSDL (function get_sdl() called on line 2679 of ext/soap/soap.c - PHP source code is version 5.3.8, function defined at line 3154 of ext/soap/php_sdl.c), AND also the 'protocol_version' option isn't explicitly set in the stream_context (line 3267, file ext/soap/php_sdl.c), it sets the 'protocol_version' option (3271), and sets up a new header - "Connection: close" (3273). The following if statement (3276) sets the http "header" option to the value of that string (3286) - effectively overwriting any custom headers that were supplied. The following if statement (3291) might be making an effort to prevent this (3294,3307), but is ineffective (operating on a pointer to the original I suspect; any copy should be made at the point of initialization, and this might not be copying the context structure itself at all). So - userland mitigation: Set the http 'protocol_version' explicitly to 1.1 in your code, and append the "\r\nConnection: close" header to your custom headers. example: $context = stream_context_create(array( 'http'=>array( 'protocol_version' => 1.1, 'header' => "token: 85E91AAC-7A4A-11E0-B46B-78E7D1E19752\r\n" . "Connection: close" ) )); Thoughts about fixing it: It appears to be safe to pass the Connection: close header implicitly - so the simple solution of appending instead of replacing the custom headers could be good enough, without having to copy, backup, and restore the original context itself. Should that be the easier solution it should be preferred. If the simple solution is used, it would also be nice to have it in the docs. ------------------------------------------------------------------------ [2011-10-27 08:49:00] richard dot deguilhem at laposte dot net I have the same problem with php 5.2.6 To 5.3.8. [VERSION] [CODE class CMyClass extends SoapClient { public function CMyClass($sWsdlUri = '',$aOptions = array()) { $aOptions['stream_context'] = stream_context_create(array( 'http' => array('header'=>"foo: bar\r\n"))); parent::__construct($sWsdlUri, $aOptions); } public function callSoapActionX() { $aParams = array(...); return $this->__soapCall('GetTokenSession', $aParams); } } [REQUEST HEADERS] POST HTTP/1.0 Host: 127.0.0.1:8052 Connection: Keep-Alive User-Agent: PHP-SOAP/5.3.8 Content-Type: application/soap+xml; charset=utf-8; action="GetTokenSession" Content-Length: 532 ------------------------------------------------------------------------ [2011-09-22 10:14:14] dave dot wilcock at gmail dot com [VERSION] PHP 5.3.2 (cli) (built: Apr 27 2010 20:28:18) Copyright (c) 1997-2010 The PHP Group Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies with eAccelerator v0.9.6.1, Copyright (c) 2004-2010 eAccelerator, by eAccelerator [CODE] $str_auth_header = "Authorization: Bearer ". $str_token; $arr_context = array('http' =>array('header' => $str_auth_header)); $obj_context = stream_context_create($arr_context); $arr_options = array ( 'soap_version' => 'SOAP_1_2', 'encoding' => 'UTF-8', 'exceptions' => true, 'trace' => true, 'cache_wsdl' => 'WSDL_CACHE_NONE', 'stream_context' => $obj_context ); $this->obj_connection = new SoapClient(self::STR_BASE_URL, $arr_options); [EXPECTED] Authorization header in HTTP request [GOT] No Authorization header in HTTP request [WORKAROUND/CODE] ini_set('user_agent', 'PHP-SOAP/' . PHP_VERSION . "\r\n" . $str_auth_header); [COMMENT] No idea why appending the user agent string with the headers would work, but it seemingly does. Bizarre. ------------------------------------------------------------------------ The remainder of the comments for this report are too long. To view the rest of the comments, please view the bug report online at https://bugs.php.net/bug.php?id=49853 -- Edit this bug report at https://bugs.php.net/bug.php?id=49853&edit=1