Completed
Branch master (d81c7d)
by Michael
04:25
created

functions.php ➔ publisherCopyr()   C

Complexity

Conditions 8
Paths 9

Size

Total Lines 33
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 15
c 0
b 0
f 0
nc 9
nop 2
dl 0
loc 33
rs 5.3846
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 30 and the first side effect is on line 23.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/*
3
 You may not change or alter any portion of this comment or credits
4
 of supporting developers from this source code or any supporting source code
5
 which is considered copyrighted (c) material of the original comment or credit authors.
6
7
 This program is distributed in the hope that it will be useful,
8
 but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10
 */
11
12
/**
13
 * @copyright       The XUUPS Project http://sourceforge.net/projects/xuups/
14
 * @license         http://www.fsf.org/copyleft/gpl.html GNU public license
15
 * @package         Publisher
16
 * @since           1.0
17
 * @author          trabis <[email protected]>
18
 * @author          The SmartFactory <www.smartfactory.ca>
19
 */
20
21
// defined('XOOPS_ROOT_PATH') || exit('XOOPS root path not defined');
0 ignored issues
show
Unused Code Comprehensibility introduced by
70% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
22
23
include_once __DIR__ . '/common.php';
24
25
/**
26
 * Includes scripts in HTML header
27
 *
28
 * @return void
29
 */
30
function publisherCpHeader()
31
{
32
    xoops_cp_header();
33
34
    //cannot use xoTheme, some conflit with admin gui
35
    echo '<link type="text/css" href="' . XOOPS_URL . '/modules/system/css/ui/' . xoops_getModuleOption('jquery_theme', 'system') . '/ui.all.css" rel="stylesheet" />
36
    <link type="text/css" href="' . PUBLISHER_URL . '/assets/css/publisher.css" rel="stylesheet" />
37
    <script type="text/javascript" src="' . PUBLISHER_URL . '/assets/js/funcs.js"></script>
38
    <script type="text/javascript" src="' . PUBLISHER_URL . '/assets/js/cookies.js"></script>
39
    <script type="text/javascript" src="' . XOOPS_URL . '/browse.php?Frameworks/jquery/jquery.js"></script>
40
    <!-- <script type="text/javascript" src="' . XOOPS_URL . '/browse.php?Frameworks/jquery/jquery-migrate-1.2.1.js"></script> -->
41
    <script type="text/javascript" src="' . XOOPS_URL . '/browse.php?Frameworks/jquery/plugins/jquery.ui.js"></script>
42
    <script type="text/javascript" src="' . PUBLISHER_URL . '/assets/js/ajaxupload.3.9.js"></script>
43
    <script type="text/javascript" src="' . PUBLISHER_URL . '/assets/js/publisher.js"></script>
44
    ';
45
}
46
47
/**
48
 * Default sorting for a given order
49
 *
50
 * @param  string $sort
51
 * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
52
 */
53
function publisherGetOrderBy($sort)
54
{
55
    if ($sort === 'datesub') {
56
        return 'DESC';
57
    } elseif ($sort === 'counter') {
58
        return 'DESC';
59
    } elseif ($sort === 'weight') {
60
        return 'ASC';
61
    } elseif ($sort === 'votes') {
62
        return 'DESC';
63
    } elseif ($sort === 'rating') {
64
        return 'DESC';
65
    } elseif ($sort === 'comments') {
66
        return 'DESC';
67
    }
68
69
    return null;
70
}
71
72
/**
73
 * @credits Thanks to Mithandir
74
 * @param  string $str
75
 * @param  int    $start
76
 * @param  int    $length
77
 * @param  string $trimMarker
78
 * @return string
79
 */
80
function publisherSubstr($str, $start, $length, $trimMarker = '...')
81
{
82
    // if the string is empty, let's get out ;-)
83
    if ($str == '') {
84
        return $str;
85
    }
86
87
    // reverse a string that is shortened with '' as trimmarker
88
    $reversedString = strrev(xoops_substr($str, $start, $length, ''));
89
90
    // find first space in reversed string
91
    $positionOfSpace = strpos($reversedString, ' ', 0);
92
93
    // truncate the original string to a length of $length
94
    // minus the position of the last space
95
    // plus the length of the $trimMarker
96
    $truncatedString = xoops_substr($str, $start, $length - $positionOfSpace + strlen($trimMarker), $trimMarker);
97
98
    return $truncatedString;
99
}
100
101
/**
102
 * @param  string $document
103
 * @return mixed
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use string.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
104
 */
105 View Code Duplication
function publisherHtml2text($document)
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
106
{
107
    // PHP Manual:: function preg_replace
108
    // $document should contain an HTML document.
109
    // This will remove HTML tags, javascript sections
110
    // and white space. It will also convert some
111
    // common HTML entities to their text equivalent.
112
    // Credits : newbb2
113
    $search = array(
114
        "'<script[^>]*?>.*?</script>'si", // Strip out javascript
115
        "'<img.*?/>'si", // Strip out img tags
116
        "'<[\/\!]*?[^<>]*?>'si", // Strip out HTML tags
117
        "'([\r\n])[\s]+'", // Strip out white space
118
        "'&(quot|#34);'i", // Replace HTML entities
119
        "'&(amp|#38);'i",
120
        "'&(lt|#60);'i",
121
        "'&(gt|#62);'i",
122
        "'&(nbsp|#160);'i",
123
        "'&(iexcl|#161);'i",
124
        "'&(cent|#162);'i",
125
        "'&(pound|#163);'i",
126
        "'&(copy|#169);'i"
127
    ); // evaluate as php
128
129
    $replace = array(
130
        '',
131
        '',
132
        '',
133
        "\\1",
134
        "\"",
135
        '&',
136
        '<',
137
        '>',
138
        ' ',
139
        chr(161),
140
        chr(162),
141
        chr(163),
142
        chr(169),
143
    );
144
145
    $text = preg_replace($search, $replace, $document);
146
147
    preg_replace_callback(
148
        '/&#(\d+);/',
149
        function ($matches) {
150
            return chr($matches[1]);
151
        },
152
        $document
153
    );
154
155
    return $text;
156
    //<?php
157
}
158
159
/**
160
 * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use string[].

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
161
 */
162
function publisherGetAllowedImagesTypes()
163
{
164
    return array('jpg/jpeg', 'image/bmp', 'image/gif', 'image/jpeg', 'image/jpg', 'image/x-png', 'image/png', 'image/pjpeg');
165
}
166
167
/**
168
 * @param  bool $withLink
169
 * @return string
170
 */
171
function publisherModuleHome($withLink = true)
172
{
173
    $publisher = PublisherPublisher::getInstance();
174
175
    if (!$publisher->getConfig('format_breadcrumb_modname')) {
176
        return '';
177
    }
178
179
    if (!$withLink) {
180
        return $publisher->getModule()->getVar('name');
0 ignored issues
show
Bug introduced by
The method getVar cannot be called on $publisher->getModule() (of type null).

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...
181
    } else {
182
        return '<a href="' . PUBLISHER_URL . '/">' . $publisher->getModule()->getVar('name') . '</a>';
0 ignored issues
show
Bug introduced by
The method getVar cannot be called on $publisher->getModule() (of type null).

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...
183
    }
184
}
185
186
/**
187
 * Copy a file, or a folder and its contents
188
 *
189
 * @author      Aidan Lister <[email protected]>
190
 * @version     1.0.0
191
 * @param  string $source The source
192
 * @param  string $dest   The destination
193
 * @return bool   Returns true on success, false on failure
194
 */
195
function publisherCopyr($source, $dest)
196
{
197
    // Simple copy for a file
198
    if (is_file($source)) {
199
        return copy($source, $dest);
200
    }
201
202
    // Make destination directory
203
    if (!is_dir($dest)) {
204
        mkdir($dest);
205
    }
206
207
    // Loop through the folder
208
    $dir = dir($source);
209
    while (false !== $entry = $dir->read()) {
210
        // Skip pointers
211
        if ($entry === '.' || $entry === '..') {
212
            continue;
213
        }
214
215
        // Deep copy directories
216
        if (($dest !== "$source/$entry") && is_dir("$source/$entry")) {
217
            publisherCopyr("$source/$entry", "$dest/$entry");
218
        } else {
219
            copy("$source/$entry", "$dest/$entry");
220
        }
221
    }
222
223
    // Clean up
224
    $dir->close();
225
226
    return true;
227
}
228
229
/**
230
 * .* @credits Thanks to the NewBB2 Development Team
231
 * @param  string $item
232
 * @param  bool   $getStatus
233
 * @return bool|int|string
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use false|string|integer.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
234
 */
235
function &publisherGetPathStatus($item, $getStatus = false)
236
{
237
    $path = '';
238
    if ('root' !== $item) {
239
        $path = $item;
240
    }
241
242
    $thePath = publisherGetUploadDir(true, $path);
243
244
    if (empty($thePath)) {
245
        return false;
246
    }
247
    if (is_writable($thePath)) {
248
        $pathCheckResult = 1;
249
        $pathStatus      = _AM_PUBLISHER_AVAILABLE;
250
    } elseif (!@is_dir($thePath)) {
251
        $pathCheckResult = -1;
252
        $pathStatus      = _AM_PUBLISHER_NOTAVAILABLE . " <a href='" . PUBLISHER_ADMIN_URL . "/index.php?op=createdir&amp;path={$item}'>" . _AM_PUBLISHER_CREATETHEDIR . '</a>';
253
    } else {
254
        $pathCheckResult = -2;
255
        $pathStatus      = _AM_PUBLISHER_NOTWRITABLE . " <a href='" . PUBLISHER_ADMIN_URL . "/index.php?op=setperm&amp;path={$item}'>" . _AM_PUBLISHER_SETMPERM . '</a>';
256
    }
257
    if (!$getStatus) {
258
        return $pathStatus;
259
    } else {
260
        return $pathCheckResult;
261
    }
262
}
263
264
/**
265
 * @credits Thanks to the NewBB2 Development Team
266
 * @param  string $target
267
 * @return bool
268
 */
269
function publisherMkdir($target)
270
{
271
    // http://www.php.net/manual/en/function.mkdir.php
272
    // saint at corenova.com
273
    // bart at cdasites dot com
274
    if (empty($target) || is_dir($target)) {
275
        return true; // best case check first
276
    }
277
278
    if (file_exists($target) && !is_dir($target)) {
279
        return false;
280
    }
281
282
    if (publisherMkdir(substr($target, 0, strrpos($target, '/')))) {
283
        if (!file_exists($target)) {
284
            $res = mkdir($target, 0777); // crawl back up & create dir tree
285
            publisherChmod($target);
286
287
            return $res;
288
        }
289
    }
290
    $res = is_dir($target);
291
292
    return $res;
293
}
294
295
/**
296
 * @credits Thanks to the NewBB2 Development Team
297
 * @param  string $target
298
 * @param  int    $mode
299
 * @return bool
300
 */
301
function publisherChmod($target, $mode = 0777)
302
{
303
    return @chmod($target, $mode);
304
}
305
306
/**
307
 * @param  bool   $hasPath
308
 * @param  string $item
309
 * @return string
310
 */
311
function publisherGetUploadDir($hasPath = true, $item = '')
312
{
313
    if ('' !== $item) {
314
        if ($item === 'root') {
315
            $item = '';
316
        } else {
317
            $item .= '/';
318
        }
319
    }
320
321
    if ($hasPath) {
322
        return PUBLISHER_UPLOAD_PATH . '/' . $item;
323
    } else {
324
        return PUBLISHER_UPLOAD_URL . '/' . $item;
325
    }
326
}
327
328
/**
329
 * @param  string $item
330
 * @param  bool   $hasPath
331
 * @return string
332
 */
333
function publisherGetImageDir($item = '', $hasPath = true)
334
{
335
    if ($item) {
336
        $item = "images/{$item}";
337
    } else {
338
        $item = 'images';
339
    }
340
341
    return publisherGetUploadDir($hasPath, $item);
342
}
343
344
/**
345
 * @param  array $errors
346
 * @return string
347
 */
348
function publisherFormatErrors($errors = array())
349
{
350
    $ret = '';
351
    foreach ($errors as $key => $value) {
352
        $ret .= '<br> - ' . $value;
353
    }
354
355
    return $ret;
356
}
357
358
/**
359
 * Checks if a user is admin of Publisher
360
 *
361
 * @return boolean
362
 */
363
function publisherUserIsAdmin()
0 ignored issues
show
Coding Style introduced by
publisherUserIsAdmin uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
364
{
365
    $publisher = PublisherPublisher::getInstance();
366
367
    static $publisherIsAdmin;
368
369
    if (isset($publisherIsAdmin)) {
370
        return $publisherIsAdmin;
371
    }
372
373
    if (!$GLOBALS['xoopsUser']) {
374
        $publisherIsAdmin = false;
375
    } else {
376
        $publisherIsAdmin = $GLOBALS['xoopsUser']->isAdmin($publisher->getModule()->getVar('mid'));
0 ignored issues
show
Bug introduced by
The method getVar cannot be called on $publisher->getModule() (of type null).

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...
377
    }
378
379
    return $publisherIsAdmin;
380
}
381
382
/**
383
 * Check is current user is author of a given article
384
 *
385
 * @param  XoopsObject $itemObj
386
 * @return bool
387
 */
388
function publisherUserIsAuthor($itemObj)
0 ignored issues
show
Coding Style introduced by
publisherUserIsAuthor uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
389
{
390
    return (is_object($GLOBALS['xoopsUser']) && is_object($itemObj) && ($GLOBALS['xoopsUser']->uid() == $itemObj->uid()));
391
}
392
393
/**
394
 * Check is current user is moderator of a given article
395
 *
396
 * @param  XoopsObject $itemObj
397
 * @return bool
398
 */
399
function publisherUserIsModerator($itemObj)
400
{
401
    $publisher         = PublisherPublisher::getInstance();
402
    $categoriesGranted = $publisher->getHandler('permission')->getGrantedItems('category_moderation');
403
404
    return (is_object($itemObj) && in_array($itemObj->categoryid(), $categoriesGranted));
405
}
406
407
/**
408
 * Saves permissions for the selected category
409
 *
410
 * @param  array   $groups     : group with granted permission
411
 * @param  integer $categoryId : categoryid on which we are setting permissions
412
 * @param  string  $permName   : name of the permission
413
 * @return boolean : TRUE if the no errors occured
414
 */
415
function publisherSaveCategoryPermissions($groups, $categoryId, $permName)
416
{
417
    $publisher = PublisherPublisher::getInstance();
418
419
    $result = true;
420
421
    $moduleId     = $publisher->getModule()->getVar('mid');
0 ignored issues
show
Bug introduced by
The method getVar cannot be called on $publisher->getModule() (of type null).

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...
422
    $gpermHandler = xoops_getHandler('groupperm');
423
    // First, if the permissions are already there, delete them
424
    $gpermHandler->deleteByModule($moduleId, $permName, $categoryId);
425
426
    // Save the new permissions
427
    if (count($groups) > 0) {
428
        foreach ($groups as $groupId) {
429
            $gpermHandler->addRight($permName, $categoryId, $groupId, $moduleId);
430
        }
431
    }
432
433
    return $result;
434
}
435
436
/**
437
 * @param  string $tablename
438
 * @param  string $iconname
439
 * @param  string $tabletitle
440
 * @param  string $tabledsc
441
 * @param  bool   $open
442
 * @return void
443
 */
444
function publisherOpenCollapsableBar($tablename = '', $iconname = '', $tabletitle = '', $tabledsc = '', $open = true)
445
{
446
    $image   = 'open12.gif';
447
    $display = 'none';
448
    if ($open) {
449
        $image   = 'close12.gif';
450
        $display = 'block';
451
    }
452
453
    echo "<h3 style=\"color: #2F5376; font-weight: bold; font-size: 14px; margin: 6px 0 0 0; \"><a href='javascript:;' onclick=\"toggle('" . $tablename . "'); toggleIcon('" . $iconname . "')\">";
454
    echo "<img id='" . $iconname . "' src='" . PUBLISHER_URL . '/assets/images/links/' . $image . "' alt='' /></a>&nbsp;" . $tabletitle . '</h3>';
455
    echo "<div id='" . $tablename . "' style='display: " . $display . ";'>";
456
    if ($tabledsc != '') {
457
        echo "<span style=\"color: #567; margin: 3px 0 12px 0; font-size: small; display: block; \">" . $tabledsc . '</span>';
458
    }
459
}
460
461
/**
462
 * @param  string $name
463
 * @param  string $icon
464
 * @return void
465
 */
466
function publisherCloseCollapsableBar($name, $icon)
467
{
468
    echo '</div>';
469
470
    $urls = publisherGetCurrentUrls();
471
    $path = $urls['phpself'];
472
473
    $cookieName = $path . '_publisher_collaps_' . $name;
474
    $cookieName = str_replace('.', '_', $cookieName);
475
    $cookie     = publisherGetCookieVar($cookieName, '');
476
477
    if ($cookie === 'none') {
478
        echo '
479
        <script type="text/javascript"><!--
480
        toggle("' . $name . '"); toggleIcon("' . $icon . '");
481
        //-->
482
        </script>
483
        ';
484
    }
485
}
486
487
/**
488
 * @param  string $name
489
 * @param  string $value
490
 * @param  int    $time
491
 * @return void
492
 */
493
function publisherSetCookieVar($name, $value, $time = 0)
494
{
495
    if ($time == 0) {
496
        $time = time() + 3600 * 24 * 365;
497
    }
498
    setcookie($name, $value, $time, '/');
499
}
500
501
/**
502
 * @param  string $name
503
 * @param  string $default
504
 * @return string
505
 */
506
function publisherGetCookieVar($name, $default = '')
0 ignored issues
show
Unused Code introduced by
The parameter $name is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
507
{
508
    //    if (isset($_COOKIE[$name]) && ($_COOKIE[$name] > '')) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
71% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
509
    //        return $_COOKIE[$name];
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
510
    //    } else {
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
511
    //        return $default;
512
    //    }
513
    return XoopsRequest::getString('name', $default, 'COOKIE');
514
}
515
516
/**
517
 * @return array
518
 */
519
function publisherGetCurrentUrls()
520
{
521
    $http = strpos(XOOPS_URL, 'https://') === false ? 'http://' : 'https://';
522
    //    $phpself     = $_SERVER['PHP_SELF'];
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
523
    //    $httphost    = $_SERVER['HTTP_HOST'];
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
524
    //    $querystring = isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : '';
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
525
    $phpself     = XoopsRequest::getString('PHP_SELF', '', 'SERVER');
526
    $httphost    = XoopsRequest::getString('HTTP_HOST', '', 'SERVER');
527
    $querystring = XoopsRequest::getString('QUERY_STRING', '', 'SERVER');
528
529
    if ($querystring != '') {
530
        $querystring = '?' . $querystring;
531
    }
532
533
    $currenturl = $http . $httphost . $phpself . $querystring;
534
535
    $urls                = array();
536
    $urls['http']        = $http;
537
    $urls['httphost']    = $httphost;
538
    $urls['phpself']     = $phpself;
539
    $urls['querystring'] = $querystring;
540
    $urls['full']        = $currenturl;
541
542
    return $urls;
543
}
544
545
/**
546
 * @return string
547
 */
548
function publisherGetCurrentPage()
549
{
550
    $urls = publisherGetCurrentUrls();
551
552
    return $urls['full'];
553
}
554
555
/**
556
 * @param  null|PublisherCategory $categoryObj
0 ignored issues
show
Documentation introduced by
Consider making the type for parameter $categoryObj a bit more specific; maybe use PublisherCategory.
Loading history...
557
 * @param  int                    $selectedid
558
 * @param  int                    $level
559
 * @param  string                 $ret
560
 * @return string
561
 */
562
function publisherAddCategoryOption(PublisherCategory $categoryObj, $selectedid = 0, $level = 0, $ret = '')
563
{
564
    $publisher = PublisherPublisher::getInstance();
565
566
    $spaces = '';
567
    for ($j = 0; $j < $level; ++$j) {
568
        $spaces .= '--';
569
    }
570
571
    $ret .= "<option value='" . $categoryObj->categoryid() . "'";
572
    if (is_array($selectedid) && in_array($categoryObj->categoryid(), $selectedid)) {
573
        $ret .= " selected='selected'";
574
    } elseif ($categoryObj->categoryid() == $selectedid) {
575
        $ret .= " selected='selected'";
576
    }
577
    $ret .= '>' . $spaces . $categoryObj->name() . "</option>\n";
578
579
    $subCategoriesObj = $publisher->getHandler('category')->getCategories(0, 0, $categoryObj->categoryid());
580
    if (count($subCategoriesObj) > 0) {
581
        ++$level;
582
        foreach ($subCategoriesObj as $catID => $subCategoryObj) {
583
            $ret .= publisherAddCategoryOption($subCategoryObj, $selectedid, $level);
0 ignored issues
show
Bug introduced by
It seems like $selectedid can also be of type array; however, publisherAddCategoryOption() does only seem to accept integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
584
        }
585
    }
586
587
    return $ret;
588
}
589
590
/**
591
 * @param  int    $selectedid
592
 * @param  int    $parentcategory
593
 * @param  bool   $allCatOption
594
 * @param  string $selectname
595
 * @return string
596
 */
597
function publisherCreateCategorySelect($selectedid = 0, $parentcategory = 0, $allCatOption = true, $selectname = 'options[0]')
598
{
599
    $publisher = PublisherPublisher::getInstance();
600
601
    $selectedid = explode(',', $selectedid);
602
603
    $ret = "<select name='" . $selectname . "[]' multiple='multiple' size='10'>";
604
    if ($allCatOption) {
605
        $ret .= "<option value='0'";
606
        if (in_array(0, $selectedid)) {
607
            $ret .= " selected='selected'";
608
        }
609
        $ret .= '>' . _MB_PUBLISHER_ALLCAT . '</option>';
610
    }
611
612
    // Creating category objects
613
    $categoriesObj = $publisher->getHandler('category')->getCategories(0, 0, $parentcategory);
614
615 View Code Duplication
    if (count($categoriesObj) > 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
616
        foreach ($categoriesObj as $catID => $categoryObj) {
617
            $ret .= publisherAddCategoryOption($categoryObj, $selectedid);
0 ignored issues
show
Documentation introduced by
$selectedid is of type array, but the function expects a integer.

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...
618
        }
619
    }
620
    $ret .= '</select>';
621
622
    return $ret;
623
}
624
625
/**
626
 * @param  int  $selectedid
627
 * @param  int  $parentcategory
628
 * @param  bool $allCatOption
629
 * @return string
630
 */
631
function publisherCreateCategoryOptions($selectedid = 0, $parentcategory = 0, $allCatOption = true)
632
{
633
    $publisher = PublisherPublisher::getInstance();
634
635
    $ret = '';
636
    if ($allCatOption) {
637
        $ret .= "<option value='0'";
638
        $ret .= '>' . _MB_PUBLISHER_ALLCAT . "</option>\n";
639
    }
640
641
    // Creating category objects
642
    $categoriesObj = $publisher->getHandler('category')->getCategories(0, 0, $parentcategory);
643 View Code Duplication
    if (count($categoriesObj) > 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
644
        foreach ($categoriesObj as $catID => $categoryObj) {
645
            $ret .= publisherAddCategoryOption($categoryObj, $selectedid);
646
        }
647
    }
648
649
    return $ret;
650
}
651
652
/**
653
 * @param  array  $errArray
654
 * @param  string $reseturl
655
 * @return void
656
 */
657
function publisherRenderErrors(&$errArray, $reseturl = '')
658
{
659
    if (is_array($errArray) && count($errArray) > 0) {
660
        echo '<div id="readOnly" class="errorMsg" style="border:1px solid #D24D00; background:#FEFECC url(' . PUBLISHER_URL
661
             . '/assets/images/important-32.png) no-repeat 7px 50%;color:#333;padding-left:45px;">';
662
663
        echo '<h4 style="text-align:left;margin:0; padding-top:0;">' . _AM_PUBLISHER_MSG_SUBMISSION_ERR;
664
665
        if ($reseturl) {
666
            echo ' <a href="' . $reseturl . '">[' . _AM_PUBLISHER_TEXT_SESSION_RESET . ']</a>';
667
        }
668
669
        echo '</h4><ul>';
670
671
        foreach ($errArray as $key => $error) {
672
            if (is_array($error)) {
673
                foreach ($error as $err) {
674
                    echo '<li><a href="#' . $key . '" onclick="var e = xoopsGetElementById(\'' . $key . '\'); e.focus();">' . htmlspecialchars($err) . '</a></li>';
675
                }
676
            } else {
677
                echo '<li><a href="#' . $key . '" onclick="var e = xoopsGetElementById(\'' . $key . '\'); e.focus();">' . htmlspecialchars($error) . '</a></li>';
678
            }
679
        }
680
        echo '</ul></div><br>';
681
    }
682
}
683
684
/**
685
 * Generate publisher URL
686
 *
687
 * @param  string $page
688
 * @param  array  $vars
689
 * @param  bool   $encodeAmp
690
 * @return string
691
 *
692
 * @credit : xHelp module, developped by 3Dev
693
 */
694
function publisherMakeUri($page, $vars = array(), $encodeAmp = true)
695
{
696
    $joinStr = '';
697
698
    $amp = ($encodeAmp ? '&amp;' : '&');
699
700
    if (!count($vars)) {
701
        return $page;
702
    }
703
704
    $qs = '';
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $qs. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
705
    foreach ($vars as $key => $value) {
706
        $qs .= $joinStr . $key . '=' . $value;
707
        $joinStr = $amp;
708
    }
709
710
    return $page . '?' . $qs;
711
}
712
713
/**
714
 * @param  string $subject
715
 * @return string
716
 */
717
function publisherTellAFriend($subject = '')
718
{
719
    if (false !== strpos($subject, '%')) {
720
        $subject = rawurldecode($subject);
721
    }
722
723
    $targetUri = XOOPS_URL . XoopsRequest::getString('REQUEST_URI', '', 'SERVER');
724
725
    return XOOPS_URL . '/modules/tellafriend/index.php?target_uri=' . rawurlencode($targetUri) . '&amp;subject=' . rawurlencode($subject);
726
}
727
728
/**
729
 * @param  bool        $another
730
 * @param  bool        $withRedirect
731
 * @param              $itemObj
732
 * @return bool|string
733
 */
734
function publisherUploadFile($another = false, $withRedirect = true, &$itemObj)
0 ignored issues
show
Coding Style introduced by
publisherUploadFile uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
publisherUploadFile uses the super-global variable $_FILES which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
735
{
736
    include_once PUBLISHER_ROOT_PATH . '/class/uploader.php';
737
738
    //    global $publisherIsAdmin;
739
    $publisher = PublisherPublisher::getInstance();
740
741
    $itemId  = XoopsRequest::getInt('itemid', 0, 'POST');
742
    $uid     = is_object($GLOBALS['xoopsUser']) ? $GLOBALS['xoopsUser']->uid() : 0;
743
    $session = PublisherSession::getInstance();
744
    $session->set('publisher_file_filename', XoopsRequest::getString('item_file_name', '', 'POST'));
745
    $session->set('publisher_file_description', XoopsRequest::getString('item_file_description', '', 'POST'));
746
    $session->set('publisher_file_status', XoopsRequest::getInt('item_file_status', 1, 'POST'));
747
    $session->set('publisher_file_uid', $uid);
748
    $session->set('publisher_file_itemid', $itemId);
749
750
    if (!is_object($itemObj)) {
751
        $itemObj = $publisher->getHandler('item')->get($itemId);
752
    }
753
754
    $fileObj = $publisher->getHandler('file')->create();
755
    $fileObj->setVar('name', XoopsRequest::getString('item_file_name', '', 'POST'));
756
    $fileObj->setVar('description', XoopsRequest::getString('item_file_description', '', 'POST'));
757
    $fileObj->setVar('status', XoopsRequest::getInt('item_file_status', 1, 'POST'));
758
    $fileObj->setVar('uid', $uid);
759
    $fileObj->setVar('itemid', $itemObj->getVar('itemid'));
760
    $fileObj->setVar('datesub', time());
761
762
    // Get available mimetypes for file uploading
763
    $allowedMimetypes = $publisher->getHandler('mimetype')->getArrayByType();
764
    // TODO : display the available mimetypes to the user
765
    $errors = array();
766
    if ($publisher->getConfig('perm_upload') && is_uploaded_file($_FILES['item_upload_file']['tmp_name'])) {
767
        if (!$ret = $fileObj->checkUpload('item_upload_file', $allowedMimetypes, $errors)) {
768
            $errorstxt = implode('<br>', $errors);
769
770
            $message = sprintf(_CO_PUBLISHER_MESSAGE_FILE_ERROR, $errorstxt);
771
            if ($withRedirect) {
772
                redirect_header('file.php?op=mod&itemid=' . $itemId, 5, $message);
773
            } else {
774
                return $message;
775
            }
776
        }
777
    }
778
779
    // Storing the file
780
    if (!$fileObj->store($allowedMimetypes)) {
781
        //        if ($withRedirect) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
63% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
782
        //            redirect_header("file.php?op=mod&itemid=" . $fileObj->itemid(), 3, _CO_PUBLISHER_FILEUPLOAD_ERROR . publisherFormatErrors($fileObj->getErrors()));
0 ignored issues
show
Unused Code Comprehensibility introduced by
55% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
783
        //            exit;
784
        //        }
785
        try {
786
            if ($withRedirect) {
787
                throw new Exception(_CO_PUBLISHER_FILEUPLOAD_ERROR . publisherFormatErrors($fileObj->getErrors()));
788
            }
789
        } catch (Exception $e) {
790
            redirect_header('file.php?op=mod&itemid=' . $fileObj->itemid(), 3, _CO_PUBLISHER_FILEUPLOAD_ERROR . publisherFormatErrors($fileObj->getErrors()));
791
        }
792
        //    } else {
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
793
        //        return _CO_PUBLISHER_FILEUPLOAD_ERROR . publisherFormatErrors($fileObj->getErrors());
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
794
    }
795
796
    if ($withRedirect) {
797
        $redirectPage = $another ? 'file.php' : 'item.php';
798
        redirect_header($redirectPage . '?op=mod&itemid=' . $fileObj->itemid(), 2, _CO_PUBLISHER_FILEUPLOAD_SUCCESS);
799
    } else {
800
        return true;
801
    }
802
803
    return null;
804
}
805
806
/**
807
 * @return string
808
 */
809
function publisherNewFeatureTag()
810
{
811
    $ret = '<span style="padding-right: 4px; font-weight: bold; color: red;">' . _CO_PUBLISHER_NEW_FEATURE . '</span>';
812
813
    return $ret;
814
}
815
816
/**
817
 * Smarty truncate_tagsafe modifier plugin
818
 *
819
 * Type:     modifier<br>
820
 * Name:     truncate_tagsafe<br>
821
 * Purpose:  Truncate a string to a certain length if necessary,
822
 *           optionally splitting in the middle of a word, and
823
 *           appending the $etc string or inserting $etc into the middle.
824
 *           Makes sure no tags are left half-open or half-closed
825
 *           (e.g. "Banana in a <a...")
826
 * @author   Monte Ohrt <monte at ohrt dot com>, modified by Amos Robinson
827
 *           <amos dot robinson at gmail dot com>
828
 * @param string
829
 * @param integer
830
 * @param string
831
 * @param boolean
832
 * @param boolean
833
 * @return string
834
 */
835
function publisherTruncateTagSafe($string, $length = 80, $etc = '...', $breakWords = false)
836
{
837
    if ($length == 0) {
838
        return '';
839
    }
840
841
    if (strlen($string) > $length) {
842
        $length -= strlen($etc);
843
        if (!$breakWords) {
844
            $string = preg_replace('/\s+?(\S+)?$/', '', substr($string, 0, $length + 1));
845
            $string = preg_replace('/<[^>]*$/', '', $string);
846
            $string = publisherCloseTags($string);
847
        }
848
849
        return $string . $etc;
850
    } else {
851
        return $string;
852
    }
853
}
854
855
/**
856
 * @author   Monte Ohrt <monte at ohrt dot com>, modified by Amos Robinson
857
 *           <amos dot robinson at gmail dot com>
858
 * @param  string $string
859
 * @return string
860
 */
861
function publisherCloseTags($string)
862
{
863
    // match opened tags
864
    if (preg_match_all('/<([a-z\:\-]+)[^\/]>/', $string, $startTags)) {
865
        $startTags = $startTags[1];
866
        // match closed tags
867
        if (preg_match_all('/<\/([a-z]+)>/', $string, $endTags)) {
868
            $completeTags = array();
869
            $endTags      = $endTags[1];
870
871
            foreach ($startTags as $key => $val) {
872
                $posb = array_search($val, $endTags);
873
                if (is_int($posb)) {
874
                    unset($endTags[$posb]);
875
                } else {
876
                    $completeTags[] = $val;
877
                }
878
            }
879
        } else {
880
            $completeTags = $startTags;
881
        }
882
883
        $completeTags = array_reverse($completeTags);
884
        $elementCount = count($completeTags);
885
        for ($i = 0; $i < $elementCount; ++$i) {
886
            $string .= '</' . $completeTags[$i] . '>';
887
        }
888
    }
889
890
    return $string;
891
}
892
893
/**
894
 * @param  int $itemId
895
 * @return string
896
 */
897
function publisherRatingBar($itemId)
0 ignored issues
show
Coding Style introduced by
publisherRatingBar uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
898
{
899
    $publisher       = PublisherPublisher::getInstance();
900
    $ratingUnitWidth = 30;
901
    $units           = 5;
902
903
    $criteria   = new Criteria('itemid', $itemId);
904
    $ratingObjs = $publisher->getHandler('rating')->getObjects($criteria);
905
    unset($criteria);
906
907
    $uid           = is_object($GLOBALS['xoopsUser']) ? $GLOBALS['xoopsUser']->getVar('uid') : 0;
908
    $count         = count($ratingObjs);
909
    $currentRating = 0;
910
    $voted         = false;
911
    $ip            = getenv('REMOTE_ADDR');
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $ip. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
912
    $rating1       = $rating2 = $ratingWidth = 0;
913
914 View Code Duplication
    foreach ($ratingObjs as $ratingObj) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
915
        $currentRating += $ratingObj->getVar('rate');
916
        if ($ratingObj->getVar('ip') == $ip || ($uid > 0 && $uid == $ratingObj->getVar('uid'))) {
917
            $voted = true;
918
        }
919
    }
920
921
    $tense = $count == 1 ? _MD_PUBLISHER_VOTE_VOTE : _MD_PUBLISHER_VOTE_VOTES; //plural form votes/vote
922
923
    // now draw the rating bar
924
    if ($count != 0) {
925
        $ratingWidth = number_format($currentRating / $count, 2) * $ratingUnitWidth;
926
        $rating1     = number_format($currentRating / $count, 1);
927
        $rating2     = number_format($currentRating / $count, 2);
928
    }
929
    $groups       = $GLOBALS['xoopsUser'] ? $GLOBALS['xoopsUser']->getGroups() : XOOPS_GROUP_ANONYMOUS;
930
    $gpermHandler = $publisher->getHandler('groupperm');
931
932
    if (!$gpermHandler->checkRight('global', PublisherConstants::PUBLISHER_RATE, $groups, $publisher->getModule()->getVar('mid'))) {
0 ignored issues
show
Bug introduced by
The method getVar cannot be called on $publisher->getModule() (of type null).

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...
933
        $staticRater = array();
934
        $staticRater[] .= "\n" . '<div class="publisher_ratingblock">';
935
        $staticRater[] .= '<div id="unit_long' . $itemId . '">';
936
        $staticRater[] .= '<div id="unit_ul' . $itemId . '" class="publisher_unit-rating" style="width:' . $ratingUnitWidth * $units . 'px;">';
937
        $staticRater[] .= '<div class="publisher_current-rating" style="width:' . $ratingWidth . 'px;">' . _MD_PUBLISHER_VOTE_RATING . ' ' . $rating2 . '/' . $units . '</div>';
938
        $staticRater[] .= '</div>';
939
        $staticRater[] .= '<div class="publisher_static">' . _MD_PUBLISHER_VOTE_RATING . ': <strong> ' . $rating1 . '</strong>/' . $units . ' (' . $count . ' ' . $tense . ') <br><em>'
940
                          . _MD_PUBLISHER_VOTE_DISABLE . '</em></div>';
941
        $staticRater[] .= '</div>';
942
        $staticRater[] .= '</div>' . "\n\n";
943
944
        return implode("\n", $staticRater);
945
    } else {
946
        $rater = '';
947
        $rater .= '<div class="publisher_ratingblock">';
948
        $rater .= '<div id="unit_long' . $itemId . '">';
949
        $rater .= '<div id="unit_ul' . $itemId . '" class="publisher_unit-rating" style="width:' . $ratingUnitWidth * $units . 'px;">';
950
        $rater .= '<div class="publisher_current-rating" style="width:' . $ratingWidth . 'px;">' . _MD_PUBLISHER_VOTE_RATING . ' ' . $rating2 . '/' . $units . '</div>';
951
952
        for ($ncount = 1; $ncount <= $units; ++$ncount) { // loop from 1 to the number of units
953
            if (!$voted) { // if the user hasn't yet voted, draw the voting stars
954
                $rater .= '<div><a href="' . PUBLISHER_URL . '/rate.php?itemid=' . $itemId . '&amp;rating=' . $ncount . '" title="' . $ncount . ' ' . _MD_PUBLISHER_VOTE_OUTOF . ' ' . $units
955
                          . '" class="publisher_r' . $ncount . '-unit rater" rel="nofollow">' . $ncount . '</a></div>';
956
            }
957
        }
958
959
        $ncount = 0; // resets the count
0 ignored issues
show
Unused Code introduced by
$ncount is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
960
        $rater .= '  </div>';
961
        $rater .= '  <div';
962
963
        if ($voted) {
964
            $rater .= ' class="publisher_voted"';
965
        }
966
967
        $rater .= '>' . _MD_PUBLISHER_VOTE_RATING . ': <strong> ' . $rating1 . '</strong>/' . $units . ' (' . $count . ' ' . $tense . ')';
968
        $rater .= '  </div>';
969
        $rater .= '</div>';
970
        $rater .= '</div>';
971
972
        return $rater;
973
    }
974
}
975
976
/**
977
 * @param  array $allowedEditors
0 ignored issues
show
Documentation introduced by
Should the type for parameter $allowedEditors not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
978
 * @return array
979
 */
980
function publisherGetEditors($allowedEditors = null)
981
{
982
    $ret    = array();
983
    $nohtml = false;
984
    xoops_load('XoopsEditorHandler');
985
    $editorHandler = XoopsEditorHandler::getInstance();
986
    $editors       = $editorHandler->getList($nohtml);
987
    foreach ($editors as $name => $title) {
988
        $key = publisherStringToInt($name);
989
        if (is_array($allowedEditors)) {
990
            //for submit page
991
            if (in_array($key, $allowedEditors)) {
992
                $ret[] = $name;
993
            }
994
        } else {
995
            //for admin permissions page
996
            $ret[$key]['name']  = $name;
997
            $ret[$key]['title'] = $title;
998
        }
999
    }
1000
1001
    return $ret;
1002
}
1003
1004
/**
1005
 * @param  string $string
1006
 * @param  int    $length
1007
 * @return int
1008
 */
1009
function publisherStringToInt($string = '', $length = 5)
1010
{
1011
    $final  = '';
1012
    $string = substr(md5($string), $length);
1013
    for ($i = 0; $i < $length; ++$i) {
1014
        $final .= (int)$string[$i];
1015
    }
1016
1017
    return (int)$final;
1018
}
1019
1020
/**
1021
 * @param  string $item
1022
 * @return string
1023
 */
1024
function publisherConvertCharset($item)
1025
{
1026
    if (_CHARSET !== 'windows-1256') {
1027
        return utf8_encode($item);
1028
    }
1029
1030
    if ($unserialize == unserialize($item)) {
0 ignored issues
show
Security Object Injection introduced by
$item can contain request data and is used in unserialized context(s) leading to a potential security vulnerability.

3 paths for user data to reach this point

  1. Path: Read from $_FILES, and XoopsMediaUploader::$mediaSize is assigned in class/uploader.php on line 161
  1. Read from $_FILES, and XoopsMediaUploader::$mediaSize is assigned
    in class/uploader.php on line 161
  2. Tainted property XoopsMediaUploader::$mediaSize is read, and $this->mediaSize is passed through sprintf(), and sprintf('File Size: %u. Maximum Size Allowed: %u', $this->mediaSize, $this->maxFileSize) is passed to XoopsMediaUploader::setErrors()
    in class/uploader.php on line 191
  3. $error is passed through trim(), and XoopsMediaUploader::$errors is assigned
    in class/uploader.php on line 463
  4. Tainted property XoopsMediaUploader::$errors is read
    in class/uploader.php on line 476
  5. XoopsMediaUploader::getErrors() returns tainted data, and $uploader->getErrors(false) is passed through implode(), and $error is assigned
    in include/ajax_upload.php on line 75
  6. $error is passed to publisherConvertCharset()
    in include/ajax_upload.php on line 106
  2. Path: Read from $_FILES, and XoopsMediaUploader::$mediaType is assigned in class/uploader.php on line 160
  1. Read from $_FILES, and XoopsMediaUploader::$mediaType is assigned
    in class/uploader.php on line 160
  2. Tainted property XoopsMediaUploader::$mediaType is read, and 'MIME type not allowed: ' . $this->mediaType is passed to XoopsMediaUploader::setErrors()
    in class/uploader.php on line 205
  3. $error is passed through trim(), and XoopsMediaUploader::$errors is assigned
    in class/uploader.php on line 463
  4. Tainted property XoopsMediaUploader::$errors is read
    in class/uploader.php on line 476
  5. XoopsMediaUploader::getErrors() returns tainted data, and $uploader->getErrors(false) is passed through implode(), and $error is assigned
    in include/ajax_upload.php on line 75
  6. $error is passed to publisherConvertCharset()
    in include/ajax_upload.php on line 106
  3. Path: Read from $_FILES, and XoopsMediaUploader::$mediaName is assigned in class/uploader.php on line 159
  1. Read from $_FILES, and XoopsMediaUploader::$mediaName is assigned
    in class/uploader.php on line 159
  2. Tainted property XoopsMediaUploader::$mediaName is read, and 'Failed uploading file: ' . $this->mediaName is passed to XoopsMediaUploader::setErrors()
    in class/uploader.php on line 354
  3. $error is passed through trim(), and XoopsMediaUploader::$errors is assigned
    in class/uploader.php on line 463
  4. Tainted property XoopsMediaUploader::$errors is read
    in class/uploader.php on line 476
  5. XoopsMediaUploader::getErrors() returns tainted data, and $uploader->getErrors(false) is passed through implode(), and $error is assigned
    in include/ajax_upload.php on line 75
  6. $error is passed to publisherConvertCharset()
    in include/ajax_upload.php on line 106

Preventing Object Injection Attacks

If you pass raw user-data to unserialize() for example, this can be used to create an object of any class that is available in your local filesystem. For an attacker, classes that have magic methods like __destruct or __wakeup are particularly interesting in such a case, as they can be exploited very easily.

We recommend to not pass user data to such a function. In case of unserialize, better use JSON to transfer data.

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
1031
        foreach ($unserialize as $key => $value) {
0 ignored issues
show
Bug introduced by
The variable $unserialize does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1032
            $unserialize[$key] = @iconv('windows-1256', 'UTF-8', $value);
0 ignored issues
show
Coding Style Comprehensibility introduced by
$unserialize was never initialized. Although not strictly required by PHP, it is generally a good practice to add $unserialize = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
1033
        }
1034
        $serialize = serialize($unserialize);
1035
1036
        return $serialize;
1037
    } else {
1038
        return @iconv('windows-1256', 'UTF-8', $item);
1039
    }
1040
}
1041