Edit report at https://bugs.php.net/bug.php?id=49853&edit=1
ID: 49853 Comment by: michaelclark at zagg dot com Reported by: rumana024 at yahoo dot com Summary: Soap Client stream context header option ignored Status: Open Type: Bug Package: SOAP related Operating System: Windows XP PHP Version: 5.2SVN-2009-10-12 (SVN) Block user comment: N Private report: N New Comment: 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); Previous Comments: ------------------------------------------------------------------------ [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. ------------------------------------------------------------------------ [2011-05-09 17:09:04] vidalis dot aris at gmail dot com Using php5.3.6 i couldn't pass extra HTTP headers to the SOAP request. stream_context_create appears to get ignored [VERSION] PHP 5.3.6 with Suhosin-Patch (cli) (built: Apr 18 2011 11:14:25) Copyright (c) 1997-2011 The PHP Group Zend Engine v2.3.0, Copyright (c) 1998-2011 Zend Technologies [CODE] $context = stream_context_create(array('http' => array('header' => "token: 85E91AAC-7A4A-11E0-B46B-78E7D1E19752\r\n"))); $soapparams = array( 'stream_context' => $context, 'trace' => 1, 'exceptions' => 1, 'soap_version' => SOAP_1_2, 'encoding' => 'UTF-8', 'features' => SOAP_SINGLE_ELEMENT_ARRAYS ); $client = new SoapClient($wsdl,$soapparams); [REQUEST HEADERS] POST /SocialMetadataService HTTP/1.1 Host: test.host.com:9080 Connection: Keep-Alive User-Agent: PHP-SOAP/5.3.6 Content-Type: application/soap+xml; charset=utf-8; action="urn:getObjectID" Content-Length: 331 ------------------------------------------------------------------------ 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