Completed
Branch master (da9c5e)
by Michael
03:00
created

PublisherUtility::copyr()   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
nc 9
nop 2
dl 0
loc 33
rs 5.3846
c 0
b 0
f 0
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 31 and the first side effect is on line 24.

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
 * PublisherUtil Class
13
 *
14
 * @copyright   XOOPS Project (http://xoops.org)
15
 * @license     http://www.fsf.org/copyleft/gpl.html GNU public license
16
 * @author      XOOPS Development Team
17
 * @package     Publisher
18
 * @since       1.03
19
 *
20
 */
21
22
use \Xmf\Request;
23
24
include_once dirname(__DIR__) . '/include/common.php';
25
26
//namespace Publisher;
27
28
/**
29
 * Class PublisherUtility
30
 */
31
class PublisherUtility
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
32
{
33
    /**
34
     * Check Xoops Version against a provided version
35
     *
36
     * @param int $x
37
     * @param int $y
38
     * @param int $z
39
     * @param string $signal
40
     * @return bool
41
     */
42
    public static function checkXoopsVersion($x, $y, $z, $signal = '==')
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $x. 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...
Comprehensibility introduced by
Avoid variables with short names like $y. 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...
Comprehensibility introduced by
Avoid variables with short names like $z. 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...
43
    {
44
        $xv = explode('-', str_replace('XOOPS ', '', XOOPS_VERSION));
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $xv. 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...
45
46
        list($a, $b, $c) = explode('.', $xv[0]);
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $a. 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...
Comprehensibility introduced by
Avoid variables with short names like $b. 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...
Comprehensibility introduced by
Avoid variables with short names like $c. 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...
47
        $xv = $a*10000 + $b*100 + $c;
48
        $mv = $x*10000 + $y*100 + $z;
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $mv. 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...
49
        if ($signal === '>') return $xv > $mv;
50
        if ($signal === '>=') return $xv >= $mv;
51
        if ($signal === '<') return $xv < $mv;
52
        if ($signal === '<=') return $xv <= $mv;
53
        if ($signal === '==') return $xv == $mv;
54
55
        return false;
56
    }
57
58
    /**
59
     * Function responsible for checking if a directory exists, we can also write in and create an index.html file
60
     *
61
     * @param string $folder The full path of the directory to check
62
     *
63
     * @return void
64
     */
65
    public static function createFolder($folder)
66
    {
67
        try {
68
            if (!file_exists($folder)) {
69
                if (!mkdir($folder) && !is_dir($folder)) {
70
                    throw new \RuntimeException(sprintf('Unable to create the %s directory', $folder));
71
                } else {
72
                    file_put_contents($folder . '/index.html', '<script>history.go(-1);</script>');
73
                }
74
            }
75
        } catch (Exception $e) {
76
            echo 'Caught exception: ', $e->getMessage(), "\n", '<br/>';
77
        }
78
    }
79
80
    /**
81
     * @param $file
82
     * @param $folder
83
     * @return bool
84
     */
85
    public static function copyFile($file, $folder)
86
    {
87
        return copy($file, $folder);
88
        //        try {
89
        //            if (!is_dir($folder)) {
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...
90
        //                throw new \RuntimeException(sprintf('Unable to copy file as: %s ', $folder));
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...
91
        //            } 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...
92
        //                return copy($file, $folder);
0 ignored issues
show
Unused Code Comprehensibility introduced by
64% 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...
93
        //            }
94
        //        } catch (Exception $e) {
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...
95
        //            echo 'Caught exception: ', $e->getMessage(), "\n", "<br>";
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...
96
        //        }
97
        //        return false;
98
    }
99
100
    /**
101
     * @param $src
102
     * @param $dst
103
     */
104
    public static function recurseCopy($src, $dst)
105
    {
106
        $dir = opendir($src);
107
        //    @mkdir($dst);
108
        while (false !== ($file = readdir($dir))) {
109
            if (($file !== '.') && ($file !== '..')) {
110
                if (is_dir($src . '/' . $file)) {
111
                    self::recurseCopy($src . '/' . $file, $dst . '/' . $file);
112
                } else {
113
                    copy($src . '/' . $file, $dst . '/' . $file);
114
                }
115
            }
116
        }
117
        closedir($dir);
118
    }
119
120
    // auto create folders----------------------------------------
121
    //TODO rename this function? And exclude image folder?
122
    public static function createDir()
123
    {
124
        // auto crate folders
125
        //        $thePath = static::getUploadDir();
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...
126
127 View Code Duplication
        if (static::getPathStatus('root', true) < 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...
128
            $thePath = static::getUploadDir();
129
            $res     = static::mkdir($thePath);
130
            $msg     = $res ? _AM_PUBLISHER_DIRCREATED : _AM_PUBLISHER_DIRNOTCREATED;
0 ignored issues
show
Unused Code introduced by
$msg 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...
131
        }
132
133 View Code Duplication
        if (static::getPathStatus('images', true) < 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...
134
            $thePath = static::getImageDir();
135
            $res     = static::mkdir($thePath);
136
137
            if ($res) {
138
                $source = PUBLISHER_ROOT_PATH . '/assets/images/blank.png';
139
                $dest   = $thePath . 'blank.png';
140
                static::copyr($source, $dest);
141
            }
142
            $msg = $res ? _AM_PUBLISHER_DIRCREATED : _AM_PUBLISHER_DIRNOTCREATED;
0 ignored issues
show
Unused Code introduced by
$msg 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...
143
        }
144
145 View Code Duplication
        if (static::getPathStatus('images/category', true) < 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...
146
            $thePath = static::getImageDir('category');
147
            $res     = static::mkdir($thePath);
148
149
            if ($res) {
150
                $source = PUBLISHER_ROOT_PATH . '/assets/images/blank.png';
151
                $dest   = $thePath . 'blank.png';
152
                static::copyr($source, $dest);
153
            }
154
            $msg = $res ? _AM_PUBLISHER_DIRCREATED : _AM_PUBLISHER_DIRNOTCREATED;
0 ignored issues
show
Unused Code introduced by
$msg 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...
155
        }
156
157 View Code Duplication
        if (static::getPathStatus('images/item', true) < 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...
158
            $thePath = static::getImageDir('item');
159
            $res     = static::mkdir($thePath);
160
161
            if ($res) {
162
                $source = PUBLISHER_ROOT_PATH . '/assets/images/blank.png';
163
                $dest   = $thePath . 'blank.png';
164
                static::copyr($source, $dest);
165
            }
166
            $msg = $res ? _AM_PUBLISHER_DIRCREATED : _AM_PUBLISHER_DIRNOTCREATED;
0 ignored issues
show
Unused Code introduced by
$msg 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...
167
        }
168
169 View Code Duplication
        if (static::getPathStatus('content', true) < 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...
170
            $thePath = static::getUploadDir(true, 'content');
171
            $res     = static::mkdir($thePath);
172
            $msg     = $res ? _AM_PUBLISHER_DIRCREATED : _AM_PUBLISHER_DIRNOTCREATED;
0 ignored issues
show
Unused Code introduced by
$msg 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...
173
        }
174
    }
175
176
    public static function buildTableItemTitleRow()
177
    {
178
        echo "<table width='100%' cellspacing='1' cellpadding='3' border='0' class='outer'>";
179
        echo '<tr>';
180
        echo "<th width='40px' class='bg3' align='center'><strong>" . _AM_PUBLISHER_ITEMID . '</strong></td>';
181
        echo "<th width='100px' class='bg3' align='center'><strong>" . _AM_PUBLISHER_ITEMCAT . '</strong></td>';
182
        echo "<th class='bg3' align='center'><strong>" . _AM_PUBLISHER_TITLE . '</strong></td>';
183
        echo "<th width='100px' class='bg3' align='center'><strong>" . _AM_PUBLISHER_CREATED . '</strong></td>';
184
185
        echo "<th width='50px' class='bg3' align='center'><strong>" . _CO_PUBLISHER_WEIGHT . '</strong></td>';
186
        echo "<th width='50px' class='bg3' align='center'><strong>" . _AM_PUBLISHER_HITS . '</strong></td>';
187
        echo "<th width='60px' class='bg3' align='center'><strong>" . _AM_PUBLISHER_RATE . '</strong></td>';
188
        echo "<th width='50px' class='bg3' align='center'><strong>" . _AM_PUBLISHER_VOTES . '</strong></td>';
189
        echo "<th width='60px' class='bg3' align='center'><strong>" . _AM_PUBLISHER_COMMENTS_COUNT . '</strong></td>';
190
191
        echo "<th width='90px' class='bg3' align='center'><strong>" . _CO_PUBLISHER_STATUS . '</strong></td>';
192
        echo "<th width='90px' class='bg3' align='center'><strong>" . _AM_PUBLISHER_ACTION . '</strong></td>';
193
        echo '</tr>';
194
    }
195
196
    /**
197
     * @param     $categoryObj
198
     * @param int $level
199
     */
200
    public static function displayCategory(PublisherCategory $categoryObj, $level = 0)
201
    {
202
        $publisher = PublisherPublisher::getInstance();
203
204
        $description = $categoryObj->description();
205
        if (!XOOPS_USE_MULTIBYTES) {
206
            if (strlen($description) >= 100) {
207
                $description = substr($description, 0, 100 - 1) . '...';
0 ignored issues
show
Unused Code introduced by
$description 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...
208
            }
209
        }
210
        $modify = "<a href='category.php?op=mod&amp;categoryid="
211
                  . $categoryObj->categoryid()
212
                  . '&amp;parentid='
213
                  . $categoryObj->parentid()
214
                  . "'><img src='"
215
                  . PUBLISHER_URL
216
                  . "/assets/images/links/edit.gif' title='"
217
                  . _AM_PUBLISHER_EDITCOL
218
                  . "' alt='"
219
                  . _AM_PUBLISHER_EDITCOL
220
                  . "' /></a>";
221
        $delete = "<a href='category.php?op=del&amp;categoryid="
222
                  . $categoryObj->categoryid()
223
                  . "'><img src='"
224
                  . PUBLISHER_URL
225
                  . "/assets/images/links/delete.png' title='"
226
                  . _AM_PUBLISHER_DELETECOL
227
                  . "' alt='"
228
                  . _AM_PUBLISHER_DELETECOL
229
                  . "' /></a>";
230
231
        $spaces = '';
232
        for ($j = 0; $j < $level; ++$j) {
233
            $spaces .= '&nbsp;&nbsp;&nbsp;';
234
        }
235
236
        echo '<tr>';
237
        echo "<td class='even' align='center'>" . $categoryObj->categoryid() . '</td>';
238
        echo "<td class='even' align='left'>"
239
             . $spaces
240
             . "<a href='"
241
             . PUBLISHER_URL
242
             . '/category.php?categoryid='
243
             . $categoryObj->categoryid()
244
             . "'><img src='"
245
             . PUBLISHER_URL
246
             . "/assets/images/links/subcat.gif' alt='' />&nbsp;"
247
             . $categoryObj->name()
248
             . '</a></td>';
249
        echo "<td class='even' align='center'>" . $categoryObj->weight() . '</td>';
250
        echo "<td class='even' align='center'> $modify $delete </td>";
251
        echo '</tr>';
252
        $subCategoriesObj = $publisher->getHandler('category')->getCategories(0, 0, $categoryObj->categoryid());
253
        if (count($subCategoriesObj) > 0) {
254
            ++$level;
255
            foreach ($subCategoriesObj as $key => $thiscat) {
256
                self::displayCategory($thiscat, $level);
257
            }
258
            unset($key, $thiscat);
259
        }
260
        //        unset($categoryObj);
0 ignored issues
show
Unused Code Comprehensibility introduced by
84% 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...
261
    }
262
263
    /**
264
     * @param bool $showmenu
265
     * @param int  $categoryId
266
     * @param int  $nbSubCats
267
     * @param null $categoryObj
268
     */
269
    public static function editCategory($showmenu = false, $categoryId = 0, $nbSubCats = 4, $categoryObj = null)
0 ignored issues
show
Unused Code introduced by
The parameter $showmenu 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...
270
    {
271
        $publisher = PublisherPublisher::getInstance();
272
273
        // if there is a parameter, and the id exists, retrieve data: we're editing a category
274
        if ($categoryId != 0) {
275
            // Creating the category object for the selected category
276
            $categoryObj = $publisher->getHandler('category')->get($categoryId);
277
            if ($categoryObj->notLoaded()) {
278
                redirect_header('category.php', 1, _AM_PUBLISHER_NOCOLTOEDIT);
279
                //            exit();
280
            }
281
        } else {
282
            if (!$categoryObj) {
283
                $categoryObj = $publisher->getHandler('category')->create();
284
            }
285
        }
286
287
        if ($categoryId != 0) {
288
            echo "<br>\n";
289
            static::openCollapsableBar('edittable', 'edittableicon', _AM_PUBLISHER_EDITCOL, _AM_PUBLISHER_CATEGORY_EDIT_INFO);
290
        } else {
291
            static::openCollapsableBar('createtable', 'createtableicon', _AM_PUBLISHER_CATEGORY_CREATE, _AM_PUBLISHER_CATEGORY_CREATE_INFO);
292
        }
293
294
        $sform = $categoryObj->getForm($nbSubCats);
295
        $sform->display();
296
297
        if (!$categoryId) {
298
            static::closeCollapsableBar('createtable', 'createtableicon');
299
        } else {
300
            static::closeCollapsableBar('edittable', 'edittableicon');
301
        }
302
303
        //Added by fx2024
304
        if ($categoryId) {
305
            $selCat = $categoryId;
306
307
            static::openCollapsableBar('subcatstable', 'subcatsicon', _AM_PUBLISHER_SUBCAT_CAT, _AM_PUBLISHER_SUBCAT_CAT_DSC);
308
            // Get the total number of sub-categories
309
            $categoriesObj = $publisher->getHandler('category')->get($selCat);
310
            $totalsubs     = $publisher->getHandler('category')->getCategoriesCount($selCat);
311
            // creating the categories objects that are published
312
            $subcatsObj    = $publisher->getHandler('category')->getCategories(0, 0, $categoriesObj->categoryid());
313
            $totalSCOnPage = count($subcatsObj);
0 ignored issues
show
Unused Code introduced by
$totalSCOnPage 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...
314
            echo "<table width='100%' cellspacing=1 cellpadding=3 border=0 class = outer>";
315
            echo '<tr>';
316
            echo "<td width='60' class='bg3' align='left'><strong>" . _AM_PUBLISHER_CATID . '</strong></td>';
317
            echo "<td width='20%' class='bg3' align='left'><strong>" . _AM_PUBLISHER_CATCOLNAME . '</strong></td>';
318
            echo "<td class='bg3' align='left'><strong>" . _AM_PUBLISHER_SUBDESCRIPT . '</strong></td>';
319
            echo "<td width='60' class='bg3' align='right'><strong>" . _AM_PUBLISHER_ACTION . '</strong></td>';
320
            echo '</tr>';
321
            if ($totalsubs > 0) {
322
                foreach ($subcatsObj as $subcat) {
323
                    $modify = "<a href='category.php?op=mod&amp;categoryid="
324
                              . $subcat->categoryid()
325
                              . "'><img src='"
326
                              . XOOPS_URL
327
                              . '/modules/'
328
                              . $publisher->getModule()->dirname()
0 ignored issues
show
Bug introduced by
The method dirname 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...
329
                              . "/assets/images/links/edit.gif' title='"
330
                              . _AM_PUBLISHER_MODIFY
331
                              . "' alt='"
332
                              . _AM_PUBLISHER_MODIFY
333
                              . "' /></a>";
334
                    $delete = "<a href='category.php?op=del&amp;categoryid="
335
                              . $subcat->categoryid()
336
                              . "'><img src='"
337
                              . XOOPS_URL
338
                              . '/modules/'
339
                              . $publisher->getModule()->dirname()
0 ignored issues
show
Bug introduced by
The method dirname 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...
340
                              . "/assets/images/links/delete.png' title='"
341
                              . _AM_PUBLISHER_DELETE
342
                              . "' alt='"
343
                              . _AM_PUBLISHER_DELETE
344
                              . "' /></a>";
345
                    echo '<tr>';
346
                    echo "<td class='head' align='left'>" . $subcat->categoryid() . '</td>';
347
                    echo "<td class='even' align='left'><a href='"
348
                         . XOOPS_URL
349
                         . '/modules/'
350
                         . $publisher->getModule()->dirname()
0 ignored issues
show
Bug introduced by
The method dirname 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...
351
                         . '/category.php?categoryid='
352
                         . $subcat->categoryid()
353
                         . '&amp;parentid='
354
                         . $subcat->parentid()
355
                         . "'>"
356
                         . $subcat->name()
357
                         . '</a></td>';
358
                    echo "<td class='even' align='left'>" . $subcat->description() . '</td>';
359
                    echo "<td class='even' align='right'> {$modify} {$delete} </td>";
360
                    echo '</tr>';
361
                }
362
                //                unset($subcat);
0 ignored issues
show
Unused Code Comprehensibility introduced by
84% 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...
363
            } else {
364
                echo '<tr>';
365
                echo "<td class='head' align='center' colspan= '7'>" . _AM_PUBLISHER_NOSUBCAT . '</td>';
366
                echo '</tr>';
367
            }
368
            echo "</table>\n";
369
            echo "<br>\n";
370
            static::closeCollapsableBar('subcatstable', 'subcatsicon');
371
372
            static::openCollapsableBar('bottomtable', 'bottomtableicon', _AM_PUBLISHER_CAT_ITEMS, _AM_PUBLISHER_CAT_ITEMS_DSC);
373
            $startitem = Request::getInt('startitem');
374
            // Get the total number of published ITEMS
375
            $totalitems = $publisher->getHandler('item')->getItemsCount($selCat, array(PublisherConstants::PUBLISHER_STATUS_PUBLISHED));
376
            // creating the items objects that are published
377
            $itemsObj         = $publisher->getHandler('item')->getAllPublished($publisher->getConfig('idxcat_perpage'), $startitem, $selCat);
378
            $totalitemsOnPage = count($itemsObj);
379
            $allcats          = $publisher->getHandler('category')->getObjects(null, true);
380
            echo "<table width='100%' cellspacing=1 cellpadding=3 border=0 class = outer>";
381
            echo '<tr>';
382
            echo "<td width='40' class='bg3' align='center'><strong>" . _AM_PUBLISHER_ITEMID . '</strong></td>';
383
            echo "<td width='20%' class='bg3' align='left'><strong>" . _AM_PUBLISHER_ITEMCOLNAME . '</strong></td>';
384
            echo "<td class='bg3' align='left'><strong>" . _AM_PUBLISHER_ITEMDESC . '</strong></td>';
385
            echo "<td width='90' class='bg3' align='center'><strong>" . _AM_PUBLISHER_CREATED . '</strong></td>';
386
            echo "<td width='60' class='bg3' align='center'><strong>" . _AM_PUBLISHER_ACTION . '</strong></td>';
387
            echo '</tr>';
388
            if ($totalitems > 0) {
389
                for ($i = 0; $i < $totalitemsOnPage; ++$i) {
390
                    $categoryObj = $allcats[$itemsObj[$i]->categoryid()];
391
                    $modify      = "<a href='item.php?op=mod&amp;itemid="
392
                                   . $itemsObj[$i]->itemid()
393
                                   . "'><img src='"
394
                                   . XOOPS_URL
395
                                   . '/modules/'
396
                                   . $publisher->getModule()->dirname()
0 ignored issues
show
Bug introduced by
The method dirname 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...
397
                                   . "/assets/images/links/edit.gif' title='"
398
                                   . _AM_PUBLISHER_EDITITEM
399
                                   . "' alt='"
400
                                   . _AM_PUBLISHER_EDITITEM
401
                                   . "' /></a>";
402
                    $delete      = "<a href='item.php?op=del&amp;itemid="
403
                                   . $itemsObj[$i]->itemid()
404
                                   . "'><img src='"
405
                                   . XOOPS_URL
406
                                   . '/modules/'
407
                                   . $publisher->getModule()->dirname()
0 ignored issues
show
Bug introduced by
The method dirname 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...
408
                                   . "/assets/images/links/delete.png' title='"
409
                                   . _AM_PUBLISHER_DELETEITEM
410
                                   . "' alt='"
411
                                   . _AM_PUBLISHER_DELETEITEM
412
                                   . "'/></a>";
413
                    echo '<tr>';
414
                    echo "<td class='head' align='center'>" . $itemsObj[$i]->itemid() . '</td>';
415
                    echo "<td class='even' align='left'>" . $categoryObj->name() . '</td>';
416
                    echo "<td class='even' align='left'>" . $itemsObj[$i]->getitemLink() . '</td>';
417
                    echo "<td class='even' align='center'>" . $itemsObj[$i]->getDatesub('s') . '</td>';
418
                    echo "<td class='even' align='center'> $modify $delete </td>";
419
                    echo '</tr>';
420
                }
421
            } else {
422
                $itemid = -1;
0 ignored issues
show
Unused Code introduced by
$itemid 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...
423
                echo '<tr>';
424
                echo "<td class='head' align='center' colspan= '7'>" . _AM_PUBLISHER_NOITEMS . '</td>';
425
                echo '</tr>';
426
            }
427
            echo "</table>\n";
428
            echo "<br>\n";
429
            $parentid         = Request::getInt('parentid', 0, 'GET');
430
            $pagenavExtraArgs = "op=mod&categoryid=$selCat&parentid=$parentid";
431
            xoops_load('XoopsPageNav');
432
            $pagenav = new XoopsPageNav($totalitems, $publisher->getConfig('idxcat_perpage'), $startitem, 'startitem', $pagenavExtraArgs);
433
            echo '<div style="text-align:right;">' . $pagenav->renderNav() . '</div>';
434
            echo "<input type='button' name='button' onclick=\"location='item.php?op=mod&categoryid=" . $selCat . "'\" value='" . _AM_PUBLISHER_CREATEITEM . "'>&nbsp;&nbsp;";
435
            echo '</div>';
436
        }
437
        //end of fx2024 code
438
    }
439
440
441
    //======================== FUNCTIONS =================================
442
443
    /**
444
     * Includes scripts in HTML header
445
     *
446
     * @return void
447
     */
448
    public static function cpHeader()
449
    {
450
        xoops_cp_header();
451
452
        //cannot use xoTheme, some conflit with admin gui
453
        echo '<link type="text/css" href="' . XOOPS_URL . '/modules/system/css/ui/' . xoops_getModuleOption('jquery_theme', 'system') . '/ui.all.css" rel="stylesheet" />
454
    <link type="text/css" href="' . PUBLISHER_URL . '/assets/css/publisher.css" rel="stylesheet" />
455
    <script type="text/javascript" src="' . PUBLISHER_URL . '/assets/js/funcs.js"></script>
456
    <script type="text/javascript" src="' . PUBLISHER_URL . '/assets/js/cookies.js"></script>
457
    <script type="text/javascript" src="' . XOOPS_URL . '/browse.php?Frameworks/jquery/jquery.js"></script>
458
    <!-- <script type="text/javascript" src="' . XOOPS_URL . '/browse.php?Frameworks/jquery/jquery-migrate-1.2.1.js"></script> -->
459
    <script type="text/javascript" src="' . XOOPS_URL . '/browse.php?Frameworks/jquery/plugins/jquery.ui.js"></script>
460
    <script type="text/javascript" src="' . PUBLISHER_URL . '/assets/js/ajaxupload.3.9.js"></script>
461
    <script type="text/javascript" src="' . PUBLISHER_URL . '/assets/js/publisher.js"></script>
462
    ';
463
    }
464
465
    /**
466
     * Default sorting for a given order
467
     *
468
     * @param  string $sort
469
     * @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...
470
     */
471
    public static function getOrderBy($sort)
472
    {
473
        if ($sort === 'datesub') {
474
            return 'DESC';
475
        } elseif ($sort === 'counter') {
476
            return 'DESC';
477
        } elseif ($sort === 'weight') {
478
            return 'ASC';
479
        } elseif ($sort === 'votes') {
480
            return 'DESC';
481
        } elseif ($sort === 'rating') {
482
            return 'DESC';
483
        } elseif ($sort === 'comments') {
484
            return 'DESC';
485
        }
486
487
        return null;
488
    }
489
490
    /**
491
     * @credits Thanks to Mithandir
492
     * @param  string $str
493
     * @param  int    $start
494
     * @param  int    $length
495
     * @param  string $trimMarker
496
     * @return string
497
     */
498
    public static function substr($str, $start, $length, $trimMarker = '...')
499
    {
500
        // if the string is empty, let's get out ;-)
501
        if ($str == '') {
502
            return $str;
503
        }
504
505
        // reverse a string that is shortened with '' as trimmarker
506
        $reversedString = strrev(xoops_substr($str, $start, $length, ''));
507
508
        // find first space in reversed string
509
        $positionOfSpace = strpos($reversedString, ' ', 0);
510
511
        // truncate the original string to a length of $length
512
        // minus the position of the last space
513
        // plus the length of the $trimMarker
514
        $truncatedString = xoops_substr($str, $start, $length - $positionOfSpace + strlen($trimMarker), $trimMarker);
515
516
        return $truncatedString;
517
    }
518
519
    /**
520
     * @param  string $document
521
     * @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...
522
     */
523 View Code Duplication
    public static function html2text($document)
0 ignored issues
show
Duplication introduced by
This method 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...
524
    {
525
        // PHP Manual:: function preg_replace
526
        // $document should contain an HTML document.
527
        // This will remove HTML tags, javascript sections
528
        // and white space. It will also convert some
529
        // common HTML entities to their text equivalent.
530
        // Credits : newbb2
531
        $search = array(
532
            "'<script[^>]*?>.*?</script>'si", // Strip out javascript
533
            "'<img.*?/>'si", // Strip out img tags
534
            "'<[\/\!]*?[^<>]*?>'si", // Strip out HTML tags
535
            "'([\r\n])[\s]+'", // Strip out white space
536
            "'&(quot|#34);'i", // Replace HTML entities
537
            "'&(amp|#38);'i",
538
            "'&(lt|#60);'i",
539
            "'&(gt|#62);'i",
540
            "'&(nbsp|#160);'i",
541
            "'&(iexcl|#161);'i",
542
            "'&(cent|#162);'i",
543
            "'&(pound|#163);'i",
544
            "'&(copy|#169);'i"
545
        ); // evaluate as php
546
547
        $replace = array(
548
            '',
549
            '',
550
            '',
551
            "\\1",
552
            "\"",
553
            '&',
554
            '<',
555
            '>',
556
            ' ',
557
            chr(161),
558
            chr(162),
559
            chr(163),
560
            chr(169)
561
        );
562
563
        $text = preg_replace($search, $replace, $document);
564
565
        preg_replace_callback('/&#(\d+);/', function ($matches) {
566
            return chr($matches[1]);
567
        }, $document);
568
569
        return $text;
570
        //<?php
571
    }
572
573
    /**
574
     * @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...
575
     */
576
    public static function getAllowedImagesTypes()
577
    {
578
        return array('jpg/jpeg', 'image/bmp', 'image/gif', 'image/jpeg', 'image/jpg', 'image/x-png', 'image/png', 'image/pjpeg');
579
    }
580
581
    /**
582
     * @param  bool $withLink
583
     * @return string
584
     */
585
    public static function moduleHome($withLink = true)
586
    {
587
        $publisher = PublisherPublisher::getInstance();
588
589
        if (!$publisher->getConfig('format_breadcrumb_modname')) {
590
            return '';
591
        }
592
593
        if (!$withLink) {
594
            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...
595
        } else {
596
            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...
597
        }
598
    }
599
600
    /**
601
     * Copy a file, or a folder and its contents
602
     *
603
     * @author      Aidan Lister <[email protected]>
604
     * @version     1.0.0
605
     * @param  string $source The source
606
     * @param  string $dest   The destination
607
     * @return bool   Returns true on success, false on failure
608
     */
609
    public static function copyr($source, $dest)
610
    {
611
        // Simple copy for a file
612
        if (is_file($source)) {
613
            return copy($source, $dest);
614
        }
615
616
        // Make destination directory
617
        if (!is_dir($dest)) {
618
            mkdir($dest);
619
        }
620
621
        // Loop through the folder
622
        $dir = dir($source);
623
        while (false !== $entry = $dir->read()) {
624
            // Skip pointers
625
            if ($entry === '.' || $entry === '..') {
626
                continue;
627
            }
628
629
            // Deep copy directories
630
            if (($dest !== "$source/$entry") && is_dir("$source/$entry")) {
631
                static::copyr("$source/$entry", "$dest/$entry");
632
            } else {
633
                copy("$source/$entry", "$dest/$entry");
634
            }
635
        }
636
637
        // Clean up
638
        $dir->close();
639
640
        return true;
641
    }
642
643
    /**
644
     * .* @credits Thanks to the NewBB2 Development Team
645
     * @param  string $item
646
     * @param  bool   $getStatus
647
     * @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...
648
     */
649
    public static function &getPathStatus($item, $getStatus = false)
650
    {
651
        $path = '';
652
        if ('root' !== $item) {
653
            $path = $item;
654
        }
655
656
        $thePath = static::getUploadDir(true, $path);
657
658
        if (empty($thePath)) {
659
            return false;
660
        }
661
        if (is_writable($thePath)) {
662
            $pathCheckResult = 1;
663
            $pathStatus      = _AM_PUBLISHER_AVAILABLE;
664
        } elseif (!@is_dir($thePath)) {
665
            $pathCheckResult = -1;
666
            $pathStatus      = _AM_PUBLISHER_NOTAVAILABLE . " <a href='" . PUBLISHER_ADMIN_URL . "/index.php?op=createdir&amp;path={$item}'>" . _AM_PUBLISHER_CREATETHEDIR . '</a>';
667
        } else {
668
            $pathCheckResult = -2;
669
            $pathStatus      = _AM_PUBLISHER_NOTWRITABLE . " <a href='" . PUBLISHER_ADMIN_URL . "/index.php?op=setperm&amp;path={$item}'>" . _AM_PUBLISHER_SETMPERM . '</a>';
670
        }
671
        if (!$getStatus) {
672
            return $pathStatus;
673
        } else {
674
            return $pathCheckResult;
675
        }
676
    }
677
678
    /**
679
     * @credits Thanks to the NewBB2 Development Team
680
     * @param  string $target
681
     * @return bool
682
     */
683
    public static function mkdir($target)
684
    {
685
        // http://www.php.net/manual/en/function.mkdir.php
686
        // saint at corenova.com
687
        // bart at cdasites dot com
688
        if (empty($target) || is_dir($target)) {
689
            return true; // best case check first
690
        }
691
692
        if (file_exists($target) && !is_dir($target)) {
693
            return false;
694
        }
695
696
        if (static::mkdir(substr($target, 0, strrpos($target, '/')))) {
697
            if (!file_exists($target)) {
698
                $res = mkdir($target, 0777); // crawl back up & create dir tree
699
                static::chmod($target);
700
701
                return $res;
702
            }
703
        }
704
        $res = is_dir($target);
705
706
        return $res;
707
    }
708
709
    /**
710
     * @credits Thanks to the NewBB2 Development Team
711
     * @param  string $target
712
     * @param  int    $mode
713
     * @return bool
714
     */
715
    public static function chmod($target, $mode = 0777)
716
    {
717
        return @chmod($target, $mode);
718
    }
719
720
    /**
721
     * @param  bool   $hasPath
722
     * @param  string $item
723
     * @return string
724
     */
725
    public static function getUploadDir($hasPath = true, $item = '')
726
    {
727
        if ('' !== $item) {
728
            if ($item === 'root') {
729
                $item = '';
730
            } else {
731
                $item .= '/';
732
            }
733
        }
734
735
        if ($hasPath) {
736
            return PUBLISHER_UPLOAD_PATH . '/' . $item;
737
        } else {
738
            return PUBLISHER_UPLOAD_URL . '/' . $item;
739
        }
740
    }
741
742
    /**
743
     * @param  string $item
744
     * @param  bool   $hasPath
745
     * @return string
746
     */
747
    public static function getImageDir($item = '', $hasPath = true)
748
    {
749
        if ($item) {
750
            $item = "images/{$item}";
751
        } else {
752
            $item = 'images';
753
        }
754
755
        return static::getUploadDir($hasPath, $item);
756
    }
757
758
    /**
759
     * @param  array $errors
760
     * @return string
761
     */
762
    public static function formatErrors($errors = array())
763
    {
764
        $ret = '';
765
        foreach ($errors as $key => $value) {
766
            $ret .= '<br> - ' . $value;
767
        }
768
769
        return $ret;
770
    }
771
772
    /**
773
     * Checks if a user is admin of Publisher
774
     *
775
     * @return boolean
776
     */
777
    public static function userIsAdmin()
0 ignored issues
show
Coding Style introduced by
userIsAdmin 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...
778
    {
779
        $publisher = PublisherPublisher::getInstance();
780
781
        static $publisherIsAdmin;
782
783
        if (isset($publisherIsAdmin)) {
784
            return $publisherIsAdmin;
785
        }
786
787
        if (!$GLOBALS['xoopsUser']) {
788
            $publisherIsAdmin = false;
789
        } else {
790
            $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...
791
        }
792
793
        return $publisherIsAdmin;
794
    }
795
796
    /**
797
     * Check is current user is author of a given article
798
     *
799
     * @param  XoopsObject $itemObj
800
     * @return bool
801
     */
802
    public static function userIsAuthor($itemObj)
0 ignored issues
show
Coding Style introduced by
userIsAuthor 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...
803
    {
804
        return (is_object($GLOBALS['xoopsUser']) && is_object($itemObj) && ($GLOBALS['xoopsUser']->uid() == $itemObj->uid()));
805
    }
806
807
    /**
808
     * Check is current user is moderator of a given article
809
     *
810
     * @param  XoopsObject $itemObj
811
     * @return bool
812
     */
813
    public static function userIsModerator($itemObj)
814
    {
815
        $publisher         = PublisherPublisher::getInstance();
816
        $categoriesGranted = $publisher->getHandler('permission')->getGrantedItems('category_moderation');
817
818
        return (is_object($itemObj) && in_array($itemObj->categoryid(), $categoriesGranted));
819
    }
820
821
    /**
822
     * Saves permissions for the selected category
823
     *
824
     * @param  array   $groups     : group with granted permission
825
     * @param  integer $categoryId : categoryid on which we are setting permissions
826
     * @param  string  $permName   : name of the permission
827
     * @return boolean : TRUE if the no errors occured
828
     */
829
    public static function saveCategoryPermissions($groups, $categoryId, $permName)
830
    {
831
        $publisher = PublisherPublisher::getInstance();
832
833
        $result = true;
834
835
        $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...
836
        $gpermHandler = xoops_getHandler('groupperm');
837
        // First, if the permissions are already there, delete them
838
        $gpermHandler->deleteByModule($moduleId, $permName, $categoryId);
839
840
        // Save the new permissions
841
        if (count($groups) > 0) {
842
            foreach ($groups as $groupId) {
843
                $gpermHandler->addRight($permName, $categoryId, $groupId, $moduleId);
844
            }
845
        }
846
847
        return $result;
848
    }
849
850
    /**
851
     * @param  string $tablename
852
     * @param  string $iconname
853
     * @param  string $tabletitle
854
     * @param  string $tabledsc
855
     * @param  bool   $open
856
     * @return void
857
     */
858
    public static function openCollapsableBar($tablename = '', $iconname = '', $tabletitle = '', $tabledsc = '', $open = true)
859
    {
860
        $image   = 'open12.gif';
861
        $display = 'none';
862
        if ($open) {
863
            $image   = 'close12.gif';
864
            $display = 'block';
865
        }
866
867
        echo "<h3 style=\"color: #2F5376; font-weight: bold; font-size: 14px; margin: 6px 0 0 0; \"><a href='javascript:;' onclick=\"toggle('" . $tablename . "'); toggleIcon('" . $iconname . "')\">";
868
        echo "<img id='" . $iconname . "' src='" . PUBLISHER_URL . '/assets/images/links/' . $image . "' alt='' /></a>&nbsp;" . $tabletitle . '</h3>';
869
        echo "<div id='" . $tablename . "' style='display: " . $display . ";'>";
870
        if ($tabledsc != '') {
871
            echo "<span style=\"color: #567; margin: 3px 0 12px 0; font-size: small; display: block; \">" . $tabledsc . '</span>';
872
        }
873
    }
874
875
    /**
876
     * @param  string $name
877
     * @param  string $icon
878
     * @return void
879
     */
880
    public static function closeCollapsableBar($name, $icon)
881
    {
882
        echo '</div>';
883
884
        $urls = static::getCurrentUrls();
885
        $path = $urls['phpself'];
886
887
        $cookieName = $path . '_publisher_collaps_' . $name;
888
        $cookieName = str_replace('.', '_', $cookieName);
889
        $cookie     = static::getCookieVar($cookieName, '');
890
891
        if ($cookie === 'none') {
892
            echo '
893
        <script type="text/javascript"><!--
894
        toggle("' . $name . '"); toggleIcon("' . $icon . '");
895
        //-->
896
        </script>
897
        ';
898
        }
899
    }
900
901
    /**
902
     * @param  string $name
903
     * @param  string $value
904
     * @param  int    $time
905
     * @return void
906
     */
907
    public static function setCookieVar($name, $value, $time = 0)
908
    {
909
        if ($time == 0) {
910
            $time = time() + 3600 * 24 * 365;
911
        }
912
        setcookie($name, $value, $time, '/');
913
    }
914
915
    /**
916
     * @param  string $name
917
     * @param  string $default
918
     * @return string
919
     */
920
    public static function getCookieVar($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...
921
    {
922
        //    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...
923
        //        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...
924
        //    } 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...
925
        //        return $default;
926
        //    }
927
        return Request::getString('name', $default, 'COOKIE');
928
    }
929
930
    /**
931
     * @return array
932
     */
933
    public static function getCurrentUrls()
934
    {
935
        $http = strpos(XOOPS_URL, 'https://') === false ? 'http://' : 'https://';
936
        //    $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...
937
        //    $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...
938
        //    $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...
939
        $phpself     = Request::getString('PHP_SELF', '', 'SERVER');
940
        $httphost    = Request::getString('HTTP_HOST', '', 'SERVER');
941
        $querystring = Request::getString('QUERY_STRING', '', 'SERVER');
942
943
        if ($querystring != '') {
944
            $querystring = '?' . $querystring;
945
        }
946
947
        $currenturl = $http . $httphost . $phpself . $querystring;
948
949
        $urls                = array();
950
        $urls['http']        = $http;
951
        $urls['httphost']    = $httphost;
952
        $urls['phpself']     = $phpself;
953
        $urls['querystring'] = $querystring;
954
        $urls['full']        = $currenturl;
955
956
        return $urls;
957
    }
958
959
    /**
960
     * @return string
961
     */
962
    public static function getCurrentPage()
963
    {
964
        $urls = static::getCurrentUrls();
965
966
        return $urls['full'];
967
    }
968
969
    /**
970
     * @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...
971
     * @param  int                    $selectedid
972
     * @param  int                    $level
973
     * @param  string                 $ret
974
     * @return string
975
     */
976
    public static function addCategoryOption(PublisherCategory $categoryObj, $selectedid = 0, $level = 0, $ret = '')
977
    {
978
        $publisher = PublisherPublisher::getInstance();
979
980
        $spaces = '';
981
        for ($j = 0; $j < $level; ++$j) {
982
            $spaces .= '--';
983
        }
984
985
        $ret .= "<option value='" . $categoryObj->categoryid() . "'";
986
        if (is_array($selectedid) && in_array($categoryObj->categoryid(), $selectedid)) {
987
            $ret .= ' selected';
988
        } elseif ($categoryObj->categoryid() == $selectedid) {
989
            $ret .= ' selected';
990
        }
991
        $ret .= '>' . $spaces . $categoryObj->name() . "</option>\n";
992
993
        $subCategoriesObj = $publisher->getHandler('category')->getCategories(0, 0, $categoryObj->categoryid());
994
        if (count($subCategoriesObj) > 0) {
995
            ++$level;
996
            foreach ($subCategoriesObj as $catID => $subCategoryObj) {
997
                $ret .= static::addCategoryOption($subCategoryObj, $selectedid, $level);
0 ignored issues
show
Bug introduced by
It seems like $selectedid can also be of type array; however, PublisherUtility::addCategoryOption() 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...
998
            }
999
        }
1000
1001
        return $ret;
1002
    }
1003
1004
    /**
1005
     * @param  int    $selectedid
1006
     * @param  int    $parentcategory
1007
     * @param  bool   $allCatOption
1008
     * @param  string $selectname
1009
     * @return string
1010
     */
1011
    public static function createCategorySelect($selectedid = 0, $parentcategory = 0, $allCatOption = true, $selectname = 'options[0]')
1012
    {
1013
        $publisher = PublisherPublisher::getInstance();
1014
1015
        $selectedid = explode(',', $selectedid);
1016
1017
        $ret = "<select name='" . $selectname . "[]' multiple='multiple' size='10'>";
1018
        if ($allCatOption) {
1019
            $ret .= "<option value='0'";
1020
            if (in_array(0, $selectedid)) {
1021
                $ret .= ' selected';
1022
            }
1023
            $ret .= '>' . _MB_PUBLISHER_ALLCAT . '</option>';
1024
        }
1025
1026
        // Creating category objects
1027
        $categoriesObj = $publisher->getHandler('category')->getCategories(0, 0, $parentcategory);
1028
1029 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...
1030
            foreach ($categoriesObj as $catID => $categoryObj) {
1031
                $ret .= static::addCategoryOption($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...
1032
            }
1033
        }
1034
        $ret .= '</select>';
1035
1036
        return $ret;
1037
    }
1038
1039
    /**
1040
     * @param  int  $selectedid
1041
     * @param  int  $parentcategory
1042
     * @param  bool $allCatOption
1043
     * @return string
1044
     */
1045
    public static function createCategoryOptions($selectedid = 0, $parentcategory = 0, $allCatOption = true)
1046
    {
1047
        $publisher = PublisherPublisher::getInstance();
1048
1049
        $ret = '';
1050
        if ($allCatOption) {
1051
            $ret .= "<option value='0'";
1052
            $ret .= '>' . _MB_PUBLISHER_ALLCAT . "</option>\n";
1053
        }
1054
1055
        // Creating category objects
1056
        $categoriesObj = $publisher->getHandler('category')->getCategories(0, 0, $parentcategory);
1057 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...
1058
            foreach ($categoriesObj as $catID => $categoryObj) {
1059
                $ret .= static::addCategoryOption($categoryObj, $selectedid);
1060
            }
1061
        }
1062
1063
        return $ret;
1064
    }
1065
1066
    /**
1067
     * @param  array  $errArray
1068
     * @param  string $reseturl
1069
     * @return void
1070
     */
1071
    public static function renderErrors(&$errArray, $reseturl = '')
1072
    {
1073
        if (is_array($errArray) && count($errArray) > 0) {
1074
            echo '<div id="readOnly" class="errorMsg" style="border:1px solid #D24D00; background:#FEFECC url('
1075
                 . PUBLISHER_URL
1076
                 . '/assets/images/important-32.png) no-repeat 7px 50%;color:#333;padding-left:45px;">';
1077
1078
            echo '<h4 style="text-align:left;margin:0; padding-top:0;">' . _AM_PUBLISHER_MSG_SUBMISSION_ERR;
1079
1080
            if ($reseturl) {
1081
                echo ' <a href="' . $reseturl . '">[' . _AM_PUBLISHER_TEXT_SESSION_RESET . ']</a>';
1082
            }
1083
1084
            echo '</h4><ul>';
1085
1086
            foreach ($errArray as $key => $error) {
1087
                if (is_array($error)) {
1088
                    foreach ($error as $err) {
1089
                        echo '<li><a href="#' . $key . '" onclick="var e = xoopsGetElementById(\'' . $key . '\'); e.focus();">' . htmlspecialchars($err) . '</a></li>';
1090
                    }
1091
                } else {
1092
                    echo '<li><a href="#' . $key . '" onclick="var e = xoopsGetElementById(\'' . $key . '\'); e.focus();">' . htmlspecialchars($error) . '</a></li>';
1093
                }
1094
            }
1095
            echo '</ul></div><br>';
1096
        }
1097
    }
1098
1099
    /**
1100
     * Generate publisher URL
1101
     *
1102
     * @param  string $page
1103
     * @param  array  $vars
1104
     * @param  bool   $encodeAmp
1105
     * @return string
1106
     *
1107
     * @credit : xHelp module, developped by 3Dev
1108
     */
1109
    public static function makeUri($page, $vars = array(), $encodeAmp = true)
1110
    {
1111
        $joinStr = '';
1112
1113
        $amp = ($encodeAmp ? '&amp;' : '&');
1114
1115
        if (!count($vars)) {
1116
            return $page;
1117
        }
1118
1119
        $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...
1120
        foreach ($vars as $key => $value) {
1121
            $qs      .= $joinStr . $key . '=' . $value;
1122
            $joinStr = $amp;
1123
        }
1124
1125
        return $page . '?' . $qs;
1126
    }
1127
1128
    /**
1129
     * @param  string $subject
1130
     * @return string
1131
     */
1132
    public static function tellAFriend($subject = '')
1133
    {
1134
        if (false !== strpos($subject, '%')) {
1135
            $subject = rawurldecode($subject);
1136
        }
1137
1138
        $targetUri = XOOPS_URL . Request::getString('REQUEST_URI', '', 'SERVER');
1139
1140
        return XOOPS_URL . '/modules/tellafriend/index.php?target_uri=' . rawurlencode($targetUri) . '&amp;subject=' . rawurlencode($subject);
1141
    }
1142
1143
    /**
1144
     * @param  bool        $another
1145
     * @param  bool        $withRedirect
1146
     * @param              $itemObj
1147
     * @return bool|string
1148
     */
1149
    public static function uploadFile($another = false, $withRedirect = true, &$itemObj)
0 ignored issues
show
Coding Style introduced by
uploadFile 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
uploadFile 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...
1150
    {
1151
        include_once PUBLISHER_ROOT_PATH . '/class/uploader.php';
1152
1153
        //    global $publisherIsAdmin;
1154
        $publisher = PublisherPublisher::getInstance();
1155
1156
        $itemId  = Request::getInt('itemid', 0, 'POST');
1157
        $uid     = is_object($GLOBALS['xoopsUser']) ? $GLOBALS['xoopsUser']->uid() : 0;
1158
        $session = PublisherSession::getInstance();
1159
        $session->set('publisher_file_filename', Request::getString('item_file_name', '', 'POST'));
1160
        $session->set('publisher_file_description', Request::getString('item_file_description', '', 'POST'));
1161
        $session->set('publisher_file_status', Request::getInt('item_file_status', 1, 'POST'));
1162
        $session->set('publisher_file_uid', $uid);
1163
        $session->set('publisher_file_itemid', $itemId);
1164
1165
        if (!is_object($itemObj)) {
1166
            $itemObj = $publisher->getHandler('item')->get($itemId);
1167
        }
1168
1169
        $fileObj = $publisher->getHandler('file')->create();
1170
        $fileObj->setVar('name', Request::getString('item_file_name', '', 'POST'));
1171
        $fileObj->setVar('description', Request::getString('item_file_description', '', 'POST'));
1172
        $fileObj->setVar('status', Request::getInt('item_file_status', 1, 'POST'));
1173
        $fileObj->setVar('uid', $uid);
1174
        $fileObj->setVar('itemid', $itemObj->getVar('itemid'));
1175
        $fileObj->setVar('datesub', time());
1176
1177
        // Get available mimetypes for file uploading
1178
        $allowedMimetypes = $publisher->getHandler('mimetype')->getArrayByType();
1179
        // TODO : display the available mimetypes to the user
1180
        $errors = array();
1181
        if ($publisher->getConfig('perm_upload') && is_uploaded_file($_FILES['item_upload_file']['tmp_name'])) {
1182
            if (!$ret = $fileObj->checkUpload('item_upload_file', $allowedMimetypes, $errors)) {
1183
                $errorstxt = implode('<br>', $errors);
1184
1185
                $message = sprintf(_CO_PUBLISHER_MESSAGE_FILE_ERROR, $errorstxt);
1186
                if ($withRedirect) {
1187
                    redirect_header('file.php?op=mod&itemid=' . $itemId, 5, $message);
1188
                } else {
1189
                    return $message;
1190
                }
1191
            }
1192
        }
1193
1194
        // Storing the file
1195
        if (!$fileObj->store($allowedMimetypes)) {
1196
            //        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...
1197
            //            redirect_header("file.php?op=mod&itemid=" . $fileObj->itemid(), 3, _CO_PUBLISHER_FILEUPLOAD_ERROR . static::formatErrors($fileObj->getErrors()));
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% 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...
1198
            //            exit;
1199
            //        }
1200
            try {
1201
                if ($withRedirect) {
1202
                    throw new Exception(_CO_PUBLISHER_FILEUPLOAD_ERROR . static::formatErrors($fileObj->getErrors()));
1203
                }
1204
            } catch (Exception $e) {
1205
                redirect_header('file.php?op=mod&itemid=' . $fileObj->itemid(), 3, _CO_PUBLISHER_FILEUPLOAD_ERROR . static::formatErrors($fileObj->getErrors()));
1206
            }
1207
            //    } 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...
1208
            //        return _CO_PUBLISHER_FILEUPLOAD_ERROR . static::formatErrors($fileObj->getErrors());
0 ignored issues
show
Unused Code Comprehensibility introduced by
56% 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...
1209
        }
1210
1211
        if ($withRedirect) {
1212
            $redirectPage = $another ? 'file.php' : 'item.php';
1213
            redirect_header($redirectPage . '?op=mod&itemid=' . $fileObj->itemid(), 2, _CO_PUBLISHER_FILEUPLOAD_SUCCESS);
1214
        } else {
1215
            return true;
1216
        }
1217
1218
        return null;
1219
    }
1220
1221
    /**
1222
     * @return string
1223
     */
1224
    public static function newFeatureTag()
1225
    {
1226
        $ret = '<span style="padding-right: 4px; font-weight: bold; color: red;">' . _CO_PUBLISHER_NEW_FEATURE . '</span>';
1227
1228
        return $ret;
1229
    }
1230
1231
    /**
1232
     * Smarty truncate_tagsafe modifier plugin
1233
     *
1234
     * Type:     modifier<br>
1235
     * Name:     truncate_tagsafe<br>
1236
     * Purpose:  Truncate a string to a certain length if necessary,
1237
     *           optionally splitting in the middle of a word, and
1238
     *           appending the $etc string or inserting $etc into the middle.
1239
     *           Makes sure no tags are left half-open or half-closed
1240
     *           (e.g. "Banana in a <a...")
1241
     * @author   Monte Ohrt <monte at ohrt dot com>, modified by Amos Robinson
1242
     *           <amos dot robinson at gmail dot com>
1243
     * @param string
1244
     * @param integer
1245
     * @param string
1246
     * @param boolean
1247
     * @param boolean
1248
     * @return string
1249
     */
1250
    public static function truncateTagSafe($string, $length = 80, $etc = '...', $breakWords = false)
1251
    {
1252
        if ($length == 0) {
1253
            return '';
1254
        }
1255
1256
        if (strlen($string) > $length) {
1257
            $length -= strlen($etc);
1258
            if (!$breakWords) {
1259
                $string = preg_replace('/\s+?(\S+)?$/', '', substr($string, 0, $length + 1));
1260
                $string = preg_replace('/<[^>]*$/', '', $string);
1261
                $string = static::closeTags($string);
1262
            }
1263
1264
            return $string . $etc;
1265
        } else {
1266
            return $string;
1267
        }
1268
    }
1269
1270
    /**
1271
     * @author   Monte Ohrt <monte at ohrt dot com>, modified by Amos Robinson
1272
     *           <amos dot robinson at gmail dot com>
1273
     * @param  string $string
1274
     * @return string
1275
     */
1276
    public static function closeTags($string)
1277
    {
1278
        // match opened tags
1279
        if (preg_match_all('/<([a-z\:\-]+)[^\/]>/', $string, $startTags)) {
1280
            $startTags = $startTags[1];
1281
            // match closed tags
1282
            if (preg_match_all('/<\/([a-z]+)>/', $string, $endTags)) {
1283
                $completeTags = array();
1284
                $endTags      = $endTags[1];
1285
1286
                foreach ($startTags as $key => $val) {
1287
                    $posb = array_search($val, $endTags);
1288
                    if (is_int($posb)) {
1289
                        unset($endTags[$posb]);
1290
                    } else {
1291
                        $completeTags[] = $val;
1292
                    }
1293
                }
1294
            } else {
1295
                $completeTags = $startTags;
1296
            }
1297
1298
            $completeTags = array_reverse($completeTags);
1299
            $elementCount = count($completeTags);
1300
            for ($i = 0; $i < $elementCount; ++$i) {
1301
                $string .= '</' . $completeTags[$i] . '>';
1302
            }
1303
        }
1304
1305
        return $string;
1306
    }
1307
1308
    /**
1309
     * @param  int $itemId
1310
     * @return string
1311
     */
1312
    public static function ratingBar($itemId)
0 ignored issues
show
Coding Style introduced by
ratingBar 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...
1313
    {
1314
        $publisher       = PublisherPublisher::getInstance();
1315
        $ratingUnitWidth = 30;
1316
        $units           = 5;
1317
1318
        $criteria   = new Criteria('itemid', $itemId);
1319
        $ratingObjs = $publisher->getHandler('rating')->getObjects($criteria);
1320
        unset($criteria);
1321
1322
        $uid           = is_object($GLOBALS['xoopsUser']) ? $GLOBALS['xoopsUser']->getVar('uid') : 0;
1323
        $count         = count($ratingObjs);
1324
        $currentRating = 0;
1325
        $voted         = false;
1326
        $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...
1327
        $rating1       = $rating2 = $ratingWidth = 0;
1328
1329 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...
1330
            $currentRating += $ratingObj->getVar('rate');
1331
            if ($ratingObj->getVar('ip') == $ip || ($uid > 0 && $uid == $ratingObj->getVar('uid'))) {
1332
                $voted = true;
1333
            }
1334
        }
1335
1336
        $tense = $count == 1 ? _MD_PUBLISHER_VOTE_VOTE : _MD_PUBLISHER_VOTE_VOTES; //plural form votes/vote
1337
1338
        // now draw the rating bar
1339
        if ($count != 0) {
1340
            $ratingWidth = number_format($currentRating / $count, 2) * $ratingUnitWidth;
1341
            $rating1     = number_format($currentRating / $count, 1);
1342
            $rating2     = number_format($currentRating / $count, 2);
1343
        }
1344
        $groups       = $GLOBALS['xoopsUser'] ? $GLOBALS['xoopsUser']->getGroups() : XOOPS_GROUP_ANONYMOUS;
1345
        $gpermHandler = $publisher->getHandler('groupperm');
1346
1347
        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...
1348
            $staticRater   = array();
1349
            $staticRater[] .= "\n" . '<div class="publisher_ratingblock">';
1350
            $staticRater[] .= '<div id="unit_long' . $itemId . '">';
1351
            $staticRater[] .= '<div id="unit_ul' . $itemId . '" class="publisher_unit-rating" style="width:' . $ratingUnitWidth * $units . 'px;">';
1352
            $staticRater[] .= '<div class="publisher_current-rating" style="width:' . $ratingWidth . 'px;">' . _MD_PUBLISHER_VOTE_RATING . ' ' . $rating2 . '/' . $units . '</div>';
1353
            $staticRater[] .= '</div>';
1354
            $staticRater[] .= '<div class="publisher_static">'
1355
                              . _MD_PUBLISHER_VOTE_RATING
1356
                              . ': <strong> '
1357
                              . $rating1
1358
                              . '</strong>/'
1359
                              . $units
1360
                              . ' ('
1361
                              . $count
1362
                              . ' '
1363
                              . $tense
1364
                              . ') <br><em>'
1365
                              . _MD_PUBLISHER_VOTE_DISABLE
1366
                              . '</em></div>';
1367
            $staticRater[] .= '</div>';
1368
            $staticRater[] .= '</div>' . "\n\n";
1369
1370
            return implode("\n", $staticRater);
1371
        } else {
1372
            $rater = '';
1373
            $rater .= '<div class="publisher_ratingblock">';
1374
            $rater .= '<div id="unit_long' . $itemId . '">';
1375
            $rater .= '<div id="unit_ul' . $itemId . '" class="publisher_unit-rating" style="width:' . $ratingUnitWidth * $units . 'px;">';
1376
            $rater .= '<div class="publisher_current-rating" style="width:' . $ratingWidth . 'px;">' . _MD_PUBLISHER_VOTE_RATING . ' ' . $rating2 . '/' . $units . '</div>';
1377
1378
            for ($ncount = 1; $ncount <= $units; ++$ncount) { // loop from 1 to the number of units
1379
                if (!$voted) { // if the user hasn't yet voted, draw the voting stars
1380
                    $rater .= '<div><a href="'
1381
                              . PUBLISHER_URL
1382
                              . '/rate.php?itemid='
1383
                              . $itemId
1384
                              . '&amp;rating='
1385
                              . $ncount
1386
                              . '" title="'
1387
                              . $ncount
1388
                              . ' '
1389
                              . _MD_PUBLISHER_VOTE_OUTOF
1390
                              . ' '
1391
                              . $units
1392
                              . '" class="publisher_r'
1393
                              . $ncount
1394
                              . '-unit rater" rel="nofollow">'
1395
                              . $ncount
1396
                              . '</a></div>';
1397
                }
1398
            }
1399
1400
            $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...
1401
            $rater  .= '  </div>';
1402
            $rater  .= '  <div';
1403
1404
            if ($voted) {
1405
                $rater .= ' class="publisher_voted"';
1406
            }
1407
1408
            $rater .= '>' . _MD_PUBLISHER_VOTE_RATING . ': <strong> ' . $rating1 . '</strong>/' . $units . ' (' . $count . ' ' . $tense . ')';
1409
            $rater .= '  </div>';
1410
            $rater .= '</div>';
1411
            $rater .= '</div>';
1412
1413
            return $rater;
1414
        }
1415
    }
1416
1417
    /**
1418
     * @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...
1419
     * @return array
1420
     */
1421
    public static function getEditors($allowedEditors = null)
1422
    {
1423
        $ret    = array();
1424
        $nohtml = false;
1425
        xoops_load('XoopsEditorHandler');
1426
        $editorHandler = XoopsEditorHandler::getInstance();
1427
        $editors       = $editorHandler->getList($nohtml);
1428
        foreach ($editors as $name => $title) {
1429
            $key = static::stringToInt($name);
1430
            if (is_array($allowedEditors)) {
1431
                //for submit page
1432
                if (in_array($key, $allowedEditors)) {
1433
                    $ret[] = $name;
1434
                }
1435
            } else {
1436
                //for admin permissions page
1437
                $ret[$key]['name']  = $name;
1438
                $ret[$key]['title'] = $title;
1439
            }
1440
        }
1441
1442
        return $ret;
1443
    }
1444
1445
    /**
1446
     * @param  string $string
1447
     * @param  int    $length
1448
     * @return int
1449
     */
1450
    public static function stringToInt($string = '', $length = 5)
1451
    {
1452
        $final  = '';
1453
        $string = substr(md5($string), $length);
1454
        for ($i = 0; $i < $length; ++$i) {
1455
            $final .= (int)$string[$i];
1456
        }
1457
1458
        return (int)$final;
1459
    }
1460
1461
    /**
1462
     * @param  string $item
1463
     * @return string
1464
     */
1465
    public static function convertCharset($item)
1466
    {
1467
        if (_CHARSET !== 'windows-1256') {
1468
            return utf8_encode($item);
1469
        }
1470
1471
        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 150
  1. Read from $_FILES, and XoopsMediaUploader::$mediaSize is assigned
    in class/uploader.php on line 150
  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 180
  3. $error is passed through trim(), and XoopsMediaUploader::$errors is assigned
    in class/uploader.php on line 452
  4. Tainted property XoopsMediaUploader::$errors is read
    in class/uploader.php on line 465
  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 69
  6. $error is passed to PublisherUtility::convertCharset()
    in include/ajax_upload.php on line 100
  2. Path: Read from $_FILES, and XoopsMediaUploader::$mediaType is assigned in class/uploader.php on line 149
  1. Read from $_FILES, and XoopsMediaUploader::$mediaType is assigned
    in class/uploader.php on line 149
  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 194
  3. $error is passed through trim(), and XoopsMediaUploader::$errors is assigned
    in class/uploader.php on line 452
  4. Tainted property XoopsMediaUploader::$errors is read
    in class/uploader.php on line 465
  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 69
  6. $error is passed to PublisherUtility::convertCharset()
    in include/ajax_upload.php on line 100
  3. Path: Read from $_FILES, and XoopsMediaUploader::$mediaName is assigned in class/uploader.php on line 148
  1. Read from $_FILES, and XoopsMediaUploader::$mediaName is assigned
    in class/uploader.php on line 148
  2. Tainted property XoopsMediaUploader::$mediaName is read, and 'Failed uploading file: ' . $this->mediaName is passed to XoopsMediaUploader::setErrors()
    in class/uploader.php on line 343
  3. $error is passed through trim(), and XoopsMediaUploader::$errors is assigned
    in class/uploader.php on line 452
  4. Tainted property XoopsMediaUploader::$errors is read
    in class/uploader.php on line 465
  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 69
  6. $error is passed to PublisherUtility::convertCharset()
    in include/ajax_upload.php on line 100

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...
1472
            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...
1473
                $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...
1474
            }
1475
            $serialize = serialize($unserialize);
1476
1477
            return $serialize;
1478
        } else {
1479
            return @iconv('windows-1256', 'UTF-8', $item);
1480
        }
1481
    }
1482
1483
    /**
1484
     *
1485
     * Verifies XOOPS version meets minimum requirements for this module
1486
     * @static
1487
     * @param XoopsModule $module
1488
     *
1489
     * @return bool true if meets requirements, false if not
1490
     */
1491
    public static function checkVerXoops(XoopsModule $module)
1492
    {
1493
        xoops_loadLanguage('admin', $module->dirname());
1494
        //check for minimum XOOPS version
1495
        $currentVer  = substr(XOOPS_VERSION, 6); // get the numeric part of string
1496
        $currArray   = explode('.', $currentVer);
1497
        $requiredVer = '' . $module->getInfo('min_xoops'); //making sure it's a string
1498
        $reqArray    = explode('.', $requiredVer);
1499
        $success     = true;
1500
        foreach ($reqArray as $k => $v) {
1501
            if (isset($currArray[$k])) {
1502
                if ($currArray[$k] > $v) {
1503
                    break;
1504
                } elseif ($currArray[$k] == $v) {
1505
                    continue;
1506
                } else {
1507
                    $success = false;
1508
                    break;
1509
                }
1510
            } else {
1511
                if ((int)$v > 0) { // handles things like x.x.x.0_RC2
1512
                    $success = false;
1513
                    break;
1514
                }
1515
            }
1516
        }
1517
1518
        if (!$success) {
1519
            $module->setErrors(sprintf(_AM_PUBLISHER_ERROR_BAD_XOOPS, $requiredVer, $currentVer));
1520
        }
1521
1522
        return $success;
1523
    }
1524
1525
    /**
1526
     *
1527
     * Verifies PHP version meets minimum requirements for this module
1528
     * @static
1529
     * @param XoopsModule $module
1530
     *
1531
     * @return bool true if meets requirements, false if not
1532
     */
1533
    public static function checkVerPhp(XoopsModule $module)
1534
    {
1535
        xoops_loadLanguage('admin', $module->dirname());
1536
        // check for minimum PHP version
1537
        $success = true;
1538
        $verNum  = phpversion();
1539
        $reqVer  =& $module->getInfo('min_php');
1540
        if (false !== $reqVer && '' !== $reqVer) {
1541
            if (version_compare($verNum, $reqVer, '<')) {
1542
                $module->setErrors(sprintf(_AM_PUBLISHER_ERROR_BAD_PHP, $reqVer, $verNum));
1543
                $success = false;
1544
            }
1545
        }
1546
1547
        return $success;
1548
    }
1549
}
1550