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/projects.php (8 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
 * Projects
25
 *
26
 * This module provides API to work with eTraxis projects.
27
 * See also {@link https://github.com/etraxis/etraxis-obsolete/wiki/tbl_projects tbl_projects} database table.
28
 *
29
 * @package DBO
30
 * @subpackage Projects
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/templates.php');
40
/**#@-*/
41
42
//------------------------------------------------------------------------------
43
//  Definitions.
44
//------------------------------------------------------------------------------
45
46
/**#@+
47
 * Data restriction.
48
 */
49
define('MAX_PROJECT_NAME',        25);
50
define('MAX_PROJECT_DESCRIPTION', 100);
51
/**#@-*/
52
53
/**#@+
54
 * Metrics type.
55
 */
56
define('METRICS_OPENED_RECORDS',      0);
57
define('METRICS_CREATION_VS_CLOSURE', 1);
58
/**#@-*/
59
60
//------------------------------------------------------------------------------
61
//  Functions.
62
//------------------------------------------------------------------------------
63
64
/**
65
 * Finds in database and returns the information about specified project.
66
 *
67
 * @param int $id Project ID.
68
 * @return array Array with data if project is found in database, FALSE otherwise.
69
 */
70
function project_find ($id)
71
{
72
    debug_write_log(DEBUG_TRACE, '[project_find]');
73
    debug_write_log(DEBUG_DUMP,  '[project_find] $id = ' . $id);
74
75
    if (get_user_level() == USER_LEVEL_ADMIN)
76
    {
77
        $rs = dal_query('projects/fndid.sql', $id);
78
    }
79
    else
80
    {
81
        $rs = dal_query('projects/fndid2.sql', $_SESSION[VAR_USERID], $id);
82
    }
83
84
    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...
85
}
86
87
/**
88
 * Returns {@link CRecordset DAL recordset} which contains all existing projects and sorted in
89
 * accordance with current sort mode.
90
 *
91
 * @param int &$sort Sort mode (used as output only). The function retrieves current sort mode from
92
 * client cookie ({@link COOKIE_PROJECTS_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_PROJECTS_PAGE}) and updates it, if it's out of valid range.
95
 * @return CRecordset Recordset with list of projects.
96
 */
97
function projects_list (&$sort, &$page)
98
{
99
    debug_write_log(DEBUG_TRACE, '[projects_list]');
100
101
    $sort_modes = array
102
    (
103
        1 => 'project_name asc',
104
        2 => 'start_time asc, project_name asc',
105
        3 => 'description asc, project_name asc',
106
        4 => 'project_name desc',
107
        5 => 'start_time desc, project_name desc',
108
        6 => 'description desc, project_name desc',
109
    );
110
111
    $sort = try_request('sort', try_cookie(COOKIE_PROJECTS_SORT));
112
    $sort = ustr2int($sort, 1, count($sort_modes));
113
114
    $page = try_request('page', try_cookie(COOKIE_PROJECTS_PAGE));
115
    $page = ustr2int($page, 1, MAXINT);
116
117
    save_cookie(COOKIE_PROJECTS_SORT, $sort);
118
    save_cookie(COOKIE_PROJECTS_PAGE, $page);
119
120
    if (get_user_level() == USER_LEVEL_ADMIN)
121
    {
122
        $rs = dal_query('projects/list.sql', $sort_modes[$sort]);
123
    }
124
    else
125
    {
126
        $rs = dal_query('projects/list2.sql', $_SESSION[VAR_USERID], $sort_modes[$sort]);
127
    }
128
129
    return $rs;
130
}
131
132
/**
133
 * Validates project information before creation or modification.
134
 *
135
 * @param string $project_name Project name.
136
 * @return int Error code:
137
 * <ul>
138
 * <li>{@link NO_ERROR} - data are valid</li>
139
 * <li>{@link ERROR_INCOMPLETE_FORM} - at least one of required field is empty</li>
140
 * </ul>
141
 */
142 View Code Duplication
function project_validate ($project_name)
143
{
144
    debug_write_log(DEBUG_TRACE, '[project_validate]');
145
    debug_write_log(DEBUG_DUMP,  '[project_validate] $project_name = ' . $project_name);
146
147
    if (ustrlen($project_name) == 0)
148
    {
149
        debug_write_log(DEBUG_NOTICE, '[project_validate] At least one required field is empty.');
150
        return ERROR_INCOMPLETE_FORM;
151
    }
152
153
    return NO_ERROR;
154
}
155
156
/**
157
 * Creates new project.
158
 *
159
 * @param string $project_name Project name.
160
 * @param string $description Optional description.
161
 * @return int Error code:
162
 * <ul>
163
 * <li>{@link NO_ERROR} - account is successfully created</li>
164
 * <li>{@link ERROR_ALREADY_EXISTS} - project with specified project name already exists</li>
165
 * </ul>
166
 */
167
function project_create ($project_name, $description)
168
{
169
    debug_write_log(DEBUG_TRACE, '[project_create]');
170
    debug_write_log(DEBUG_DUMP,  '[project_create] $project_name = ' . $project_name);
171
    debug_write_log(DEBUG_DUMP,  '[project_create] $description  = ' . $description);
172
173
    // Check that there is no project with the same project name.
174
    $rs = dal_query('projects/fndk.sql', ustrtolower($project_name));
175
176
    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...
177
    {
178
        debug_write_log(DEBUG_NOTICE, '[project_create] Project already exists.');
179
        return ERROR_ALREADY_EXISTS;
180
    }
181
182
    // Create an project.
183
    dal_query('projects/create.sql',
184
              $project_name,
185
              time(),
186
              ustrlen($description) == 0 ? NULL : $description);
187
188
    return NO_ERROR;
189
}
190
191
/**
192
 * Modifies specified project.
193
 *
194
 * @param int $id ID of project to be modified.
195
 * @param string $project_name New project name.
196
 * @param string $description New description.
197
 * @return int Error code:
198
 * <ul>
199
 * <li>{@link NO_ERROR} - project is successfully modified</li>
200
 * <li>{@link ERROR_ALREADY_EXISTS} - another project with specified project name already exists</li>
201
 * </ul>
202
 */
203
function project_modify ($id, $project_name, $description)
204
{
205
    debug_write_log(DEBUG_TRACE, '[project_modify]');
206
    debug_write_log(DEBUG_DUMP,  '[project_modify] $id           = ' . $id);
207
    debug_write_log(DEBUG_DUMP,  '[project_modify] $project_name = ' . $project_name);
208
    debug_write_log(DEBUG_DUMP,  '[project_modify] $description  = ' . $description);
209
210
    // Check that there is no project with the same project name, besides this one.
211
    $rs = dal_query('projects/fndku.sql', $id, ustrtolower($project_name));
212
213
    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...
214
    {
215
        debug_write_log(DEBUG_NOTICE, '[project_modify] Project already exists.');
216
        return ERROR_ALREADY_EXISTS;
217
    }
218
219
    // Modify the project.
220
    dal_query('projects/modify.sql',
221
              $id,
222
              $project_name,
223
              ustrlen($description) == 0 ? NULL : $description);
224
225
    return NO_ERROR;
226
}
227
228
/**
229
 * Checks whether project can be deleted.
230
 *
231
 * @param int $id ID of project to be deleted.
232
 * @return bool TRUE if project can be deleted, FALSE otherwise.
233
 */
234
function is_project_removable ($id)
235
{
236
    debug_write_log(DEBUG_TRACE, '[is_project_removable]');
237
    debug_write_log(DEBUG_DUMP,  '[is_project_removable] $id = ' . $id);
238
239
    $rs = dal_query('projects/rfndc.sql', $id);
240
241
    return ($rs->fetch(0) == 0);
242
}
243
244
/**
245
 * Deletes specified project.
246
 *
247
 * @param int $id ID of project to be deleted.
248
 * @return int Always {@link NO_ERROR}.
249
 */
250
function project_delete ($id)
251
{
252
    debug_write_log(DEBUG_TRACE, '[project_delete]');
253
    debug_write_log(DEBUG_DUMP,  '[project_delete] $id = ' . $id);
254
255
    dal_query('subscriptions/sdelallp.sql', $id);
256
257
    dal_query('filters/fshdelallg.sql', $id);
258
    dal_query('filters/fshdelallp.sql', $id);
259
    dal_query('filters/fa2delallp.sql', $id);
260
    dal_query('filters/fadelallp.sql',  $id);
261
    dal_query('filters/fsdelalls.sql',  $id);
262
    dal_query('filters/fsdelallp.sql',  $id);
263
    dal_query('filters/ftdelalls.sql',  $id);
264
    dal_query('filters/ftdelallp.sql',  $id);
265
    dal_query('filters/ffdelallf.sql',  $id);
266
    dal_query('filters/ffdelallp.sql',  $id);
267
    dal_query('filters/vdelallp.sql',   $id);
268
    dal_query('filters/fdelallp.sql',   $id);
269
270
    dal_query('projects/lvdelall.sql',  $id);
271
    dal_query('projects/fpdelall.sql',  $id);
272
    dal_query('projects/fdelall.sql',   $id);
273
    dal_query('projects/gpdelall.sql',  $id);
274
    dal_query('projects/gtdelall.sql',  $id);
275
    dal_query('projects/rtdelall.sql',  $id);
276
    dal_query('projects/rdelalls.sql',  $id);
277
    dal_query('projects/rdelallg.sql',  $id);
278
    dal_query('projects/sadelalls.sql', $id);
279
    dal_query('projects/sadelallg.sql', $id);
280
    dal_query('projects/sdelall.sql',   $id);
281
    dal_query('projects/tdelall.sql',   $id);
282
    dal_query('projects/msdelall.sql',  $id);
283
    dal_query('projects/gdelall.sql',   $id);
284
    dal_query('projects/delete.sql',    $id);
285
286
    return NO_ERROR;
287
}
288
289
/**
290
 * Exports specified project to XML code (see also {@link project_import}).
291
 *
292
 * @param int $id Project ID of project to be exported.
293
 * @return string Generated XML code for specified project.
294
 */
295
function project_export ($id)
296
{
297
    debug_write_log(DEBUG_TRACE, '[project_export]');
298
    debug_write_log(DEBUG_DUMP,  '[project_export] $id = ' . $id);
299
300
    // Find the project.
301
    $project = project_find($id);
302
303
    if (!$project)
0 ignored issues
show
Bug Best Practice introduced by
The expression $project 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...
304
    {
305
        return NULL;
306
    }
307
308
    // Generate XML code for groups.
309
    $sort = $page = NULL;
310
    $rs = groups_list($id, $sort, $page);
311
    $groups = array();
312
313
    while (($group = $rs->fetch()))
314
    {
315
        array_push($groups, $group['group_id']);
316
    }
317
318
    $xml = groups_export($groups);
319
320
    // Generate XML code for templates.
321
    $rs = templates_list($id, $sort, $page);
322
323
    while (($template = $rs->fetch()))
324
    {
325
        $xml .= template_export($template["template_id"], TRUE);
326
    }
327
328
    // Merge project, groups, and templates.
329
    $xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
330
         . sprintf("<project name=\"%s\" description=\"%s\">\n",
331
                   ustr2html($project['project_name']),
332
                   ustr2html($project['description']))
333
         . $xml
334
         . "</project>\n";
335
336
    return $xml;
337
}
338
339
/**
340
 * Imports project specified as XML code (see also {@link project_export}).
341
 *
342
 * @param string $xmlfile File with XML code uploaded as described {@link http://www.php.net/features.file-upload here}.
343
 * @param string &$error In case of failure - the error message (used as output only).
344
 * @return int ID of newly imported project (used as output only), or 0 on failure.
345
 */
346
function project_import ($xmlfile, &$error)
347
{
348
    debug_write_log(DEBUG_TRACE, '[project_import]');
349
    debug_write_log(DEBUG_DUMP,  '[project_import] $xmlfile["name"]     = ' . $xmlfile['name']);
350
    debug_write_log(DEBUG_DUMP,  '[project_import] $xmlfile["type"]     = ' . $xmlfile['type']);
351
    debug_write_log(DEBUG_DUMP,  '[project_import] $xmlfile["size"]     = ' . $xmlfile['size']);
352
    debug_write_log(DEBUG_DUMP,  '[project_import] $xmlfile["tmp_name"] = ' . $xmlfile['tmp_name']);
353
    debug_write_log(DEBUG_DUMP,  '[project_import] $xmlfile["error"]    = ' . $xmlfile['error']);
354
355
    // Check for possible upload errors, provided by PHP.
356
    switch ($xmlfile['error'])
357
    {
358
        case UPLOAD_ERR_OK:
359
            $error = NULL;
360
            break;  // nop
361
        case UPLOAD_ERR_INI_SIZE:
362
            $error = get_html_resource(RES_ALERT_UPLOAD_INI_SIZE_ID);
363
            return 0;
364
        case UPLOAD_ERR_FORM_SIZE:
365
            $error = get_html_resource(RES_ALERT_UPLOAD_FORM_SIZE_ID);
366
            return 0;
367
        case UPLOAD_ERR_PARTIAL:
368
            $error = get_html_resource(RES_ALERT_UPLOAD_PARTIAL_ID);
369
            return 0;
370
        case UPLOAD_ERR_NO_FILE:
371
            $error = get_html_resource(RES_ALERT_UPLOAD_NO_FILE_ID);
372
            return 0;
373
        case UPLOAD_ERR_NO_TMP_DIR:
374
            $error = get_html_resource(RES_ALERT_UPLOAD_NO_TMP_DIR_ID);
375
            return 0;
376
        case UPLOAD_ERR_CANT_WRITE:
377
            $error = get_html_resource(RES_ALERT_UPLOAD_CANT_WRITE_ID);
378
            return 0;
379
        case UPLOAD_ERR_EXTENSION:
380
            $error = get_html_resource(RES_ALERT_UPLOAD_EXTENSION_ID);
381
            return 0;
382
        default:
383
            $error = get_html_resource(RES_ALERT_UNKNOWN_ERROR_ID);
384
            return 0;
385
    }
386
387
    // Check for file size.
388
    if ($xmlfile['size'] > ATTACHMENTS_MAXSIZE * 1024)
389
    {
390
        debug_write_log(DEBUG_WARNING, '[project_import] File is too large.');
391
        $error = get_html_resource(RES_ALERT_UPLOAD_FORM_SIZE_ID);
392
        return 0;
393
    }
394
395
    // Check whether the file was uploaded via HTTP POST (security issue).
396 View Code Duplication
    if (!is_uploaded_file($xmlfile['tmp_name']))
397
    {
398
        debug_write_log(DEBUG_WARNING, '[project_import] Function "is_uploaded_file" warns that file named by "' . $xmlfile['tmp_name'] . '" was not uploaded via HTTP POST.');
399
        return 0;
400
    }
401
402
    // Load XML file and check for parser errors.
403
    libxml_use_internal_errors(TRUE);
404
405
    $xml = simplexml_load_file($xmlfile['tmp_name']);
406
407
    if ($xml === FALSE)
408
    {
409
        $xmlerrs = libxml_get_errors();
410
411
        debug_write_log(DEBUG_WARNING, "[project_import] Line {$xmlerrs[0]->line}: {$xmlerrs[0]->message}");
412
413
        $error = sprintf('<b>%s %d:</b> %s',
414
                         get_html_resource(RES_LINE_ID),
415
                         $xmlerrs[0]->line,
416
                         ustr2html($xmlerrs[0]->message));
417
418
        return 0;
419
    }
420
421
    // Validate project.
422
    $xml['name']        = ustrcut($xml['name'],        MAX_PROJECT_NAME);
423
    $xml['description'] = ustrcut($xml['description'], MAX_PROJECT_DESCRIPTION);
424
425
    switch (project_validate($xml['name']))
426
    {
427
        case NO_ERROR:
428
            break;  // nop
429
        case ERROR_INCOMPLETE_FORM:
430
            $error = get_html_resource(RES_ALERT_REQUIRED_ARE_EMPTY_ID);
431
            return 0;
432
        default:
433
            $error = get_html_resource(RES_ALERT_UNKNOWN_ERROR_ID);
434
            return 0;
435
    }
436
437
    dal_transaction_start();
438
439
    // Create project.
440
    project_create($xml['name'], $xml['description']);
441
442
    $rs = dal_query('projects/fndk.sql', ustrtolower($xml['name']));
443
444 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...
445
    {
446
        debug_write_log(DEBUG_WARNING, '[parse_project_xml] Created project not found.');
447
        $error = get_html_resource(RES_ALERT_UNKNOWN_ERROR_ID);
448
        return 0;
449
    }
450
451
    $project = $rs->fetch('project_id');
452
453
    if     ( !groups_import   ($project, $xml, $error) ) { $project = 0; }
454
    elseif ( !templates_import($project, $xml, $error) ) { $project = 0; }
455
456
    dal_transaction_stop($project != 0);
457
458
    return $project;
459
}
460
461
/**
462
 * Generates XML code for context menu on project's pages for specified project.
463
 *
464
 * @param string $template_url URL for using in template links.
465
 * @param string $state_url URL for using in state links.
466
 * @param string $field_url URL for using in field links.
467
 * @param int $project_id ID of project which context menu should be generated.
468
 * @param int $template_id ID of template to be expanded (NULL to keep all collapsed).
469
 * @param int $state_id ID of state to be expanded (NULL to keep all collapsed).
470
 * @return string Generated XML code.
471
 */
472
function gen_context_menu ($template_url, $state_url, $field_url, $project_id, $template_id = NULL, $state_id = NULL)
473
{
474
    debug_write_log(DEBUG_TRACE, '[gen_context_menu]');
475
    debug_write_log(DEBUG_DUMP,  '[gen_context_menu] $template_url = ' . $template_url);
476
    debug_write_log(DEBUG_DUMP,  '[gen_context_menu] $state_url    = ' . $state_url);
477
    debug_write_log(DEBUG_DUMP,  '[gen_context_menu] $field_url    = ' . $field_url);
478
    debug_write_log(DEBUG_DUMP,  '[gen_context_menu] $project_id   = ' . $project_id);
479
    debug_write_log(DEBUG_DUMP,  '[gen_context_menu] $template_id  = ' . $template_id);
480
    debug_write_log(DEBUG_DUMP,  '[gen_context_menu] $state_id     = ' . $state_id);
481
482
    $xml = NULL;
483
484
    if (get_user_level() == USER_LEVEL_ADMIN)
485
    {
486
        $templates = dal_query('templates/list.sql', $project_id, 'template_name asc');
487
488
        if ($templates->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...
489
        {
490
            $xml = '<contextmenu>';
491
492
            while (($template = $templates->fetch()))
493
            {
494
                $xml .= ($template['template_id'] == $template_id
495
                            ? '<submenu url="' . $template_url . $template['template_id'] . '" text="' . ustr2html($template['template_name']) . '" expanded="true">'
496
                            : '<submenu url="' . $template_url . $template['template_id'] . '" text="' . ustr2html($template['template_name']) . '">');
497
498
                $states = dal_query('states/list.sql', $template['template_id'], 'state_name asc');
499
500
                if ($states->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...
501
                {
502
                    $xml .= '<menuitem>'
503
                          . get_html_resource(RES_NONE_ID)
504
                          . '</menuitem>';
505
                }
506
                else
507
                {
508
                    while (($state = $states->fetch()))
509
                    {
510
                        $xml .= ($state['state_id'] == $state_id
511
                                    ? '<submenu url="' . $state_url . $state['state_id'] . '" text="' . ustr2html($state['state_name']) . '" expanded="true">'
512
                                    : '<submenu url="' . $state_url . $state['state_id'] . '" text="' . ustr2html($state['state_name']) . '">');
513
514
                        $fields = dal_query('fields/list.sql', $state['state_id'], 'field_order asc');
515
516
                        if ($fields->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...
517
                        {
518
                            $xml .= '<menuitem>'
519
                                  . get_html_resource(RES_NONE_ID)
520
                                  . '</menuitem>';
521
                        }
522
                        else
523
                        {
524
                            while (($field = $fields->fetch()))
525
                            {
526
                                $xml .= '<menuitem url="' . $field_url . $field['field_id'] . '">'
527
                                      . ustr2html($field['field_name'])
528
                                      . '</menuitem>';
529
                            }
530
                        }
531
532
                        $xml .= '</submenu>';
533
                        }
534
                    }
535
536
                $xml .= '</submenu>';
537
            }
538
539
            $xml .= '</contextmenu>';
540
        }
541
    }
542
543
    return $xml;
544
}
545
546
?>
547