Issues (1098)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/dbo/templates.php (14 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
//------------------------------------------------------------------------------
4
//
5
//  eTraxis - Records tracking web-based system
6
//  Copyright (C) 2005-2011  Artem Rodygin
7
//
8
//  This program is free software: you can redistribute it and/or modify
9
//  it under the terms of the GNU General Public License as published by
10
//  the Free Software Foundation, either version 3 of the License, or
11
//  (at your option) any later version.
12
//
13
//  This program is distributed in the hope that it will be useful,
14
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
15
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
//  GNU General Public License for more details.
17
//
18
//  You should have received a copy of the GNU General Public License
19
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
//
21
//------------------------------------------------------------------------------
22
23
/**
24
 * Templates
25
 *
26
 * This module provides API to work with eTraxis templates.
27
 * See also {@link https://github.com/etraxis/etraxis-obsolete/wiki/tbl_templates tbl_templates} database table.
28
 *
29
 * @package DBO
30
 * @subpackage Templates
31
 */
32
33
/**#@+
34
 * Dependency.
35
 */
36
require_once('../engine/engine.php');
37
require_once('../dbo/accounts.php');
38
require_once('../dbo/groups.php');
39
require_once('../dbo/states.php');
40
require_once('../dbo/events.php');
41
/**#@-*/
42
43
//------------------------------------------------------------------------------
44
//  Definitions.
45
//------------------------------------------------------------------------------
46
47
/**#@+
48
 * Data restriction.
49
 */
50
define('MAX_TEMPLATE_NAME',        50);
51
define('MAX_TEMPLATE_PREFIX',      3);
52
define('MAX_TEMPLATE_DESCRIPTION', 100);
53
define('MIN_TEMPLATE_DAYS_COUNT',  1);
54
define('MAX_TEMPLATE_DAYS_COUNT',  100);
55
/**#@-*/
56
57
/**#@+
58
 * Template role.
59
 */
60
define('TEMPLATE_ROLE_AUTHOR',      -1);
61
define('TEMPLATE_ROLE_RESPONSIBLE', -2);
62
define('TEMPLATE_ROLE_REGISTERED',  -3);
63
define('MIN_TEMPLATE_ROLE', TEMPLATE_ROLE_REGISTERED);
64
/**#@-*/
65
66
//------------------------------------------------------------------------------
67
//  Functions.
68
//------------------------------------------------------------------------------
69
70
/**
71
 * Finds in database and returns the information about specified template.
72
 *
73
 * @param int $id Template ID.
74
 * @return array Array with data if template is found in database, FALSE otherwise.
75
 */
76
function template_find ($id)
77
{
78
    debug_write_log(DEBUG_TRACE, '[template_find]');
79
    debug_write_log(DEBUG_DUMP,  '[template_find] $id = ' . $id);
80
81
    $rs = dal_query('templates/fndid.sql', $id);
82
83
    return ($rs->rows == 0 ? FALSE : $rs->fetch());
0 ignored issues
show
The property $rows is declared protected in CRecordset. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
84
}
85
86
/**
87
 * Returns {@link CRecordset DAL recordset} which contains all existing templates of specified project,
88
 * sorted in accordance with current sort mode.
89
 *
90
 * @param int $id Project ID.
91
 * @param int &$sort Sort mode (used as output only). The function retrieves current sort mode from
92
 * client cookie ({@link COOKIE_TEMPLATES_SORT}) and updates it, if it's out of valid range.
93
 * @param int &$page Number of current page tab (used as output only). The function retrieves current
94
 * page from client cookie ({@link COOKIE_TEMPLATES_PAGE}) and updates it, if it's out of valid range.
95
 * @return CRecordset Recordset with list of templates.
96
 */
97 View Code Duplication
function templates_list ($id, &$sort, &$page)
98
{
99
    debug_write_log(DEBUG_TRACE, '[templates_list]');
100
    debug_write_log(DEBUG_DUMP,  '[templates_list] $id = ' . $id);
101
102
    $sort_modes = array
103
    (
104
        1  => 'template_name asc',
105
        2  => 'template_prefix asc',
106
        3  => 'critical_age asc, template_name asc',
107
        4  => 'frozen_time asc, template_name asc',
108
        5  => 'description asc, template_name asc',
109
        6  => 'template_name desc',
110
        7  => 'template_prefix desc',
111
        8  => 'critical_age desc, template_name desc',
112
        9  => 'frozen_time desc, template_name desc',
113
        10 => 'description desc, template_name desc',
114
    );
115
116
    $sort = try_request('sort', try_cookie(COOKIE_TEMPLATES_SORT));
117
    $sort = ustr2int($sort, 1, count($sort_modes));
118
119
    $page = try_request('page', try_cookie(COOKIE_TEMPLATES_PAGE));
120
    $page = ustr2int($page, 1, MAXINT);
121
122
    save_cookie(COOKIE_TEMPLATES_SORT, $sort);
123
    save_cookie(COOKIE_TEMPLATES_PAGE, $page);
124
125
    return dal_query('templates/list.sql', $id, $sort_modes[$sort]);
126
}
127
128
/**
129
 * Validates template information before creation or modification.
130
 *
131
 * @param string $template_name Template name.
132
 * @param string $template_prefix Template prefix.
133
 * @param int $critical_age Critical age.
134
 * @param int $frozen_time Frozen time.
135
 * @return int Error code:
136
 * <ul>
137
 * <li>{@link NO_ERROR} - data are valid</li>
138
 * <li>{@link ERROR_INCOMPLETE_FORM} - at least one of required field is empty</li>
139
 * <li>{@link ERROR_INVALID_INTEGER_VALUE} - value of $critical_age or $frozen_time is not an integer</li>
140
 * <li>{@link ERROR_INTEGER_VALUE_OUT_OF_RANGE} - value of $critical_age or $frozen_time is out of valid range</li>
141
 * </ul>
142
 */
143
function template_validate ($template_name, $template_prefix, $critical_age, $frozen_time)
144
{
145
    debug_write_log(DEBUG_TRACE, '[template_validate]');
146
    debug_write_log(DEBUG_DUMP,  '[template_validate] $template_name   = ' . $template_name);
147
    debug_write_log(DEBUG_DUMP,  '[template_validate] $template_prefix = ' . $template_prefix);
148
    debug_write_log(DEBUG_DUMP,  '[template_validate] $critical_age    = ' . $critical_age);
149
    debug_write_log(DEBUG_DUMP,  '[template_validate] $frozen_time     = ' . $frozen_time);
150
151
    if (ustrlen($template_name)   == 0 ||
152
        ustrlen($template_prefix) == 0)
153
    {
154
        debug_write_log(DEBUG_NOTICE, '[template_validate] At least one required field is empty.');
155
        return ERROR_INCOMPLETE_FORM;
156
    }
157
158
    // Validate 'Critical age'.
159 View Code Duplication
    if (ustrlen($critical_age) != 0)
160
    {
161
        debug_write_log(DEBUG_NOTICE, '[template_validate] Validate critical age value.');
162
163
        if (!is_intvalue($critical_age))
164
        {
165
            debug_write_log(DEBUG_NOTICE, '[template_validate] Invalid critical age value.');
166
            return ERROR_INVALID_INTEGER_VALUE;
167
        }
168
169
        if ($critical_age < MIN_TEMPLATE_DAYS_COUNT || $critical_age > MAX_TEMPLATE_DAYS_COUNT)
170
        {
171
            debug_write_log(DEBUG_NOTICE, '[template_validate] Critical age value is out of range.');
172
            return ERROR_INTEGER_VALUE_OUT_OF_RANGE;
173
        }
174
    }
175
176
    // Validate 'Frozen time'.
177 View Code Duplication
    if (ustrlen($frozen_time) != 0)
178
    {
179
        debug_write_log(DEBUG_NOTICE, '[template_validate] Validate frozen time value.');
180
181
        if (!is_intvalue($frozen_time))
182
        {
183
            debug_write_log(DEBUG_NOTICE, '[template_validate] Invalid frozen time value.');
184
            return ERROR_INVALID_INTEGER_VALUE;
185
        }
186
187
        if ($frozen_time < MIN_TEMPLATE_DAYS_COUNT || $frozen_time > MAX_TEMPLATE_DAYS_COUNT)
188
        {
189
            debug_write_log(DEBUG_NOTICE, '[template_validate] Frozen time value is out of range.');
190
            return ERROR_INTEGER_VALUE_OUT_OF_RANGE;
191
        }
192
    }
193
194
    return NO_ERROR;
195
}
196
197
/**
198
 * Creates new template.
199
 *
200
 * @param int $project_id ID of project which new template will belong to.
201
 * @param string $template_name Template name.
202
 * @param string $template_prefix Template prefix.
203
 * @param int $critical_age Critical age.
204
 * @param int $frozen_time Frozen time.
205
 * @param string $description Optional description.
206
 * @param bool $guest_access Ability of guest access to the template records.
207
 * @return int Error code:
208
 * <ul>
209
 * <li>{@link NO_ERROR} - template is successfully created</li>
210
 * <li>{@link ERROR_ALREADY_EXISTS} - template with specified name or prefix already exists</li>
211
 * </ul>
212
 */
213
function template_create ($project_id, $template_name, $template_prefix, $critical_age, $frozen_time, $description, $guest_access)
214
{
215
    debug_write_log(DEBUG_TRACE, '[template_create]');
216
    debug_write_log(DEBUG_DUMP,  '[template_create] $project_id      = ' . $project_id);
217
    debug_write_log(DEBUG_DUMP,  '[template_create] $template_name   = ' . $template_name);
218
    debug_write_log(DEBUG_DUMP,  '[template_create] $template_prefix = ' . $template_prefix);
219
    debug_write_log(DEBUG_DUMP,  '[template_create] $critical_age    = ' . $critical_age);
220
    debug_write_log(DEBUG_DUMP,  '[template_create] $frozen_time     = ' . $frozen_time);
221
    debug_write_log(DEBUG_DUMP,  '[template_create] $description     = ' . $description);
222
    debug_write_log(DEBUG_DUMP,  '[template_create] $guest_access    = ' . $guest_access);
223
224
    // Check that there is no template with the same name or prefix in the specified project.
225
    $rs = dal_query('templates/fndk.sql', $project_id, ustrtolower($template_name), ustrtolower($template_prefix));
226
227
    if ($rs->rows != 0)
0 ignored issues
show
The property $rows is declared protected in CRecordset. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
228
    {
229
        debug_write_log(DEBUG_NOTICE, '[template_create] Template already exists.');
230
        return ERROR_ALREADY_EXISTS;
231
    }
232
233
    // Create a template.
234
    dal_query('templates/create.sql',
235
              $project_id,
236
              $template_name,
237
              $template_prefix,
238
              ustrlen($critical_age) == 0 ? NULL : $critical_age,
239
              ustrlen($frozen_time)  == 0 ? NULL : $frozen_time,
240
              ustrlen($description)  == 0 ? NULL : $description,
241
              bool2sql($guest_access));
242
243
    return NO_ERROR;
244
}
245
246
/**
247
 * Clones everything (states, fields, permissions, etc) from one template to another (must be pre-created).
248
 *
249
 * @param int $source_id ID of template to be cloned.
250
 * @param int $dest_id ID of new template.
251
 * @return int Error code:
252
 * <ul>
253
 * <li>{@link NO_ERROR} - template is successfully cloned</li>
254
 * <li>{@link ERROR_NOT_FOUND} - at least one of specified templates cannot be found</li>
255
 * </ul>
256
 */
257
function template_clone ($source_id, $dest_id)
258
{
259
    debug_write_log(DEBUG_TRACE, '[template_clone]');
260
    debug_write_log(DEBUG_DUMP,  '[template_clone] $source_id = ' . $source_id);
261
    debug_write_log(DEBUG_DUMP,  '[template_clone] $dest_id   = ' . $dest_id);
262
263
    $source = template_find($source_id);
264
    $dest   = template_find($dest_id);
265
266
    if (!$source || !$dest)
0 ignored issues
show
Bug Best Practice introduced by
The expression $source 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...
Bug Best Practice introduced by
The expression $dest 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...
267
    {
268
        debug_write_log(DEBUG_NOTICE, '[template_clone] Template cannot be found.');
269
        return ERROR_NOT_FOUND;
270
    }
271
272
    dal_query('templates/gpclone.sql', $source_id, $dest_id, $source['project_id'], $dest['project_id']);
273
    dal_query('templates/sclone.sql',  $source_id, $dest_id);
274
    dal_query('templates/gtclone.sql', $source_id, $dest_id, $source['project_id'], $dest['project_id']);
275
    dal_query('templates/rtclone.sql', $source_id, $dest_id);
276
    dal_query('templates/fclone.sql',  $source_id, $dest_id);
277
    dal_query('templates/lvclone.sql', $source_id, $dest_id);
278
    dal_query('templates/fpclone.sql', $source_id, $dest_id, $source['project_id'], $dest['project_id']);
279
280
    template_author_perm_set      ($dest_id, $source['author_perm']);
281
    template_responsible_perm_set ($dest_id, $source['responsible_perm']);
282
    template_registered_perm_set  ($dest_id, $source['registered_perm']);
283
284
    return NO_ERROR;
285
}
286
287
/**
288
 * Modifies specified template.
289
 *
290
 * @param int $id ID of template to be modified.
291
 * @param int $project_id ID of project which the template belongs to.
292
 * @param string $template_name New template name.
293
 * @param string $template_prefix New template prefix.
294
 * @param int $critical_age New critical age.
295
 * @param int $frozen_time New frozen time.
296
 * @param string $description New description.
297
 * @param bool $guest_access Ability of guest access to the template records.
298
 * @return int Error code:
299
 * <ul>
300
 * <li>{@link NO_ERROR} - template is successfully modified</li>
301
 * <li>{@link ERROR_ALREADY_EXISTS} - another template with specified name or prefix already exists</li>
302
 * </ul>
303
 */
304
function template_modify ($id, $project_id, $template_name, $template_prefix, $critical_age, $frozen_time, $description, $guest_access)
305
{
306
    debug_write_log(DEBUG_TRACE, '[template_modify]');
307
    debug_write_log(DEBUG_DUMP,  '[template_modify] $id              = ' . $id);
308
    debug_write_log(DEBUG_DUMP,  '[template_modify] $project_id      = ' . $project_id);
309
    debug_write_log(DEBUG_DUMP,  '[template_modify] $template_name   = ' . $template_name);
310
    debug_write_log(DEBUG_DUMP,  '[template_modify] $template_prefix = ' . $template_prefix);
311
    debug_write_log(DEBUG_DUMP,  '[template_modify] $critical_age    = ' . $critical_age);
312
    debug_write_log(DEBUG_DUMP,  '[template_modify] $frozen_time     = ' . $frozen_time);
313
    debug_write_log(DEBUG_DUMP,  '[template_modify] $description     = ' . $description);
314
    debug_write_log(DEBUG_DUMP,  '[template_modify] $guest_access    = ' . $guest_access);
315
316
    // Check that there is no template with the same name or prefix, besides this one.
317
    $rs = dal_query('templates/fndku.sql', $id, $project_id, ustrtolower($template_name), ustrtolower($template_prefix));
318
319
    if ($rs->rows != 0)
0 ignored issues
show
The property $rows is declared protected in CRecordset. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
320
    {
321
        debug_write_log(DEBUG_NOTICE, '[template_modify] Template already exists.');
322
        return ERROR_ALREADY_EXISTS;
323
    }
324
325
    // Modify the template.
326
    dal_query('templates/modify.sql',
327
              $id,
328
              $template_name,
329
              $template_prefix,
330
              ustrlen($critical_age) == 0 ? NULL : $critical_age,
331
              ustrlen($frozen_time)  == 0 ? NULL : $frozen_time,
332
              ustrlen($description)  == 0 ? NULL : $description,
333
              bool2sql($guest_access));
334
335
    return NO_ERROR;
336
}
337
338
/**
339
 * Checks whether template can be deleted.
340
 *
341
 * @param int $id ID of template to be deleted.
342
 * @return bool TRUE if template can be deleted, FALSE otherwise.
343
 */
344
function is_template_removable ($id)
345
{
346
    debug_write_log(DEBUG_TRACE, '[is_template_removable]');
347
    debug_write_log(DEBUG_DUMP,  '[is_template_removable] $id = ' . $id);
348
349
    $rs = dal_query('templates/rfndc.sql', $id);
350
351
    return ($rs->fetch(0) == 0);
352
}
353
354
/**
355
 * Deletes specified template.
356
 *
357
 * @param int $id ID of template to be deleted.
358
 * @return int Always {@link NO_ERROR}.
359
 */
360 View Code Duplication
function template_delete ($id)
361
{
362
    debug_write_log(DEBUG_TRACE, '[template_delete]');
363
    debug_write_log(DEBUG_DUMP,  '[template_delete] $id = ' . $id);
364
365
    dal_query('subscriptions/sdelallt.sql', $id);
366
367
    dal_query('filters/fadelallt.sql', $id);
368
    dal_query('filters/fdelallt.sql',  $id);
369
370
    dal_query('templates/lvdelall.sql', $id);
371
    dal_query('templates/fpdelall.sql', $id);
372
    dal_query('templates/fsdelall.sql', $id);
373
    dal_query('templates/fdelall.sql',  $id);
374
    dal_query('templates/gtdelall.sql', $id);
375
    dal_query('templates/rtdelall.sql', $id);
376
    dal_query('templates/sadelall.sql', $id);
377
    dal_query('templates/sdelall.sql',  $id);
378
    dal_query('templates/gpdelall.sql', $id);
379
    dal_query('templates/delete.sql',   $id);
380
381
    return NO_ERROR;
382
}
383
384
/**
385
 * Locks specified template.
386
 *
387
 * @param int $id ID of template to be locked.
388
 * @return int Always {@link NO_ERROR}.
389
 */
390
function template_lock ($id)
391
{
392
    debug_write_log(DEBUG_TRACE, '[template_lock]');
393
    debug_write_log(DEBUG_DUMP,  '[template_lock] $id = ' . $id);
394
395
    dal_query('templates/setlock.sql', $id, 1);
396
397
    return NO_ERROR;
398
}
399
400
/**
401
 * Unlocks specified template.
402
 *
403
 * @param int $id ID of template to be unlocked.
404
 * @return int Always {@link NO_ERROR}.
405
 */
406
function template_unlock ($id)
407
{
408
    debug_write_log(DEBUG_TRACE, '[template_unlock]');
409
    debug_write_log(DEBUG_DUMP,  '[template_unlock] $id = ' . $id);
410
411
    dal_query('templates/setlock.sql', $id, 0);
412
413
    return NO_ERROR;
414
}
415
416
/**
417
 * Sets permissions of system role 'author' for specified template.
418
 *
419
 * @param int $id ID of template which permissions should be set for.
420
 * @param int $perm New permissions set.
421
 * @return int Always {@link NO_ERROR}.
422
 */
423
function template_author_perm_set ($id, $perm)
424
{
425
    debug_write_log(DEBUG_TRACE, '[template_author_perm_set]');
426
    debug_write_log(DEBUG_DUMP,  '[template_author_perm_set] $id   = ' . $id);
427
    debug_write_log(DEBUG_DUMP,  '[template_author_perm_set] $perm = ' . $perm);
428
429
    dal_query('templates/apset.sql', $id, $perm);
430
431
    return NO_ERROR;
432
}
433
434
/**
435
 * Sets permissions of system role 'responsible' for specified template.
436
 *
437
 * @param int $id ID of template which permissions should be set for.
438
 * @param int $perm New permissions set.
439
 * @return int Always {@link NO_ERROR}.
440
 */
441
function template_responsible_perm_set ($id, $perm)
442
{
443
    debug_write_log(DEBUG_TRACE, '[template_responsible_perm_set]');
444
    debug_write_log(DEBUG_DUMP,  '[template_responsible_perm_set] $id   = ' . $id);
445
    debug_write_log(DEBUG_DUMP,  '[template_responsible_perm_set] $perm = ' . $perm);
446
447
    dal_query('templates/rpset.sql', $id, $perm);
448
449
    return NO_ERROR;
450
}
451
452
/**
453
 * Sets permissions of system role 'registered' for specified template.
454
 *
455
 * @param int $id ID of template which permissions should be set for.
456
 * @param int $perm New permissions set.
457
 * @return int Always {@link NO_ERROR}.
458
 */
459
function template_registered_perm_set ($id, $perm)
460
{
461
    debug_write_log(DEBUG_TRACE, '[template_registered_perm_set]');
462
    debug_write_log(DEBUG_DUMP,  '[template_registered_perm_set] $id   = ' . $id);
463
    debug_write_log(DEBUG_DUMP,  '[template_registered_perm_set] $perm = ' . $perm);
464
465
    dal_query('templates/r2pset.sql', $id, $perm);
466
467
    return NO_ERROR;
468
}
469
470
/**
471
 * Exports specified template to XML code (see also {@link project_export}).
472
 *
473
 * @param int $id ID of template to be exported.
474
 * @param bool $just_the_node Whether the function should return the XML code of the template node alone instead of a complete XML schema.
475
 * @return string Generated XML code for specified template.
476
 */
477
function template_export ($id, $just_the_node = FALSE)
478
{
479
    debug_write_log(DEBUG_TRACE, '[template_export]');
480
    debug_write_log(DEBUG_DUMP,  '[template_export] $id            = ' . $id);
481
    debug_write_log(DEBUG_DUMP,  '[template_export] $just_the_node = ' . $just_the_node);
482
483
    // Allocation of permissions to XML code.
484
    $permissions = array
485
    (
486
        PERMIT_CREATE_RECORD         => 'create',
487
        PERMIT_MODIFY_RECORD         => 'modify',
488
        PERMIT_POSTPONE_RECORD       => 'postpone',
489
        PERMIT_RESUME_RECORD         => 'resume',
490
        PERMIT_REASSIGN_RECORD       => 'reassign',
491
        PERMIT_REOPEN_RECORD         => 'reopen',
492
        PERMIT_ADD_COMMENTS          => 'comment',
493
        PERMIT_ATTACH_FILES          => 'attach',
494
        PERMIT_REMOVE_FILES          => 'remove',
495
        PERMIT_CONFIDENTIAL_COMMENTS => 'secret',
496
        PERMIT_SEND_REMINDERS        => 'remind',
497
        PERMIT_DELETE_RECORD         => 'delete',
498
        PERMIT_ADD_SUBRECORDS        => 'addsubrec',
499
        PERMIT_REMOVE_SUBRECORDS     => 'remsubrec',
500
        PERMIT_VIEW_RECORD           => 'view',
501
    );
502
503
    // Find the template.
504
    $template = template_find($id);
505
506
    if (!$template)
0 ignored issues
show
Bug Best Practice introduced by
The expression $template 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...
507
    {
508
        return NULL;
509
    }
510
511
    $groups = array();
512
513
    // Generate XML code for general template information.
514
    $xml = sprintf("  <template name=\"%s\" prefix=\"%s\" description=\"%s\" critical_age=\"%s\" frozen_time=\"%s\" guest_access=\"%s\">\n",
515
                   ustr2html($template['template_name']),
516
                   ustr2html($template['template_prefix']),
517
                   ustr2html($template['description']),
518
                   $template['critical_age'],
519
                   $template['frozen_time'],
520
                   ($template['guest_access'] ? 'yes' : 'no'));
521
522
    $xml .= "    <permissions>\n";
523
524
    // Add XML code for template "author" permissions.
525 View Code Duplication
    if ($template['author_perm'] != 0)
526
    {
527
        $xml .= "      <author>\n";
528
529
        foreach ($permissions as $flag => $permit)
530
        {
531
            $xml .= (($template['author_perm'] & $flag) == 0 ? NULL : "        <permit>{$permit}</permit>\n");
532
        }
533
534
        $xml .= "      </author>\n";
535
    }
536
537
    // Add XML code for template "responsible" permissions.
538 View Code Duplication
    if ($template['responsible_perm'] != 0)
539
    {
540
        $xml .= "      <responsible>\n";
541
542
        foreach ($permissions as $flag => $permit)
543
        {
544
            $xml .= (($template['responsible_perm'] & $flag) == 0 ? NULL : "        <permit>{$permit}</permit>\n");
545
        }
546
547
        $xml .= "      </responsible>\n";
548
    }
549
550
    // Add XML code for template "registered" permissions.
551 View Code Duplication
    if ($template['registered_perm'] != 0)
552
    {
553
        $xml .= "      <registered>\n";
554
555
        foreach ($permissions as $flag => $permit)
556
        {
557
            $xml .= (($template['registered_perm'] & $flag) == 0 ? NULL : "        <permit>{$permit}</permit>\n");
558
        }
559
560
        $xml .= "      </registered>\n";
561
    }
562
563
    // Enumerate local groups of the same project and all global groups.
564
    $rs = dal_query('groups/gplist3.sql', $id);
565
566
    while (($group = $rs->fetch()))
567
    {
568
        // Add XML code for template permissions of each group that has ones.
569
        if ($group['perms'] != 0)
570
        {
571
            // Save ID of processed group for future reference.
572
            array_push($groups, $group['group_id']);
573
574
            // Add XML code for group name and type.
575
            $xml .= sprintf("      <group name=\"%s\" type=\"%s\">\n",
576
                              ustr2html($group['group_name']),
577
                              (is_null($group['project_id']) ? 'global' : 'local'));
578
579
            // Add XML code for permissions information.
580
            foreach ($permissions as $flag => $permit)
581
            {
582
                $xml .= (($group['perms'] & $flag) == 0 ? NULL : "        <permit>{$permit}</permit>\n");
583
            }
584
585
            $xml .= "      </group>\n";
586
        }
587
    }
588
589
    $xml .= "    </permissions>\n";
590
591
    // Export all existing states of the template.
592
    $xml .= state_export($id, $groups);
593
    $xml .= "  </template>\n";
594
595
    if ($just_the_node)
596
    {
597
        return $xml;
598
    }
599
600
    // Merge project, groups, and template.
601
    $xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
602
         . sprintf("<project name=\"%s\" description=\"%s\">\n",
603
                   ustr2html($template['project_name']),
604
                   ustr2html($template['p_description']))
605
         . groups_export($groups)
606
         . $xml
607
         . "</project>\n";
608
609
    return $xml;
610
}
611
612
/**
613
 * Imports templates described as XML code into the specified project.
614
 *
615
 * @param int $project_id ID of destination project.
616
 * @param string $xml Valid XML code.
617
 * @param string &$error In case of failure - the error message (used as output only).
618
 * @return bool Whether the import was successful.
619
 */
620
function templates_import ($project_id, $xml, &$error)
621
{
622
    debug_write_log(DEBUG_TRACE, '[templates_import]');
623
    debug_write_log(DEBUG_DUMP,  '[templates_import] $project_id = ' . $project_id);
624
625
    // Allocation of XML code to permissions.
626
    $permissions = array
627
    (
628
        'create'    => PERMIT_CREATE_RECORD,
629
        'modify'    => PERMIT_MODIFY_RECORD,
630
        'postpone'  => PERMIT_POSTPONE_RECORD,
631
        'resume'    => PERMIT_RESUME_RECORD,
632
        'reassign'  => PERMIT_REASSIGN_RECORD,
633
        'reopen'    => PERMIT_REOPEN_RECORD,
634
        'comment'   => PERMIT_ADD_COMMENTS,
635
        'attach'    => PERMIT_ATTACH_FILES,
636
        'remove'    => PERMIT_REMOVE_FILES,
637
        'secret'    => PERMIT_CONFIDENTIAL_COMMENTS,
638
        'remind'    => PERMIT_SEND_REMINDERS,
639
        'delete'    => PERMIT_DELETE_RECORD,
640
        'addsubrec' => PERMIT_ADD_SUBRECORDS,
641
        'remsubrec' => PERMIT_REMOVE_SUBRECORDS,
642
        'view'      => PERMIT_VIEW_RECORD,
643
    );
644
645
    // Enumerate templates.
646
    $templates = $xml->xpath('/project/template');
0 ignored issues
show
The method xpath cannot be called on $xml (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
647
648
    if ($templates !== FALSE)
649
    {
650
        foreach ($templates as $template)
651
        {
652
            $rs = dal_query('templates/count.sql');
653
654 View Code Duplication
            if (MAX_TEMPLATES_NUMBER != 0 && $rs->fetch(0) >= MAX_TEMPLATES_NUMBER)
655
            {
656
                debug_write_log(DEBUG_NOTICE, 'Maximum amount of templates is already reached.');
657
                return TRUE;
658
            }
659
660
            $template['name']         = ustrcut($template['name'],         MAX_TEMPLATE_NAME);
661
            $template['prefix']       = ustrcut($template['prefix'],       MAX_TEMPLATE_PREFIX);
662
            $template['critical_age'] = ustrcut($template['critical_age'], ustrlen(MAX_TEMPLATE_DAYS_COUNT));
663
            $template['frozen_time']  = ustrcut($template['frozen_time'],  ustrlen(MAX_TEMPLATE_DAYS_COUNT));
664
            $template['description']  = ustrcut($template['description'],  MAX_TEMPLATE_DESCRIPTION);
665
666
            $guest_access = ($template['guest_access'] == 'yes');
667
668
            // Validate template.
669
            switch (template_validate($template['name'], $template['prefix'], $template['critical_age'], $template['frozen_time']))
670
            {
671
                case NO_ERROR:
672
                    break;  // nop
673
                case ERROR_INCOMPLETE_FORM:
674
                    $error = get_html_resource(RES_ALERT_REQUIRED_ARE_EMPTY_ID);
675
                    return FALSE;
676
                case ERROR_INVALID_INTEGER_VALUE:
677
                    $error = get_html_resource(RES_ALERT_INVALID_INTEGER_VALUE_ID);
678
                    return FALSE;
679
                case ERROR_INTEGER_VALUE_OUT_OF_RANGE:
680
                    $error = ustrprocess(get_html_resource(RES_ALERT_INTEGER_VALUE_OUT_OF_RANGE_ID), MIN_TEMPLATE_DAYS_COUNT, MAX_TEMPLATE_DAYS_COUNT);
681
                    return FALSE;
682
                default:
683
                    debug_write_log(DEBUG_WARNING, '[templates_import] Template validation failure.');
684
                    $error = get_html_resource(RES_ALERT_UNKNOWN_ERROR_ID);
685
                    return FALSE;
686
            }
687
688
            // Create template.
689
            switch (template_create($project_id,
690
                                    $template['name'],
691
                                    $template['prefix'],
692
                                    $template['critical_age'],
693
                                    $template['frozen_time'],
694
                                    $template['description'],
695
                                    $guest_access))
696
            {
697
                case NO_ERROR:
698
                    break;
699
                case ERROR_ALREADY_EXISTS:
700
                    $error = get_html_resource(RES_ALERT_TEMPLATE_ALREADY_EXISTS_ID);
701
                    return FALSE;
702
                default:
703
                    debug_write_log(DEBUG_WARNING, '[templates_import] Template creation failure.');
704
                    $error = get_html_resource(RES_ALERT_UNKNOWN_ERROR_ID);
705
                    return FALSE;
706
            }
707
708
            $rs = dal_query('templates/fndk2.sql', $project_id, ustrtolower($template['name']));
709
710 View Code Duplication
            if ($rs->rows == 0)
0 ignored issues
show
The property $rows is declared protected in CRecordset. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
711
            {
712
                debug_write_log(DEBUG_WARNING, '[templates_import] Created template not found.');
713
                $error = get_html_resource(RES_ALERT_UNKNOWN_ERROR_ID);
714
                return FALSE;
715
            }
716
717
            $template_id = $rs->fetch('template_id');
718
719
            // Set author permissions.
720
            $permits = $template->xpath('./permissions/author/permit');
0 ignored issues
show
The method xpath cannot be called on $template (of type array<string,string,{"description":"string"}>).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
721
722 View Code Duplication
            if ($permits !== FALSE)
723
            {
724
                $perms = 0;
725
726
                foreach ($permits as $permit)
727
                {
728
                    $permit = strval($permit);
729
730
                    if (array_key_exists($permit, $permissions))
731
                    {
732
                        $perms |= $permissions[$permit];
733
                    }
734
                }
735
736
                template_author_perm_set($template_id, $perms);
737
            }
738
739
            // Set responsible permissions.
740
            $permits = $template->xpath('./permissions/responsible/permit');
0 ignored issues
show
The method xpath cannot be called on $template (of type array<string,string,{"description":"string"}>).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
741
742 View Code Duplication
            if ($permits !== FALSE)
743
            {
744
                $perms = 0;
745
746
                foreach ($permits as $permit)
747
                {
748
                    $permit = strval($permit);
749
750
                    if (array_key_exists($permit, $permissions))
751
                    {
752
                        $perms |= $permissions[$permit];
753
                    }
754
                }
755
756
                template_responsible_perm_set($template_id, $perms);
757
            }
758
759
            // Set registered permissions.
760
            $permits = $template->xpath('./permissions/registered/permit');
0 ignored issues
show
The method xpath cannot be called on $template (of type array<string,string,{"description":"string"}>).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
761
762 View Code Duplication
            if ($permits !== FALSE)
763
            {
764
                $perms = 0;
765
766
                foreach ($permits as $permit)
767
                {
768
                    $permit = strval($permit);
769
770
                    if (array_key_exists($permit, $permissions))
771
                    {
772
                        $perms |= $permissions[$permit];
773
                    }
774
                }
775
776
                template_registered_perm_set($template_id, $perms);
777
            }
778
779
            // Enumerate groups permissions.
780
            $groups = $template->xpath('./permissions/group');
0 ignored issues
show
The method xpath cannot be called on $template (of type array<string,string,{"description":"string"}>).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
781
782
            if ($groups !== FALSE)
783
            {
784
                foreach ($groups as $group)
785
                {
786
                    if (isset($group->permit))
787
                    {
788
                        // Find the group.
789
                        $rs = dal_query('groups/fndk.sql',
790
                                        $group['type'] == 'global' ? 'is null' : '=' . $project_id,
791
                                        ustrtolower(ustrcut($group['name'], MAX_GROUP_NAME)));
792
793
                        if ($rs->rows != 0)
0 ignored issues
show
The property $rows is declared protected in CRecordset. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
794
                        {
795
                            $group_id = $rs->fetch('group_id');
796
797
                            // Set group permissions.
798
                            $perms = 0;
799
800
                            foreach ($group->permit as $permit)
801
                            {
802
                                $permit = strval($permit);
803
804
                                if (array_key_exists($permit, $permissions))
805
                                {
806
                                    $perms |= $permissions[$permit];
807
                                }
808
                            }
809
810
                            group_set_permissions($group_id, $template_id, $perms);
811
                        }
812
                    }
813
                }
814
            }
815
816
            // Import states.
817
            if (!states_import($template_id, $template, $error))
0 ignored issues
show
$template is of type array<string,string,{"description":"string"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
818
            {
819
                return FALSE;
820
            }
821
        }
822
    }
823
824
    return TRUE;
825
}
826
827
?>
828