Failed Conditions
Pull Request — dev (#132)
by Steve
03:45
created

Http::checkUnreachablepath()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 1 Features 0
Metric Value
c 4
b 1
f 0
dl 0
loc 6
rs 9.4286
cc 1
eloc 4
nc 1
nop 0
1
<?php
2
/**
3
 * Mage Scan
4
 *
5
 * PHP version 5
6
 *
7
 * @category  MageScan
8
 * @package   MageScan
9
 * @author    Steve Robbins <[email protected]>
10
 * @copyright 2015 Steve Robbins
11
 * @license   http://creativecommons.org/licenses/by/4.0/ CC BY 4.0
12
 * @link      https://github.com/steverobbins/magescan
13
 */
14
15
namespace MageScan;
16
17
use MageScan\Check\Catalog;
18
use MageScan\Check\Module;
19
use MageScan\Check\Patch;
20
use MageScan\Check\Sitemap;
21
use MageScan\Check\TechHeader;
22
use MageScan\Check\UnreachablePath;
23
use MageScan\Check\Version;
24
use MageScan\Request;
25
use MageScan\Url;
26
27
/**
28
 * Scan a Magento site using a web browser
29
 *
30
 * @category  MageScan
31
 * @package   MageScan
32
 * @author    Steve Robbins <[email protected]>
33
 * @copyright 2015 Steve Robbins
34
 * @license   http://creativecommons.org/licenses/by/4.0/ CC BY 4.0
35
 * @link      https://github.com/steverobbins/magescan
36
 */
37
class Http
38
{
39
    /**
40
     * The URL we are scanning
41
     *
42
     * @var string
43
     */
44
    public $url;
45
46
    /**
47
     * Request object
48
     *
49
     * @var \MageScan\Request
50
     */
51
    protected $request;
52
53
    /**
54
     * Start a check
55
     *
56
     * @param string $code
57
     * @param string $url
58
     */
59
    public function __construct($code, $url)
1 ignored issue
show
Coding Style introduced by
__construct 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...
60
    {
61
        $magescanUrl = new Url;
62
        $this->url     = $magescanUrl->clean(urldecode($url));
63
        $this->request = new Request($this->url, isset($_SERVER['ALLOW_INSECURE']));
64
        call_user_func([$this, 'check' . ucwords($code)]);
65
    }
66
67
    /**
68
     * Check for Magento version
69
     *
70
     * @return void
71
     */
72
    public function checkMagentoinfo()
73
    {
74
        $version = new Version;
75
        $version->setRequest($this->request);
76
        $version = $version->getInfo();
77
        $rows    = [
78
            ['Edition', $version[0] ?: 'Unknown'],
79
            ['Version', $version[1] ?: 'Unknown']
80
        ];
81
        $this->respond(['body' => $rows]);
82
    }
83
84
    /**
85
     * Check for installed modules
86
     *
87
     * @return void
88
     */
89
    public function checkModules()
90
    {
91
        $module = new Module;
92
        $module->setRequest($this->request);
93
        $this->respond(array_keys($module->getFiles()));
94
    }
95
96
    /**
97
     * Check for an installed module
98
     *
99
     * @return void
100
     */
101
    public function checkModulessingle()
1 ignored issue
show
Coding Style introduced by
checkModulessingle uses the super-global variable $_GET 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...
102
    {
103
        $module = new Module;
104
        $module->setRequest($this->request);
105
        $file   = $_GET['path'];
106
        $files  = $module->getFiles();
107
        $result = $module->checkForModule($_GET['path']);
108
        if ($result) {
109
            $this->respond([
110
                isset($files[$file]) ? $files[$file] : '<!-- how did this happen -->'
111
            ]);
112
        }
113
    }
114
115
    /**
116
     * Check for install patches
117
     *
118
     * @return void
119
     */
120
    public function checkPatch()
121
    {
122
        $patch   = new Patch;
123
        $patch->setRequest($this->request);
124
        $patches = $patch->checkAll($this->url);
125
        $rows    = [];
126 View Code Duplication
        foreach ($patches as $name => $result) {
1 ignored issue
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...
127
            switch ($result) {
128
                case PATCH::PATCHED:
129
                    $status = '<span class="pass">Patched</span class="pass">';
130
                    break;
131
                case PATCH::UNPATCHED:
132
                    $status = '<span class="fail">Unpatched</span class="fail">';
133
                    break;
134
                default:
135
                    $status = 'Unknown';
136
            }
137
            $rows[] = [
138
                $name,
139
                $status
140
            ];
141
        }
142
        $this->respond([
143
            'head' => ['Patch', 'Status'],
144
            'body' => $rows
145
        ]);
146
    }
147
148
    /**
149
     * Check for catalog information
150
     *
151
     * @return void
152
     */
153
    public function checkCatalog()
154
    {
155
        $rows    = [];
156
        $catalog = new Catalog;
157
        $catalog->setRequest($this->request);
158
        $categoryCount = $catalog->categoryCount();
159
        $rows[]        = [
160
            '<a href="' . $this->url. 'catalog/seo_sitemap/category" target="_blank">Categories</a>',
161
            $categoryCount !== false ? $categoryCount : 'Unknown'
162
        ];
163
        $productCount = $catalog->productCount();
164
        $rows[]       = [
165
            '<a href="' . $this->url . 'catalog/seo_sitemap/product" target="_blank">Products</a>',
166
            $productCount !== false ? $productCount : 'Unknown'
167
        ];
168
        $this->respond(['body' => $rows]);
169
    }
170
171
    /**
172
     * Check for a valid sitemap
173
     *
174
     * @return void
175
     */
176
    public function checkSitemap()
177
    {
178
        $rows       = [];
179
        $response   = $this->request->get('robots.txt');
0 ignored issues
show
Documentation Bug introduced by
The method get does not exist on object<MageScan\Request>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
180
        $sitemap    = new Sitemap;
181
        $sitemap->setRequest($this->request);
182
        $sitemapUrl = $sitemap->getSitemapFromRobotsTxt($response);
183
        if ($sitemapUrl === false) {
184
            $rows[] = ['<span class="fail">Sitemap is not declared in <a href="' . $this->url
185
                . 'robots.txt" target="_blank">robots.txt</a></span>'];
186
            $sitemapUrl = $this->url . 'sitemap.xml';
187
        } else {
188
            $rows[] = ['<span class="pass">Sitemap is declared in <a href="' . $this->url
189
                . 'robots.txt" target="_blank">robots.txt</a></span></span>'];
190
        }
191
        $response = $this->request->get($sitemapUrl);
0 ignored issues
show
Documentation Bug introduced by
The method get does not exist on object<MageScan\Request>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
192
        if ($response->code == 200) {
193
            $rows[] = ['<span class="pass"><a href="' . $sitemapUrl
194
                . '" target="_blank">Sitemap</a> is accessible</span>'];
195
        } else {
196
            $rows[] = ['<span class="fail"><a href="' . $sitemapUrl
197
                . '" target="_blank">Sitemap</a> is not accessible</span>'];
198
        }
199
        $this->respond(['body' => $rows]);
200
    }
201
202
    /**
203
     * Check for server technologies
204
     *
205
     * @return void
206
     */
207
    public function checkServertech()
208
    {
209
        $rows       = [];
210
        $techHeader = new TechHeader;
211
        $techHeader->setRequest($this->request);
212
        $values     = $techHeader->getHeaders();
213
        if (empty($values)) {
214
            $rows[] = ['No detectable technology was found'];
215
        }
216
        foreach ($values as $key => $value) {
217
            $rows[] = [$key, $value];
218
        }
219
        $this->respond(['body' => $rows]);
220
    }
221
222
    /**
223
     * Check for unreachable paths
224
     *
225
     * @return void
226
     */
227
    public function checkUnreachablepath()
228
    {
229
        $unreachablePath = new UnreachablePath;
230
        $unreachablePath->setRequest($this->request);
231
        $this->respond($unreachablePath->getPaths());
232
    }
233
234
    /**
235
     * Check for unreachable paths
236
     *
237
     * @return void
238
     */
239
    public function checkUnreachablepathsingle()
1 ignored issue
show
Coding Style introduced by
checkUnreachablepathsingle uses the super-global variable $_GET 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...
240
    {
241
        $unreachablePath = new UnreachablePath;
242
        $unreachablePath->setRequest($this->request);
243
        $result          = $unreachablePath->checkPath($_GET['path']);
244
        if ($result[2] === true) {
245
            return;
246
        }
247
        if ($result[2] === false) {
248
            $result[0] = '<a target="_blank" href="' . $this->url . $result[0] . '">' . $result[0] . '</a>';
249
            $result[2] = '<span class="fail">Reachable</span>';
250
        } elseif (substr($result[1], 0, 1) == 3) {
251
            if (substr($result[2], 0, 4) == 'http') {
252
                $newUrl = $result[2];
253
            } else {
254
                $newUrl = $this->url . substr($result[2], 1);
255
            }
256
            $result[0] = '<a target="_blank" href="' . $newUrl . '">' . $result[0] . '</a>';
257
            $result[2] = '<a target="_blank" href="' . $newUrl . '">Redirect</a>';
258
        }
259
        $this->respond($result);
260
    }
261
262
    /**
263
     * Send JSON response
264
     *
265
     * @param array $data
266
     *
267
     * @return void
268
     */
269
    public function respond(array $data)
270
    {
271
        echo json_encode($data);
272
    }
273
}
274