Completed
Branch master (b963e0)
by Michael
03:39
created

PublisherUtility::userIsAuthor()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 2
nc 3
nop 1
dl 0
loc 4
rs 10
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 32 and the first side effect is on line 25.

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

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

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

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

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.

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

Loading history...
1371
     *
1372
     * @param null|string $requiredVer
1373
     * @return bool true if meets requirements, false if not
1374
     */
1375
    public static function checkVerXoops(XoopsModule $module = null, $requiredVer = null)
1376
    {
1377
        $moduleDirName = basename(dirname(__DIR__));
1378
        if (null === $module) {
1379
            $module = XoopsModule::getByDirname($moduleDirName);
1380
        }
1381
        xoops_loadLanguage('admin', $moduleDirName);
1382
        //check for minimum XOOPS version
1383
        $currentVer = substr(XOOPS_VERSION, 6); // get the numeric part of string
1384
        $currArray  = explode('.', $currentVer);
1385
        if (null === $requiredVer) {
1386
            $requiredVer = '' . $module->getInfo('min_xoops'); //making sure it's a string
1387
        }
1388
        $reqArray = explode('.', $requiredVer);
1389
        $success  = true;
1390
        foreach ($reqArray as $k => $v) {
1391
            if (isset($currArray[$k])) {
1392
                if ($currArray[$k] > $v) {
1393
                    break;
1394
                } elseif ($currArray[$k] == $v) {
1395
                    continue;
1396
                } else {
1397
                    $success = false;
1398
                    break;
1399
                }
1400
            } else {
1401
                if ((int)$v > 0) { // handles versions like x.x.x.0_RC2
1402
                    $success = false;
1403
                    break;
1404
                }
1405
            }
1406
        }
1407
1408
        if (false === $success) {
1409
            $module->setErrors(sprintf(_AM_PUBLISHER_ERROR_BAD_XOOPS, $requiredVer, $currentVer));
1410
        }
1411
1412
        return $success;
1413
    }
1414
1415
    /**
1416
     *
1417
     * Verifies PHP version meets minimum requirements for this module
1418
     * @static
1419
     * @param XoopsModule $module
1420
     *
1421
     * @return bool true if meets requirements, false if not
1422
     */
1423
    public static function checkVerPhp(XoopsModule $module)
1424
    {
1425
        xoops_loadLanguage('admin', $module->dirname());
1426
        // check for minimum PHP version
1427
        $success = true;
1428
        $verNum  = PHP_VERSION;
1429
        $reqVer  = $module->getInfo('min_php');
1430
        if (false !== $reqVer && '' !== $reqVer) {
1431
            if (version_compare($verNum, $reqVer, '<')) {
1432
                $module->setErrors(sprintf(_AM_PUBLISHER_ERROR_BAD_PHP, $reqVer, $verNum));
1433
                $success = false;
1434
            }
1435
        }
1436
1437
        return $success;
1438
    }
1439
}
1440