Passed
Push — develop ( 5a77ad...a33561 )
by Портнов
04:54
created

AGIBase::evaluateReadResponse()   B

Complexity

Conditions 10
Paths 5

Size

Total Lines 34
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 22
c 1
b 0
f 0
dl 0
loc 34
rs 7.6666
cc 10
nc 5
nop 2

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
4
namespace MikoPBX\Core\Asterisk;
5
6
class AGIBase {
7
    /**
8
     * Request variables read in on initialization.
9
     *
10
     * Often contains any/all of the following:
11
     *   agi_request - name of agi script
12
     *   agi_channel - current channel
13
     *   agi_language - current language
14
     *   agi_type - channel type (SIP, ZAP, IAX, ...)
15
     *   agi_uniqueid - unique id based on unix time
16
     *   agi_callerid - callerID string
17
     *   agi_dnid - dialed number id
18
     *   agi_rdnis - referring DNIS number
19
     *   agi_context - current context
20
     *   agi_extension - extension dialed
21
     *   agi_priority - current priority
22
     *   agi_enhanced - value is 1.0 if started as an EAGI script
23
     *   agi_accountcode - set by SetAccount in the dialplan
24
     *   agi_network - value is yes if this is a fastagi
25
     *   agi_network_script - name of the script to execute
26
     *
27
     * NOTE: program arguments are still in $_SERVER['argv'].
28
     *
29
     * @var array
30
     * @access public
31
     */
32
    public array $request;
33
34
    /**
35
     * Input Stream
36
     *
37
     * @access private
38
     */
39
    public $in;
40
41
    /**
42
     * Output Stream
43
     *
44
     * @access private
45
     */
46
    public $out;
47
48
    /**
49
     * Application option delimiter
50
     *
51
     * @access public
52
     */
53
    public string  $option_delim = ",";
54
55
    /**
56
     * Constructor
57
     */
58
    public function __construct()
59
    {
60
        ob_implicit_flush(1);
61
        // Open stdin & stdout.
62
        $this->in  = defined('STDIN') ? STDIN  : fopen('php://stdin',  'rb');
63
        $this->out = defined('STDOUT')? STDOUT : fopen('php://stdout', 'wb');
64
        $this->request = [];
65
66
        $this->readRequestData();
67
    }
68
69
    /**
70
     * Считываем переданные скрипту переменные.
71
     */
72
    protected function readRequestData():void{
73
        if($this->in !== false){
74
            $str = PHP_EOL;
75
            // read the request
76
            $resIn = fgets($this->in);
77
            if($resIn !== false){
78
                $str = $resIn;
79
            }
80
            while ($str !== PHP_EOL) {
81
                $this->request[substr($str, 0, strpos($str, ':'))] = trim(substr($str, strpos($str, ':') + 1));
82
                $resIn = fgets($this->in);
83
                if($resIn === false){
84
                    break;
85
                }
86
                $str = $resIn;
87
            }
88
        }
89
    }
90
91
    /**
92
     * Разбор ответа сервера.
93
     * @param $str
94
     * @param $ret
95
     */
96
    protected function evaluateParseResponse($str, &$ret):void{
97
        $ret['result'] = null;
98
        $ret['data']   = '';
99
        if ( (int)$ret['code'] !== 200){
100
            // some sort of error
101
            $ret['data'] = $str;
102
        }else{
103
            // Normal AGI RES OK response
104
            $parse    = explode(' ', trim($str));
105
            $in_token = false;
106
            foreach ($parse as $token) {
107
                if ($in_token){
108
                    // we previously hit a token starting with ')' but not ending in ')'
109
                    $ret['data'] .= ' ' . trim($token, '() ');
110
                    if ($token[strlen($token) - 1] === ')') {
111
                        $in_token = false;
112
                    }
113
                }elseif ($token[0] === '('){
114
                    if ($token[strlen($token) - 1] !== ')') {
115
                        $in_token = true;
116
                    }
117
                    $ret['data'] .= ' ' . trim($token, '() ');
118
                }elseif (strpos($token, '=')){
119
                    $token          = explode('=', $token);
120
                    $ret[$token[0]] = $token[1];
121
                }elseif ($token !== ''){
122
                    $ret['data'] .= ' ' . $token;
123
                }
124
            }
125
            $ret['data'] = trim($ret['data']);
126
        }
127
    }
128
129
    /**
130
     * Чтение ответа сервера.
131
     * @param string $str
132
     * @param array  $ret
133
     * @return bool
134
     */
135
    protected function evaluateReadResponse(string & $str, array & $ret): bool{
136
        $result = true;
137
        if(!is_resource($this->in)){
138
            return $result;
139
        }
140
141
        $count = 0;
142
        do {
143
            $str = trim(fgets($this->in, 4096));
144
        } while ($str === '' && $count++ < 5);
145
146
        if ($count >= 5) {
147
            return false;
148
        }
149
150
        $ret['code'] = substr($str, 0, 3);
151
        $str         = trim(substr($str, 3));
152
153
        if ($str[0] === '-') // We have a multiline response!
154
        {
155
            $count = 0;
156
            $str   = substr($str, 1) . "\n";
157
            $line  = fgets($this->in, 4096);
158
            while (strpos($line, $ret['code']) !== 0 && $count < 5) {
159
                $str   .= $line;
160
                $line  = fgets($this->in, 4096);
161
                $count = (trim($line) === '') ? $count + 1 : 0;
162
            }
163
            if ($count >= 5) {
164
                $result = false;
165
            }
166
        }
167
168
        return $result;
169
    }
170
171
    /**
172
     * Evaluate an AGI command.
173
     *
174
     * @access private
175
     *
176
     * @param string $command
177
     *
178
     * @return array ('code'=>$code, 'result'=>$result, 'data'=>$data)
179
     */
180
    protected function evaluate($command)
181
    {
182
        $broken = ['code' => 500, 'result' => -1, 'data' => ''];
183
184
        if( !is_resource($this->out) ){
185
            return $broken;
186
        }
187
188
        if ( !fwrite($this->out, trim($command) . "\n")) {
189
            return $broken;
190
        }
191
        fflush($this->out);
192
        // parse result
193
        $str = '';
194
        $ret = [];
195
        if(!$this->evaluateReadResponse($str, $ret)){
196
            return $broken;
197
        }
198
        $this->evaluateParseResponse($str, $ret);
199
        return $ret;
200
    }
201
}