使用workman框架,写一个简单的soap服务,访问wsdl无法正常获取服务定义的xml内容。经调试后发现workman收到请求后没有正确设置 sapi_globals_struct.request_info
workman代码
<?php
use Workerman\Worker;
use Workerman\Protocols\Http\Request;
use Workerman\Protocols\Http\Response;
use Workerman\Connection\TcpConnection;
require_once __DIR__ . '/vendor/autoload.php';
// 创建一个Worker监听2345端口,使用http协议通讯
$http_worker = new Worker("http://0.0.0.0:2345");
// 设置进程名称
$http_worker->name = 'SoapServerWorker';
// 启动4个进程对外提供服务
$http_worker->count = 1;
class SoapServ {
public function sayHello($name) {
return "Hello, " . $name;
}
}
// 当有客户端连接时
$http_worker->onConnect = function ($connection) {
echo "新连接:{$connection->id}\n";
};
// 接收到浏览器发送的数据时回复hello world给浏览器
$http_worker->onMessage = function(TcpConnection $connection, Request $request)
{
if ($request->path() == '/serv') {
try {
ini_set('display_errors', 'On');
ini_set('soap.wsdl_cache_enabled', "0"); //关闭wsdl缓存
ob_start();
$server = new SoapServer('/var/www/interfacems/workman/webman.wsdl', array('soap_version' => SOAP_1_2));
$server->setClass('SoapServ');
$server->handle();
// readfile('webman.wsdl');
$ret = ob_get_clean();
$response = new Response(200, [
'Content-Type' => 'text/xml; charset=utf-8',
], $ret);
$connection->send($response);
return;
} catch (Exception $e) {
// 错误处理逻辑
$connection->send("Error: " . $e->getMessage());
}
} elseif ($request->path() == '/client') {
try {
$client = new SoapClient("http://localhost:8080/serv?wsdl");
$fs = $client->__getFunctions();
// 向浏览器发送hello world
$response = new Response(200, [
'Content-Type' => 'text/json; charset=utf-8',
], json_encode($fs, JSON_UNESCAPED_UNICODE));
$connection->send($response);
} catch (Exception $e) {
// 错误处理逻辑
$connection->send("Error: " . $e->getMessage());
}
} else {
// 如果不是预期的路径,可以发送404响应或其他逻辑
$connection->send("Not Found");
}
};
// 运行worker
Worker::runAll();
调试soap代码 soap.c:1158
printf("request_method = %s query_string=%s \n", SG(request_info).request_method, SG(request_info).query_string);
// 这里修改了源码,打印了request_info属性值,输出为null
if (SG(request_info).request_method &&
strcmp(SG(request_info).request_method, "GET") == 0 &&
SG(request_info).query_string &&
stricmp(SG(request_info).query_string, "wsdl") == 0) {
if (service->sdl) {
/*
char *hdr = emalloc(sizeof("Location: ")+strlen(service->sdl->source));
strcpy(hdr,"Location: ");
strcat(hdr,service->sdl->source);
sapi_add_header(hdr, sizeof("Location: ")+strlen(service->sdl->source)-1, 1);
efree(hdr);
*/
zval readfile, readfile_ret, param;
sapi_add_header("Content-Type: text/xml; charset=utf-8", sizeof("Content-Type: text/xml; charset=utf-8")-1, 1);
ZVAL_STRING(¶m, service->sdl->source);
ZVAL_STRING(&readfile, "readfile");
if (call_user_function(EG(function_table), NULL, &readfile, &readfile_ret, 1, ¶m ) == FAILURE) {
soap_server_fault("Server", "Couldn't find WSDL", NULL, NULL, NULL);
}
zval_ptr_dtor(¶m);
zval_ptr_dtor_str(&readfile);
zval_ptr_dtor(&readfile_ret);
SOAP_SERVER_END_CODE();
return;
} else {
soap_server_fault("Server", "WSDL generation is not supported yet", NULL, NULL, NULL);
/*
sapi_add_header("Content-Type: text/xml; charset=utf-8", sizeof("Content-Type: text/xml; charset=utf-8"), 1);
PUTS("<?xml version=\"1.0\" ?>\n<definitions\n");
PUTS(" xmlns=\"http://schemas.xmlsoap.org/wsdl/\"\n");
PUTS(" targetNamespace=\"");
PUTS(service->uri);
PUTS("\">\n");
PUTS("</definitions>");
*/
SOAP_SERVER_END_CODE();
return;
}
输出:
[root@localhost workman]# php test.php start
Workerman[test.php] start in DEBUG mode
------------------------------------------- WORKERMAN --------------------------------------------
Workerman version:4.1.15 PHP version:8.3.6 Event-Loop:\Workerman\Events\Select
-------------------------------------------- WORKERS ---------------------------------------------
proto user worker listen processes status
tcp root SoapServerWorker http://0.0.0.0:2345 1 [OK]
--------------------------------------------------------------------------------------------------
Press Ctrl+C to stop. Start success.
request_method = (null) query_string=(null)
workman版本信息: "workerman/workerman": "^4.1"
操作系统环境信息:
[root@localhost php-8.3.6]# cat /etc/os-release
NAME="openEuler"
VERSION="22.03 (LTS-SP3)"
ID="openEuler"
VERSION_ID="22.03"
PRETTY_NAME="openEuler 22.03 (LTS-SP3)"
ANSI_COLOR="0;31"
[root@localhost php-8.3.6]# php -v
PHP 8.3.6 (cli) (built: Jul 4 2024 11:02:42) (ZTS DEBUG)
Copyright (c) The PHP Group
Zend Engine v4.3.6, Copyright (c) Zend Technologies
[root@localhost php-8.3.6]# php --ri soap
soap
Soap Client => enabled
Soap Server => enabled
Directive => Local Value => Master Value
soap.wsdl_cache_enabled => On => On
soap.wsdl_cache_dir => /tmp => /tmp
soap.wsdl_cache_ttl => 86400 => 86400
soap.wsdl_cache => 1 => 1
soap.wsdl_cache_limit => 5 => 5
webman是一个php cli的框架,不是c扩展,没有办法直接操作更改内核结构体,除非php提供了接口。
使用php cli启动服务是会正常赋值的。
启动服务:
测试代码:
测试命令:
curl http://localhost:2345/soap.php?wsdl
php -S 是启动php内置的server,和php cli不是一回事
调试php -S 也是第一步进入的是sapi/cli下面的cli_server
php -S栈信息如下:
workman调用栈如下:
看了源码是一个是 do_cli 一个是do_cli_server,难道是php cli就没有设置request_info?
已经通过改写实现soapserver的功能,手动判断是否有wsdl的请求,如有则返回wsdl文件内容。
代码如下: