aboutsummaryrefslogtreecommitdiffstats
path: root/src/XmlRpcMethod.php
blob: 001169bacab699cbac13ba7e9b9f6464daa26e45 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
<?php

// SPDX-FileCopyrightText: 2024 Eilertsens Kodeknekkeri
// SPDX-FileCopyrightText: 2024 Harald Eilertsen
//
// SPDX-License-Identifier: AGPL-3.0-or-later

namespace VolseNet\Webtrap;

use XMLReader;

/**
 * A representation of an XML-RPC method call.
 *
 * This is just a representation to hold information about the attempted
 * call. It does not try to perform any action on it.
 */
class XmlRpcMethod
{
    /**
     * Parse raw XML to an XmlRpcMethod object.
     *
     * We're not very strict when parsing, but trying to extract the
     * most useful information. At the moment that is the method `name`,
     * and an array of the `params` passed to the method.
     *
     * @param string $payload   The raw XML representation of the method call.
     *
     * @return XmlRpcMethod|null
     */
    public static function parse(string $payload): self|null
    {
        $errorflag = libxml_use_internal_errors(true);

        $xml = XMLReader::XML($payload);

        $method_name = null;
        $params = [];
        $expect = null;

        while ($xml->read()) {
            $tag = strtolower($xml->name);
            switch ($tag) {
                case 'methodname':
                case 'value':
                    if ($xml->nodeType === XMLReader::ELEMENT) {
                        $expect = $tag;
                    } else {
                        $expect = null;
                    }
                    break;

                case '#text':
                    if ($xml->hasValue) {
                        switch ($expect) {
                            case 'methodname':
                                $method_name = $xml->value;
                                break;

                            case 'value':
                                $params[] = $xml->value;
                                break;
                        }
                    }
                    break;

                default:
                    // nothing
            }
        }

        $errors = libxml_get_errors();
        libxml_use_internal_errors($errorflag);

        if (! empty($errors)) {
            throw new \RuntimeException(
                'errors while parsing XML',
                $errors[0]->code
            );
        }

        if (! empty($method_name)) {
            return new XmlRpcMethod($method_name, $params);
        }

        return null;
    }

    /**
     * Constructs a new XmlRpcMethod object from the method name and params.
     *
     * @param string $name      The method name
     * @param array $params     An array or params for the method call.
     */
    public function __construct(public string $name, public array $params)
    {
    }
}