Passed
Push — develop ( c1253e...f72558 )
by Nikolay
12:51
created

GetController::playback()   C

Complexity

Conditions 15
Paths 94

Size

Total Lines 82
Code Lines 66

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 66
c 0
b 0
f 0
dl 0
loc 82
rs 5.9166
cc 15
nc 94
nop 0

How to fix   Long Method    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
 * MikoPBX - free phone system for small business
4
 * Copyright © 2017-2023 Alexey Portnov and Nikolay Beketov
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License along with this program.
17
 * If not, see <https://www.gnu.org/licenses/>.
18
 */
19
20
namespace MikoPBX\PBXCoreREST\Controllers\Cdr;
21
22
23
use MikoPBX\Core\System\Util;
24
use MikoPBX\PBXCoreREST\Controllers\BaseController;
25
use MikoPBX\PBXCoreREST\Http\Response;
26
use MikoPBX\PBXCoreREST\Lib\CdrDBProcessor;
27
use MikoPBX\PBXCoreREST\Lib\FilesManagementProcessor;
28
29
30
/**
31
 * Class GetController
32
 * @RoutePrefix("/pbxcore/api/cdr")
33
 *
34
 * @package MikoPBX\PBXCoreREST\Controllers\Cdr
35
 *
36
 * @examples
37
 *
38
 * The following command can be used to invoke this action:
39
 * curl http://127.0.0.1/pbxcore/api/cdr/getActiveChannels;
40
 *
41
 * Example response:
42
 * [{"start":"2018-02-27 10:45:07","answer":null,"src_num":"206","dst_num":"226","did":"","linkedid":"1519717507.24"}]
43
 *
44
 * The response is an array of arrays with the following fields:
45
 * "start"     => 'TEXT',     // DateTime
46
 * "answer"    => 'TEXT',     // DateTime
47
 * "endtime"   => 'TEXT',     // DateTime
48
 * "src_num"   => 'TEXT',
49
 * "dst_num"   => 'TEXT',
50
 * "linkedid"  => 'TEXT',
51
 * "did"       => 'TEXT'
52
 *
53
 *
54
 * Playback sound
55
 *
56
 * http://172.16.156.212/pbxcore/api/cdr/playback?view=/storage/usbdisk1/mikopbx/voicemailarchive/monitor/2018/05/11/16/mikopbx-1526043925.13_43T4MdXcpT.mp3
57
 * http://172.16.156.212/pbxcore/api/cdr/playback?view=/storage/usbdisk1/mikopbx/voicemailarchive/monitor/2018/06/01/17/mikopbx-1527865189.0_qrQeNUixcV.wav
58
 * http://172.16.156.223/pbxcore/api/cdr/playback?view=/storage/usbdisk1/mikopbx/voicemailarchive/monitor/2018/12/18/09/mikopbx-1545113960.4_gTvBUcLEYh.mp3&download=true&filename=test.mp3
59
 *
60
 *
61
 */
62
class GetController extends BaseController
63
{
64
65
    /**
66
     * This method retrieves the list of active calls  from CDR.
67
     *
68
     * @param string $actionName The name of the action.
69
     *
70
     * Get active channels based on CDR data. These are the unfinished calls (endtime IS NULL).
71
     * @Get("/getActiveChannels")
72
     *
73
     * This method performs playback of a recorded file with scrolling
74
     * @Get("/playback")
75
     *
76
     * New method through Nginx only (TODO::Check auth by lua) (described in nginx.conf)
77
     * @Get("/v2/playback")
78
     *
79
     * @return void
80
     */
81
    public function callAction(string $actionName): void
82
    {
83
        switch ($actionName) {
84
            case 'playback':
85
                $this->playback();
86
                break;
87
            default:
88
                $data = $this->request->getPost();
89
                $this->sendRequestToBackendWorker(FilesManagementProcessor::class, $actionName, $data);
90
        }
91
92
        $this->sendRequestToBackendWorker(CdrDBProcessor::class, $actionName);
93
    }
94
95
    /**
96
     * This method performs playback of a recorded file with scrolling.
97
     * The following API parameters are available:
98
     * - view: Full path to the recording file.
99
     * - download (optional): Specifies whether to download the recording or not.
100
     * - filename (optional): Specifies a custom filename for the downloaded file.
101
     *
102
     * @return void
103
     */
104
    private function playback(): void
105
    {
106
        $filename  = $this->request->get('view');
107
        $extension = Util::getExtensionOfFile($filename);
108
        if (in_array($extension, ['mp3', 'wav']) && Util::recFileExists($filename)) {
109
            $ctype = '';
110
            switch ($extension) {
111
                case 'mp3':
112
                    $ctype = 'audio/mpeg';
113
                    break;
114
                case 'wav':
115
                    $ctype = 'audio/x-wav';
116
                    break;
117
            }
118
            $filesize = filesize($filename);
119
            if (isset($_SERVER['HTTP_RANGE'])) {
120
                $range = $_SERVER['HTTP_RANGE'];
121
                [$param, $range] = explode('=', $range);
122
                if (strtolower(trim($param)) !== 'bytes') {
123
                    $this->sendError(400);
124
125
                    return;
126
                }
127
                $range = explode(',', $range);
128
                $range = explode('-', $range[0]);
129
                if ($range[0] === '') {
130
                    $end   = $filesize - 1;
131
                    $start = $end - (int)$range[0];
132
                } elseif ($range[1] === '') {
133
                    $start = (int)$range[0];
134
                    $end   = $filesize - 1;
135
                } else {
136
                    $start = (int)$range[0];
137
                    $end   = (int)$range[1];
138
                }
139
                $length = $end - $start + 1;
140
141
                $this->response->resetHeaders();
142
                if ( ! $fp = fopen($filename, 'rb')) {
143
                    $this->sendError(Response::INTERNAL_SERVER_ERROR);
144
                } else {
145
                    $this->response->setRawHeader('HTTP/1.1 206 Partial Content');
146
                    $this->response->setHeader('Content-type', $ctype);
147
                    $this->response->setHeader('Content-Range', "bytes $start-$end/$filesize");
148
                    $this->response->setContentLength($length);
149
                    if ($start) {
150
                        fseek($fp, $start);
151
                    }
152
                    $content = '';
153
                    while ($length) {
154
                        set_time_limit(0);
155
                        $read    = ($length > 8192) ? 8192 : $length;
156
                        $length  -= $read;
157
                        $content .= fread($fp, $read);
158
                    }
159
                    fclose($fp);
160
                    $this->response->setContent($content);
161
                }
162
            } else {
163
                $this->response->setHeader('Content-type', $ctype);
164
                $this->response->setContentLength($filesize);
165
                $this->response->setHeader('Accept-Ranges', 'bytes');
166
                $this->response->setStatusCode(Response::OK, 'OK');
167
                $this->response->setFileToSend($filename);
168
            }
169
            $this->response->setHeader('Server', 'nginx');
170
171
            $is_download = ! empty($this->request->get('download'));
172
            if ($is_download) {
173
                $new_filename = $this->request->get('filename');
174
                if (empty($new_filename)) {
175
                    $new_filename = basename($filename);
176
                }
177
178
                $this->response->setHeader(
179
                    'Content-Disposition',
180
                    "attachment; filename*=UTF-8''" . basename($new_filename)
181
                );
182
            }
183
            $this->response->sendRaw();
184
        } else {
185
            $this->sendError(Response::NOT_FOUND);
186
        }
187
    }
188
189
}