Passed
Push — master ( b85c6b...c02a92 )
by Nils
04:55
created

handleTask()   D

Complexity

Conditions 17
Paths 27

Size

Total Lines 173
Code Lines 104

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 17
eloc 104
c 1
b 0
f 0
nc 27
nop 4
dl 0
loc 173
rs 4.1733

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
 * Teampass - a collaborative passwords manager.
4
 * ---
5
 * This library is distributed in the hope that it will be useful,
6
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
7
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
8
 * ---
9
 *
10
 * @project   Teampass
11
 * @version   
12
 * @file      background_tasks___items_handler.php
13
 * ---
14
 *
15
 * @author    Nils Laumaillé ([email protected])
16
 *
17
 * @copyright 2009-2024 Teampass.net
18
 *
19
 * @license   https://spdx.org/licenses/GPL-3.0-only.html#licenseText GPL-3.0
20
 * ---
21
 *
22
 * @see       https://www.teampass.net
23
 */
24
25
use voku\helper\AntiXSS;
26
use TeampassClasses\NestedTree\NestedTree;
27
use TeampassClasses\SessionManager\SessionManager;
28
use Symfony\Component\HttpFoundation\Request;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Request. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
29
use TeampassClasses\Language\Language;
30
use EZimuel\PHPSecureSession;
31
use TeampassClasses\PerformChecks\PerformChecks;
32
33
34
// Load functions
35
require_once __DIR__.'/../sources/main.functions.php';
36
37
// init
38
loadClasses('DB');
39
$session = SessionManager::getSession();
40
$request = Request::createFromGlobals();
41
$lang = new Language();
42
43
// Load config if $SETTINGS not defined
44
try {
45
    include_once __DIR__.'/../includes/config/tp.config.php';
46
} catch (Exception $e) {
47
    throw new Exception("Error file '/includes/config/tp.config.php' not exists", 1);
48
}
49
50
// Define Timezone
51
date_default_timezone_set(isset($SETTINGS['timezone']) === true ? $SETTINGS['timezone'] : 'UTC');
52
53
// Set header properties
54
header('Content-type: text/html; charset=utf-8');
55
header('Cache-Control: no-cache, no-store, must-revalidate');
56
error_reporting(E_ERROR);
57
// increase the maximum amount of time a script is allowed to run
58
set_time_limit($SETTINGS['task_maximum_run_time']);
59
60
// --------------------------------- //
61
62
require_once __DIR__.'/background_tasks___functions.php';
63
64
$tree = new NestedTree(prefixTable('nested_tree'), 'id', 'parent_id', 'title');
65
66
// Get PHP binary
67
$phpBinaryPath = getPHPBinary();
68
69
// log start
70
$logID = doLog('start', 'item_keys', (isset($SETTINGS['enable_tasks_log']) === true ? (int) $SETTINGS['enable_tasks_log'] : 0));
71
72
73
// Manage the tasks in queue.
74
// Task to treat selection is:
75
// 1- take first is_in_progress === 1
76
// 2- take first is_in_progress === 0 and finished_at === null
77
DB::debugmode(false);
78
$process_to_perform = DB::queryfirstrow(
79
    'SELECT *
80
    FROM ' . prefixTable('processes') . '
81
    WHERE is_in_progress = %i AND process_type IN ("item_copy", "new_item", "update_item", "item_update_create_keys")
82
    ORDER BY increment_id ASC',
83
    1
84
);
85
86
if (DB::count() > 0) {
87
    // handle tasks inside this process
88
    handleTask(
89
        $process_to_perform['increment_id'],
90
        json_decode($process_to_perform['arguments'], true),
91
        $SETTINGS,
92
    );
93
} else {
94
    // search for next process to handle
95
    $process_to_perform = DB::queryfirstrow(
96
        'SELECT *
97
        FROM ' . prefixTable('processes') . '
98
        WHERE is_in_progress = %i AND finished_at = "" AND process_type IN ("item_copy", "new_item", "update_item", "item_update_create_keys")
99
        ORDER BY increment_id ASC',
100
        0
101
    );
102
    //print_r($process_to_perform);
103
    if (DB::count() > 0) {
104
        // update DB - started_at
105
        DB::update(
106
            prefixTable('processes'),
107
            array(
108
                'started_at' => time(),
109
            ),
110
            'increment_id = %i',
111
            $process_to_perform['increment_id']
112
        );
113
114
        provideLog('[PROCESS][#'. $process_to_perform['increment_id'].'][START]', $SETTINGS);
115
        handleTask(
116
            $process_to_perform['increment_id'],
117
            json_decode($process_to_perform['arguments'], true),
118
            $SETTINGS,
119
            $process_to_perform['item_id']
120
        );
121
    } else {
122
123
    }
124
}
125
126
// log end
127
doLog('end', '', (isset($SETTINGS['enable_tasks_log']) === true ? (int) $SETTINGS['enable_tasks_log'] : 0), $logID);
128
129
// launch a new iterative process
130
$process_to_perform = DB::queryfirstrow(
131
    'SELECT *
132
    FROM ' . prefixTable('processes') . '
133
    WHERE is_in_progress = %i AND process_type IN ("item_copy", "new_item", "update_item", "item_update_create_keys")
134
    ORDER BY increment_id DESC',
135
    1
136
);
137
if (DB::count() > 0) {
138
    $process = new Symfony\Component\Process\Process([$phpBinaryPath, __FILE__]);
139
    $process->start();
140
    $process->wait();
141
}
142
143
/**
144
 * Handle the task
145
 *
146
 * @param int   $processId
147
 * @param array $ProcessArguments
148
 * @param array $SETTINGS
149
 *
150
 * @return bool
151
 */
152
function handleTask(int $processId, array $ProcessArguments, array $SETTINGS, int $itemId = null): bool
153
{
154
    provideLog('[PROCESS][#'. $processId.'][START]', $SETTINGS);
155
    $task_to_perform = DB::queryfirstrow(
156
        'SELECT *
157
        FROM ' . prefixTable('processes_tasks') . '
158
        WHERE process_id = %i AND finished_at IS NULL
159
        ORDER BY increment_id ASC',
160
        $processId
161
    );
162
163
    // get the process object
164
    $processObject = json_decode($ProcessArguments['object_key'], true);
165
    
166
    if (DB::count() > 0) {
167
        // check if a linux process is not currently on going
168
        // if sub_task_in_progress === 1 then exit
169
        if ((int) $task_to_perform['sub_task_in_progress'] === 0) {
170
            provideLog('[TASK][#'. $task_to_perform['increment_id'].'][START]', $SETTINGS);
171
172
            // handle next task
173
            $args = json_decode($task_to_perform['task'], true);
174
            //print_r($args);return false;
175
176
            // flag as in progress
177
            DB::update(
178
                prefixTable('processes'),
179
                array(
180
                    'updated_at' => time(),
181
                    'is_in_progress' => 1,
182
                ),
183
                'increment_id = %i',
184
                $processId
185
            );
186
187
            // flag task as on going
188
            if ((int) $args['index'] === 0) {
189
                DB::update(
190
                    prefixTable('processes_tasks'),
191
                    array(
192
                        'is_in_progress' => 1,
193
                    ),
194
                    'increment_id = %i',
195
                    $task_to_perform['increment_id']
196
                );
197
            }
198
199
            // flag sub task in progress as on going
200
            DB::update(
201
                prefixTable('processes_tasks'),
202
                array(
203
                    'sub_task_in_progress' => 1,
204
                ),
205
                'increment_id = %i',
206
                $task_to_perform['increment_id']
207
            );
208
209
            // perform the task step "create_users_files_key"
210
            if ($args['step'] === 'create_users_files_key') {
211
                storeUsersShareKey(
212
                    prefixTable('sharekeys_files'),
213
                    0,
214
                    -1,
215
                    (int) $ProcessArguments['item_id'],
216
                    '',
217
                    false,
218
                    false,
219
                    $processObject['files'],
220
                    array_key_exists('all_users_except_id', $ProcessArguments) === true ? $ProcessArguments['all_users_except_id'] : -1,
221
                    (int) in_array('parent_id', $ProcessArguments) === true ? $ProcessArguments['parent_id'] : -1
0 ignored issues
show
introduced by
The condition (int)in_array('parent_id...cessArguments) === true is always false.
Loading history...
Unused Code introduced by
The call to storeUsersShareKey() has too many arguments starting with (int)in_array('parent_id...ments['parent_id'] : -1. ( Ignorable by Annotation )

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

221
                /** @scrutinizer ignore-call */ 
222
                storeUsersShareKey(

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
222
                );
223
            } elseif ($args['step'] === 'create_users_fields_key') {
224
                storeUsersShareKey(
225
                    prefixTable('sharekeys_fields'),
226
                    0,
227
                    -1,
228
                    (int) $ProcessArguments['item_id'],
229
                    (string) $ProcessArguments['pwd'],
230
                    false,
231
                    false,
232
                    [],
233
                    array_key_exists('all_users_except_id', $ProcessArguments) === true ? $ProcessArguments['all_users_except_id'] : -1,
234
                    (int) in_array('parent_id', $ProcessArguments) === true ? $ProcessArguments['parent_id'] : -1
0 ignored issues
show
introduced by
The condition (int)in_array('parent_id...cessArguments) === true is always false.
Loading history...
235
                );
236
            } elseif ($args['step'] === 'create_users_pwd_key') {
237
                //error_log('create_users_pwd_key - '. print_r($ProcessArguments, true)." - inArray: ".array_key_exists('all_users_except_id', $ProcessArguments));
238
                storeUsersShareKey(
239
                    prefixTable('sharekeys_items'),
240
                    0,
241
                    -1,
242
                    (int) $ProcessArguments['item_id'],
243
                    (string) $ProcessArguments['pwd'],
244
                    false,
245
                    false,
246
                    [],
247
                    array_key_exists('all_users_except_id', $ProcessArguments) === true ? $ProcessArguments['all_users_except_id'] : -1
248
                );
249
            }
250
251
            // update the task status
252
            DB::update(
253
                prefixTable('processes_tasks'),
254
                array(
255
                    'sub_task_in_progress' => 0,    // flag sub task is no more in prgoress
256
                    'task' => json_encode(["status" => "Done"]),
257
                    'is_in_progress' => -1,
258
                    'finished_at' => time(),
259
                    'updated_at' => time(),
260
                ),
261
                'increment_id = %i',
262
                $task_to_perform['increment_id']
263
            );
264
265
            provideLog('[TASK]['.$args['step'].'] starting at '.$args['index'].' is done.', $SETTINGS);
266
267
            // are all tasks done?
268
            $tasks = DB::query(
0 ignored issues
show
Unused Code introduced by
The assignment to $tasks is dead and can be removed.
Loading history...
269
                'SELECT *
270
                FROM ' . prefixTable('processes_tasks') . '
271
                WHERE process_id = %i AND finished_at IS NULL',
272
                $processId
273
            );
274
            if (DB::count() === 0) {
275
                // all tasks are done
276
                provideLog('[PROCESS]['.$processId.'][FINISHED]', $SETTINGS);
277
                DB::debugmode(false);
278
                DB::update(
279
                    prefixTable('processes'),
280
                    array(
281
                        'finished_at' => time(),
282
                        'is_in_progress' => -1,
283
                        'arguments' => json_encode([
284
                            'new_user_id' => isset($ProcessArguments['new_user_id']) === true ? $ProcessArguments['new_user_id'] : '',
285
                        ])
286
                    ),
287
                    'increment_id = %i',
288
                    $processId
289
                );
290
291
                // if item was being updated then remove the edition lock
292
                if (is_null($itemId) === false) {
293
                    DB::delete(prefixTable('items_edition'), 'item_id = %i', $itemId);
294
                }
295
            }
296
            return false;
297
298
        } else {
299
            // Task is currently being in progress by another server process
300
            provideLog('[TASK][#'. $task_to_perform['increment_id'].'][WARNING] Similar task already being processes', $SETTINGS);
301
            return false;
302
        }
303
    } else {
304
        // no more task to perform
305
        provideLog('[PROCESS]['.$processId.'][FINISHED]', $SETTINGS);
306
        DB::update(
307
            prefixTable('processes'),
308
            array(
309
                'finished_at' => time(),
310
                'is_in_progress' => -1,
311
                'arguments' => json_encode([
312
                    'item_id' => isset($ProcessArguments['item_id']) === true ? $ProcessArguments['item_id'] : '',
313
                ])
314
            ),
315
            'increment_id = %i',
316
            $processId
317
        );
318
319
        // if item was being updated then remove the edition lock
320
        if (is_null($itemId) === false) {
321
            DB::delete(prefixTable('items_edition'), 'item_id = %i', $itemId);
322
        }
323
    }
324
    return false;
325
}