Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

workman没有正确设置sapi_globals_struct的request_info #1040

Open
alreadyshow opened this issue Jul 4, 2024 · 3 comments
Open

workman没有正确设置sapi_globals_struct的request_info #1040

alreadyshow opened this issue Jul 4, 2024 · 3 comments

Comments

@alreadyshow
Copy link

问题描述

使用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(&param, service->sdl->source);
			ZVAL_STRING(&readfile, "readfile");
			if (call_user_function(EG(function_table), NULL, &readfile, &readfile_ret, 1, &param ) == FAILURE) {
				soap_server_fault("Server", "Couldn't find WSDL", NULL, NULL, NULL);
			}

			zval_ptr_dtor(&param);
			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)

操作系统环境及workerman/webman等具体版本

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
@walkor
Copy link
Owner

walkor commented Jul 4, 2024

那么问题来了,PHP cli里如何正确设置 sapi_globals_struct的request_info ?

@alreadyshow
Copy link
Author

已经通过改写实现soapserver的功能,手动判断是否有wsdl的请求,如有则返回wsdl文件内容。
代码如下:

<?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");

// 将屏幕打印输出到Worker::$stdoutFile指定的文件中
Worker::$stdoutFile = 'stdout.log';


// 设置进程名称
$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缓存

            $wsdl = file_get_contents('/var/www/interfacems/workman/webman.wsdl');
            if ($request->method() == 'GET' && $request->get('wsdl') !== null) {
                $response = new Response(200, [
                    'Content-Type' => 'application/xml; charset=utf-8',
                ], $wsdl);
                $connection->send($response);
                return;
            }
            
            $server = new SoapServer('/var/www/interfacems/workman/webman.wsdl', array('soap_version' => SOAP_1_2));
            $server->setClass('SoapServ');
            ob_start();
            $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();

@Tinywan
Copy link
Contributor

Tinywan commented Jul 8, 2024

结论是啥

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants