Completed
Push — master ( 3fef35...593e0d )
by Michael
02:10
created

XoopsInstallWizard::createForm()   C

Complexity

Conditions 7
Paths 7

Size

Total Lines 31
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 31
rs 6.7272
cc 7
eloc 20
nc 7
nop 0
1
<?php
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
 * See the enclosed file license.txt for licensing information.
14
 * If you did not receive this file, get it at http://www.gnu.org/licenses/gpl-2.0.html
15
 *
16
 * @copyright   XOOPS Project (http://xoops.org)
17
 * @license     http://www.gnu.org/licenses/gpl-2.0.html GNU General Public License (GPL)
18
 * @package     installer
19
 * @since       2.3.0
20
 * @author      Haruki Setoyama  <[email protected]>
21
 * @author      Kazumi Ono <[email protected]>
22
 * @author      Skalpa Keo <[email protected]>
23
 * @author      Taiwen Jiang <[email protected]>
24
 * @author      DuGris (aka L. JEN) <[email protected]>
25
 */
26
class XoopsInstallWizard
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...
27
{
28
    public $language    = 'english';
29
    public $pages       = array();
30
    public $currentPage = 'langselect';
31
    public $pageIndex   = 0;
32
    public $configs     = array();
33
34
    /**
35
     * @return bool
36
     */
37
    public function xoInit()
0 ignored issues
show
Coding Style introduced by
xoInit uses the super-global variable $_SERVER 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
xoInit uses the super-global variable $_COOKIE 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...
38
    {
39
        if (@empty($_SERVER['REQUEST_URI'])) {
40
            $_SERVER['REQUEST_URI'] = $_SERVER['PHP_SELF'];
41
        }
42
43
        // Load the main language file
44
        $this->initLanguage(!empty($_COOKIE['xo_install_lang']) ? $_COOKIE['xo_install_lang'] : 'english');
45
        // Setup pages
46
        include_once './../include/page.php';
47
        $this->pages = $pages;
0 ignored issues
show
Bug introduced by
The variable $pages does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
48
49
        // Load default configs
50
        include_once './../include/config.php';
51
        $this->configs = $configs;
0 ignored issues
show
Bug introduced by
The variable $configs does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
52
        /*
53
        // Database type
54
        $this->db_types  = $db_types;
55
56
        // setup config site info
57
        $this->conf_names  = $conf_names;
58
59
        // languages config files
60
        $this->language_files = $language_files;
61
62
        // extension_loaded
63
        $this->extensions = $extensions;
64
65
        // Modules to be installed by default
66
        $this->modules = $modules;
67
68
        // xoops_lib, xoops_data directories
69
        $this->xoopsPathDefault = $xoopsPathDefault;
70
71
        // writable xoops_lib, xoops_data directories
72
        $this->dataPath = $dataPath;
73
74
        // Protector default trust_path
75
        $this->trust_path = isset($trust_path) ? $trust_path : false;
76
77
        // Writable files and directories
78
        $this->writable = $writable;
79
        */
80
81
        if (!$this->checkAccess()) {
82
            return false;
83
        }
84
85
        $pagename = preg_replace('~(page_)(.*)~', '$2', basename($_SERVER['PHP_SELF'], '.php'));
86
        $this->setPage($pagename);
87
88
        // Prevent client caching
89
        header('Cache-Control: no-store, no-cache, must-revalidate', false);
90
        header('Pragma: no-cache');
91
92
        return true;
93
    }
94
95
    /**
96
     * @return bool
97
     */
98
    public function checkAccess()
0 ignored issues
show
Coding Style introduced by
checkAccess uses the super-global variable $_SERVER 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
checkAccess 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
checkAccess uses the super-global variable $_COOKIE 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...
99
    {
100
        if (INSTALL_USER != '' && INSTALL_PASSWORD != '') {
101
            if (!isset($_SERVER['PHP_AUTH_USER'])) {
102
                header('WWW-Authenticate: Basic realm="XOOPS Installer"');
103
                header('HTTP/1.0 401 Unauthorized');
104
                echo 'You can not access this XOOPS installer.';
105
106
                return false;
107
            }
108
            if (INSTALL_USER != '' && $_SERVER['PHP_AUTH_USER'] != INSTALL_USER) {
109
                header('HTTP/1.0 401 Unauthorized');
110
                echo 'You can not access this XOOPS installer.';
111
112
                return false;
113
            }
114
            if (INSTALL_PASSWORD != $_SERVER['PHP_AUTH_PW']) {
115
                header('HTTP/1.0 401 Unauthorized');
116
                echo 'You can not access this XOOPS installer.';
117
118
                return false;
119
            }
120
        }
121
122
        if (empty($GLOBALS['xoopsOption']['checkadmin'])) {
123
            return true;
124
        }
125
126
        if (empty($GLOBALS['xoopsUser']) && !empty($_COOKIE['xo_install_user'])) {
127
            install_acceptUser($_COOKIE['xo_install_user']);
128
        }
129
        if (empty($GLOBALS['xoopsUser'])) {
130
            redirect_header('../user.php');
131
        }
132
        if (!$GLOBALS['xoopsUser']->isAdmin()) {
133
            return false;
134
        }
135
136
        return true;
137
    }
138
139
    /**
140
     * @param $file
141
     */
142
    public function loadLangFile($file)
143
    {
144
        if (file_exists("./language/{$this->language}/{$file}.php")) {
145
            include_once "./language/{$this->language}/{$file}.php";
146
        } else {
147
            include_once "./../language/english/$file.php";
148
        }
149
    }
150
151
    /**
152
     * @param $language
153
     */
154
    public function initLanguage($language)
155
    {
156
        $language = preg_replace("/[^a-z0-9_\-]/i", '', $language);
157
        if (!file_exists("./language/{$language}/install.php")) {
158
            $language = 'english';
159
        }
160
        $this->language = $language;
161
        $this->loadLangFile('install');
162
    }
163
164
    /**
165
     * @param $page
166
     *
167
     * @return bool|mixed
168
     */
169
    public function setPage($page)
0 ignored issues
show
Coding Style introduced by
setPage uses the super-global variable $_COOKIE 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...
170
    {
171
        $pages = array_keys($this->pages);
172
        if ((int)$page && $page >= 0 && $page < count($pages)) {
173
            $this->pageIndex   = $page;
174
            $this->currentPage = $pages[$page];
0 ignored issues
show
Documentation Bug introduced by
It seems like $pages[$page] can also be of type integer. However, the property $currentPage is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

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

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
175
        } elseif (isset($this->pages[$page])) {
176
            $this->currentPage = $page;
177
            $this->pageIndex   = array_search($this->currentPage, $pages);
0 ignored issues
show
Documentation Bug introduced by
It seems like array_search($this->currentPage, $pages) can also be of type false. However, the property $pageIndex is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

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

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
178
        } else {
179
            return false;
180
        }
181
182
        if ($this->pageIndex > 0 && !isset($_COOKIE['xo_install_lang'])) {
183
            header('Location: index.php');
184
        }
185
186
        return $this->pageIndex;
187
    }
188
189
    /**
190
     * @return string
191
     */
192
    public function baseLocation()
0 ignored issues
show
Coding Style introduced by
baseLocation uses the super-global variable $_SERVER 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...
193
    {
194
        $proto = (@$_SERVER['HTTPS'] === 'on') ? 'https' : 'http';
195
        $host  = $_SERVER['HTTP_HOST'];
196
        $base  = substr($_SERVER['PHP_SELF'], 0, strrpos($_SERVER['PHP_SELF'], '/'));
197
198
        return $proto . '://' . $host . $base;
199
    }
200
201
    /**
202
     * @param $page
203
     *
204
     * @return string
205
     */
206
    public function pageURI($page)
207
    {
208
        $pages     = array_keys($this->pages);
209
        $pageIndex = $this->pageIndex;
210
        if (!(int)$page{0}) {
211
            if ($page{0} == '+') {
212
                $pageIndex += substr($page, 1);
213
            } elseif ($page{0} == '-') {
214
                $pageIndex -= substr($page, 1);
215
            } else {
216
                $pageIndex = (int)array_search($page, $pages);
217
            }
218
        }
219
        if (!isset($pages[$pageIndex])) {
220
            if (defined('XOOPS_URL')) {
221
                return XOOPS_URL;
222
            } else {
223
                return $this->baseLocation();
224
            }
225
        }
226
        $page = $pages[$pageIndex];
227
228
        return $this->baseLocation() . "/page_{$page}.php";
229
    }
230
231
    /**
232
     * @param        $page
233
     * @param int    $status
234
     * @param string $message
235
     */
236
    public function redirectToPage($page, $status = 303, $message = 'See other')
0 ignored issues
show
Coding Style introduced by
redirectToPage uses the super-global variable $_SERVER 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...
237
    {
238
        $location = $this->pageURI($page);
239
        $proto    = !@empty($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1';
240
        header("{$proto} {$status} {$message}");
241
        //header( "Status: $status $message" );
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...
242
        header("Location: {$location}");
243
    }
244
245
    /**
246
     * @return string
247
     */
248
    public function createForm()
249
    {
250
        $hidden = '';
251
        $ret    = '';
252
253
        foreach ($this->form as $form) {
0 ignored issues
show
Bug introduced by
The property form does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
254
            $ret .= '<fieldset><legend>' . $form->getTitle() . "</legend>\n";
255
256
            foreach ($form->getElements() as $ele) {
257
                if (is_object($ele)) {
258
                    if (!$ele->isHidden()) {
259
                        if (($caption = $ele->getCaption()) != '') {
260
                            $name = $ele->getName();
0 ignored issues
show
Unused Code introduced by
$name 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...
261
                            $ret .= "<label class='xolabel' for='" . $ele->getName() . "'>" . $caption . '</label>';
262
                            if (($desc = $ele->getDescription()) != '') {
263
                                $ret .= "<div class='xoform-help'>";
264
                                $ret .= $desc;
265
                                $ret .= '</div>';
266
                            }
267
                        }
268
                        $ret .= $ele->render() . "\n";
269
                    } else {
270
                        $hidden .= $ele->render() . "\n";
271
                    }
272
                }
273
            }
274
            $ret .= "</fieldset>\n" . $hidden . "\n" . $form->renderValidationJS(true);
275
        }
276
277
        return $ret;
278
    }
279
}
280