Completed
Pull Request — master (#112)
by
unknown
03:22
created

SEOstats::_getPage()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 17
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3.072

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 17
ccs 8
cts 10
cp 0.8
rs 9.4285
cc 3
eloc 11
nc 3
nop 1
crap 3.072
1
<?php
2
namespace SEOstats;
3
4
use SEOstats\Common\SEOstatsException as E;
5
use SEOstats\Config as Config;
6
use SEOstats\Helper as Helper;
7
use SEOstats\Services as Service;
8
9
/** SEOstats
10
 *  ================================================================================
11
 *  PHP library to request a bunch of SEO-relevant metrics, such as looking up the
12
 *  visibilty of a URL within organic search results, Pagespeed analysis, the
13
 *  Google Toolbar PageRank, Page-Authority, Backlink-Details, Traffic Statistics,
14
 *  social media relevance, comparing competing websites and a lot more.
15
 *  ================================================================================
16
 * @package     SEOstats
17
 * @author      Stephan Schmitz <[email protected]>
18
 * @copyright   Copyright (c) 2010 - present Stephan Schmitz
19
 * @license     http://eyecatchup.mit-license.org
20
 * @version     CVS: $Id: SEOstats.php, v2.5.2 Rev 31 2013/08/14 13:57:17 ssc Exp $
21
 * @link        https://github.com/eyecatchup/SEOstats/
22
 *  ================================================================================
23
 *  LICENSE: Permission is hereby granted, free of charge, to any person obtaining
24
 *  a copy of this software and associated documentation files (the "Software'),
25
 *  to deal in the Software without restriction, including without limitation the
26
 *  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
27
 *  copies of the Software, and to permit persons to whom the Software is furnished
28
 *  to do so, subject to the following conditions:
29
 *
30
 *    The above copyright notice and this permission notice shall be included in all
31
 *  copies or substantial portions of the Software.
32
 *
33
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
37
 *  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
38
 *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
39
 *  ================================================================================
40
 */
41
42
/**
43
 * Check required PHP settings.
44
 */
45
if (!function_exists('curl_init')) {
46
    throw new E('SEOstats requires the PHP CURL extension.');
47
    exit();
48
}
49
50
if (1 == ini_get('safe_mode') || 'on' === strtolower(ini_get('safe_mode'))) {
51
    throw new E('Because some SEOstats functions require the CURLOPT_FOLLOWLOCATION flag, ' .
52
        'you must not run PHP in safe mode! (This flag can not be set in safe mode.)');
53
    exit();
54
}
55
56
/**
57
 * Starting point for the SEOstats library. Example Usage:
58
 *
59
 * <code>
60
 * ...
61
 * $url = 'http://www.domain.tld';
62
 *
63
 * // Get the Google Toolbar PageRank value.
64
 * $result = \SEOstats\Services\Google::getPageRank($url);
65
 *
66
 * // Get the first 100 results for a Google search for 'query string'.
67
 * $result = \SEOstats\Services\Google::getSerps('query string');
68
 *
69
 * // Get the first 500 results for a Google search for 'query string'.
70
 * $result = \SEOstats\Services\Google::getSerps('query string', 500);
71
 *
72
 * // Check the first 500 results for a Google search for 'query string' for
73
 * // occurrences of the given domain name and return an array of matching
74
 * // URL's and their position within the serps.
75
 * $result = \SEOstats\Services\Google::getSerps('query string', 500, $url);
76
 * ...
77
 * </code>
78
 *
79
 */
80
class SEOstats
81
{
82
    const BUILD_NO = Config\Package::VERSION_CODE;
83
84
    protected static $_url,
85
        $_host,
86
        $_lastHtml,
87
        $_lastLoadedUrl
88
        = false;
89
90 158
    public function __construct($url = false)
91
    {
92 158
        if (false !== $url) {
93
            self::setUrl($url);
94
        }
95 158
    }
96
97 1
    public function Alexa()
98
    {
99 1
        return new Service\Alexa;
100
    }
101
102 1
    public function Google()
103
    {
104 1
        return new Service\Google;
105
    }
106
107 1
    public function Mozscape()
108
    {
109 1
        return new Service\Mozscape;
110
    }
111
112 1
    public function OpenSiteExplorer()
113
    {
114 1
        return new Service\OpenSiteExplorer;
115
    }
116
117 1
    public function SEMRush()
118
    {
119 1
        return new Service\SemRush;
120
    }
121
122 1
    public function Sistrix()
123
    {
124 1
        return new Service\Sistrix;
125
    }
126
127 1
    public function Social()
128
    {
129 1
        return new Service\Social;
130
    }
131
132 1
    public static function getLastLoadedHtml()
133
    {
134 1
        return self::$_lastHtml;
135
    }
136
137 24
    public static function getLastLoadedUrl()
138
    {
139 24
        return self::$_lastLoadedUrl;
140
    }
141
142
    /**
143
     * Ensure the URL is set, return default otherwise
144
     * @return string
145
     */
146 90
    public static function getUrl($url = false)
147
    {
148 90
        $url = false !== $url ? $url : self::$_url;
149 90
        return $url;
150
    }
151
152 145
    public function setUrl($url)
153
    {
154 145
        if (false !== Helper\Url::isRfc($url)) {
155 144
            self::$_url = $url;
156 144
            self::$_host = Helper\Url::parseHost($url);
157 144
        } else {
158 1
            throw new E('Invalid URL!');
159
            exit();
0 ignored issues
show
Unused Code introduced by
die; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
160
        }
161 144
        return true;
162
    }
163
164 2
    public static function getHost($url = false)
165
    {
166 2
        return Helper\Url::parseHost(self::getUrl($url));
167
    }
168
169 1
    public static function getDomain($url = false)
0 ignored issues
show
Unused Code introduced by
The parameter $url 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...
170
    {
171 1
        return 'http://' . self::getHost($url = false);
172
    }
173
174
    /**
175
     * @return DOMDocument
176
     */
177 26
    protected static function _getDOMDocument($html)
178
    {
179 26
        $doc = new \DOMDocument;
180 26
        @$doc->loadHtml($html);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
181 26
        return $doc;
182
    }
183
184
    /**
185
     * @return DOMXPath
186
     */
187 26
    protected static function _getDOMXPath($doc)
188
    {
189 26
        $xpath = new \DOMXPath($doc);
190 26
        return $xpath;
191
    }
192
193
    /**
194
     * @return HTML string
195
     */
196 2
    protected static function _getPage($url)
197
    {
198 2
        $url = self::getUrl($url);
199 2
        if (self::getLastLoadedUrl() == $url) {
200
            return self::getLastLoadedHtml();
201
        }
202
203 2
        $html = Helper\HttpRequest::sendRequest($url);
204 2
        if ($html) {
205 2
            self::$_lastLoadedUrl = $url;
0 ignored issues
show
Documentation Bug introduced by
The property $_lastLoadedUrl was declared of type boolean, but $url is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
206 2
            self::_setHtml($html);
207 2
            return $html;
208
        } else {
209
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by SEOstats\SEOstats::_getPage of type SEOstats\HTML.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
210
            // return self::noDataDefaultValue();
211
        }
212
    }
213
214 3
    protected static function _setHtml($str)
215
    {
216 3
        self::$_lastHtml = $str;
217 3
    }
218
219 44
    public static function noDataDefaultValue()
220
    {
221 44
        return Config\DefaultSettings::get('DEFAULT_RETURN_NO_DATA');
222
    }
223
}
224