Passed
Push — 1.11.x ( 680d76...6673eb )
by
unknown
13:22 queued 51s
created

track()   D

Complexity

Conditions 18
Paths 32

Size

Total Lines 103
Code Lines 71

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 71
c 1
b 0
f 1
dl 0
loc 103
rs 4.8666
cc 18
nc 32
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
 * (c) Copyright Ascensio System SIA 2024.
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 *     http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
require_once __DIR__.'/../../main/inc/global.inc.php';
18
19
use ChamiloSession as Session;
20
use Onlyoffice\DocsIntegrationSdk\Models\Callback as OnlyofficeCallback;
21
use Onlyoffice\DocsIntegrationSdk\Models\CallbackDocStatus;
22
23
$plugin = OnlyofficePlugin::create();
24
25
if (isset($_GET['hash']) && !empty($_GET['hash'])) {
26
27
    @header('Content-Type: application/json; charset=utf-8');
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for header(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

27
    /** @scrutinizer ignore-unhandled */ @header('Content-Type: application/json; charset=utf-8');

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
Bug introduced by
Are you sure the usage of header('Content-Type: ap...n/json; charset=utf-8') is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
28
    @header('X-Robots-Tag: noindex');
0 ignored issues
show
Bug introduced by
Are you sure the usage of header('X-Robots-Tag: noindex') is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
29
    @header('X-Content-Type-Options: nosniff');
0 ignored issues
show
Bug introduced by
Are you sure the usage of header('X-Content-Type-Options: nosniff') is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
30
31
    $appSettings = new OnlyofficeAppsettings($plugin);
32
    $jwtManager = new OnlyofficeJwtManager($appSettings);
33
    list($hashData, $error) = $jwtManager->readHash($_GET['hash'], api_get_security_key());
34
    if (null === $hashData) {
35
        error_log("ONLYOFFICE CALLBACK: ERROR - Hash inválido: ".$error);
36
        exit(json_encode(['status' => 'error', 'error' => $error]));
37
    }
38
39
    $type = $hashData->type;
40
    $courseId = $hashData->courseId;
41
    $userId = $hashData->userId;
42
    $docId = $hashData->docId;
43
    $groupId = $hashData->groupId;
44
    $sessionId = $hashData->sessionId;
45
    $docPath = isset($_GET['docPath']) ? urldecode($_GET['docPath']) : ($hashData->docPath ?? null);
46
47
    if (!empty($userId)) {
48
        $userInfo = api_get_user_info($userId);
49
    } else {
50
        exit(json_encode(['error' => 'User not found']));
51
    }
52
53
    if (api_is_anonymous()) {
54
        $loggedUser = [
55
            'user_id' => $userInfo['id'],
56
            'status' => $userInfo['status'],
57
            'uidReset' => true,
58
        ];
59
60
        Session::write('_user', $loggedUser);
61
        Login::init_user($loggedUser['user_id'], true);
62
    } else {
63
        $userId = api_get_user_id();
64
    }
65
66
    switch ($type) {
67
        case 'track':
68
            $callbackResponseArray = track();
69
            exit(json_encode($callbackResponseArray));
70
        case 'download':
71
            $callbackResponseArray = download();
72
            exit(json_encode($callbackResponseArray));
73
        case 'empty':
74
            $callbackResponseArray = emptyFile();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $callbackResponseArray is correct as emptyFile() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
75
            exit(json_encode($callbackResponseArray));
76
        default:
77
            exit(json_encode(['status' => 'error', 'error' => '404 Method not found']));
78
    }
79
}
80
81
/**
82
 * Handle request from the document server with the document status information.
83
 */
84
function track(): array
85
{
86
    global $courseCode;
87
    global $userId;
88
    global $docId;
89
    global $docPath;
90
    global $groupId;
91
    global $sessionId;
92
    global $courseInfo;
93
    global $appSettings;
94
    global $jwtManager;
95
96
    $body_stream = file_get_contents('php://input');
97
    if ($body_stream === false) {
98
        return ['error' => 'Bad Request'];
99
    }
100
101
    $data = json_decode($body_stream, true);
102
103
    if (null === $data) {
104
        return ['error' => 'Bad Response'];
105
    }
106
107
    if ($data['status'] == 4) {
108
        return ['status' => 'success', 'message' => 'No changes detected'];
109
    }
110
111
    if ($jwtManager->isJwtEnabled()) {
112
        if (!empty($data['token'])) {
113
            try {
114
                $payload = $jwtManager->decode($data['token'], $appSettings->getJwtKey());
115
            } catch (UnexpectedValueException $e) {
116
                return ['status' => 'error', 'error' => '403 Access denied'];
117
            }
118
        } else {
119
            $token = substr(getallheaders()[$appSettings->getJwtHeader()], strlen('Bearer '));
120
            try {
121
                $decodeToken = $jwtManager->decode($token, $appSettings->getJwtKey());
122
                $payload = $decodeToken->payload;
123
            } catch (UnexpectedValueException $e) {
124
                return ['status' => 'error', 'error' => '403 Access denied'];
125
            }
126
        }
127
    }
128
129
    if (!empty($docPath)) {
130
        $docPath = urldecode($docPath);
131
        $filePath = api_get_path(SYS_COURSE_PATH).$docPath;
132
133
        if (!file_exists($filePath)) {
134
            return ['status' => 'error', 'error' => 'File not found'];
135
        }
136
137
        $documentKey = basename($docPath);
138
        if ($data['status'] == 2 || $data['status'] == 3) {
139
            if (!empty($data['url'])) {
140
                $newContent = file_get_contents($data['url']);
141
                if ($newContent === false) {
142
                    return ['status' => 'error', 'error' => 'Failed to fetch document'];
143
                }
144
145
                if (file_put_contents($filePath, $newContent) === false) {
146
                    return ['status' => 'error', 'error' => 'Failed to save document'];
147
                }
148
            } else {
149
                return ['status' => 'error', 'error' => 'No file URL provided'];
150
            }
151
        }
152
    } else if (!empty($docId)) {
153
        $docInfo = DocumentManager::get_document_data_by_id($docId, $courseCode, false, $sessionId);
154
        if (!$docInfo || !file_exists($docInfo['absolute_path'])) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $docInfo of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
155
            return ['status' => 'error', 'error' => 'File not found'];
156
        }
157
158
        $documentKey = $docId;
159
        $data['url'] = $payload->url ?? null;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $payload does not seem to be defined for all execution paths leading up to this point.
Loading history...
160
        $data['status'] = $payload->status;
161
    } else {
162
        return ['status' => 'error', 'error' => 'File not found'];
163
    }
164
165
    $docStatus = new CallbackDocStatus($data['status']);
166
    $callback = new OnlyofficeCallback();
167
    $callback->setStatus($docStatus);
168
    $callback->setKey($documentKey);
169
    $callback->setUrl($data['url']);
170
    $callbackService = new OnlyofficeCallbackService(
171
        $appSettings,
172
        $jwtManager,
173
        [
174
            'courseCode' => $courseCode,
175
            'userId' => $userId,
176
            'docId' => $docId ?? '',
177
            'docPath' => $docPath ?? '',
178
            'groupId' => $groupId,
179
            'sessionId' => $sessionId,
180
            'courseInfo' => $courseInfo,
181
        ]
182
    );
183
184
    $result = $callbackService->processCallback($callback, $documentKey);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $result is correct as $callbackService->proces...callback, $documentKey) targeting Onlyoffice\DocsIntegrati...vice::processCallback() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
185
186
    return $result;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $result returns the type null which is incompatible with the type-hinted return array.
Loading history...
187
}
188
189
/**
190
 * Downloading file by the document service.
191
 */
192
function download()
193
{
194
    global $plugin;
195
    global $courseCode;
196
    global $userId;
197
    global $docId;
198
    global $groupId;
199
    global $docPath;
200
    global $courseCode;
201
    global $sessionId;
202
    global $courseInfo;
203
    global $appSettings;
204
    global $jwtManager;
205
206
    if ($jwtManager->isJwtEnabled()) {
207
        $token = substr(getallheaders()[$appSettings->getJwtHeader()], strlen('Bearer '));
208
        try {
209
            $payload = $jwtManager->decode($token, $appSettings->getJwtKey());
210
        } catch (UnexpectedValueException $e) {
211
            return ['status' => 'error', 'error' => '403 Access denied'];
212
        }
213
    }
214
215
    if (!empty($docPath)) {
216
        $filePath = api_get_path(SYS_COURSE_PATH) . urldecode($docPath);
217
218
        if (!file_exists($filePath)) {
219
            return ['status' => 'error', 'error' => 'File not found'];
220
        }
221
222
        $docInfo = [
223
            'title' => basename($filePath),
224
            'absolute_path' => $filePath,
225
        ];
226
    } else if (!empty($docId) && !empty($courseCode)) {
227
        $docInfo = DocumentManager::get_document_data_by_id($docId, $courseCode, false, $sessionId);
228
        if (!$docInfo || !file_exists($docInfo['absolute_path'])) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $docInfo of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
229
            return ['status' => 'error', 'error' => 'File not found'];
230
        }
231
232
        $filePath = $docInfo['absolute_path'];
233
    } else {
234
        return ['status' => 'error', 'error' => 'Invalid request'];
235
    }
236
237
    @header('Content-Type: application/octet-stream');
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for header(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

237
    /** @scrutinizer ignore-unhandled */ @header('Content-Type: application/octet-stream');

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
Bug introduced by
Are you sure the usage of header('Content-Type: application/octet-stream') is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
238
    @header('Content-Disposition: attachment; filename='.$docInfo['title']);
0 ignored issues
show
Bug introduced by
Are you sure the usage of header('Content-Disposit...=' . $docInfo['title']) is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
239
240
    readfile($filePath);
241
    exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
242
}
243
244
/**
245
 * Downloading empty file by the document service.
246
 */
247
function emptyFile()
248
{
249
    global $plugin;
250
    global $type;
251
    global $courseCode;
252
    global $userId;
253
    global $docId;
254
    global $groupId;
255
    global $sessionId;
256
    global $courseInfo;
257
    global $appSettings;
258
    global $jwtManager;
259
260
    if ($type !== 'empty') {
261
        $result['status'] = 'error';
0 ignored issues
show
Comprehensibility Best Practice introduced by
$result was never initialized. Although not strictly required by PHP, it is generally a good practice to add $result = array(); before regardless.
Loading history...
262
        $result['error'] = 'Download empty with other action';
263
264
        return $result;
265
    }
266
267
    if ($jwtManager->isJwtEnabled()) {
268
        $token = substr(getallheaders()[$appSettings->getJwtHeader()], strlen('Bearer '));
269
        try {
270
            $payload = $jwtManager->decode($token, $appSettings->getJwtKey());
271
        } catch (UnexpectedValueException $e) {
272
            $result['status'] = 'error';
273
            $result['error'] = '403 Access denied';
274
275
            return $result;
276
        }
277
    }
278
279
    $template = TemplateManager::getEmptyTemplate('docx');
280
281
    if (!$template) {
282
        $result['status'] = 'error';
283
        $result['error'] = 'File not found';
284
285
        return $result;
286
    }
287
288
    @header('Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document');
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for header(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

288
    /** @scrutinizer ignore-unhandled */ @header('Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document');

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
Bug introduced by
Are you sure the usage of header('Content-Type: ap...processingml.document') is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
289
    @header('Content-Disposition: attachment; filename='.'docx.docx');
0 ignored issues
show
Bug introduced by
Are you sure the usage of header('Content-Disposit...lename=' . 'docx.docx') is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
290
    readfile($template);
291
    exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
292
}
293