wikigame::wikigame()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
<?php
2
/*
3
 * c-wikigame
4
 * github.com/01mu
5
 */
6
class wikigame
7
{
8
    private $agent;
9
    private $context;
10
    private $conn;
11
    public function wikigame()
12
    {
13
        $this->agent = 'github.com/01mu/c-wikigame';
14
        $ctx = array("http" => array("header" => $this->agent));
15
        $this->context = stream_context_create($ctx);
16
    }
17
    public function get_popular()
18
    {
19
        $http = 'Wikipedia:Multiyear_ranking_of_most_viewed_pages';
20
        $sql = 'INSERT INTO popular (article) VALUES (?)';
21
        $article_str = $this->get_quotes_string($http);
22
        $end = strlen($article_str);
23
        $start = strpos($article_str, '==Countries==');
24
        $article_str = substr($article_str, $start, $end);
25
        $links = $this->get_links($article_str);
26
        foreach($links as $thing)
27
        {
28
            if(strpos($thing, ':') == 0) {
29
                print("'" . $thing . "' inserted.\n");
30
                $link = $this->clean_popular_link($thing);
31
                $stmt = $this->conn->prepare($sql);
32
                $stmt->execute(array($link));
33
            }
34
        }
35
    }
36
    public function create_table()
37
    {
38
        $query = 'SHOW TABLES LIKE "popular"';
39
        $result = $this->conn->query($query)->fetchAll();
40
        $exists = count($result);
41
        if(!$exists) {
42
            printf("Table 'popular' created.\n");
43
            $sql = "CREATE TABLE popular (
44
                id INT(8) AUTO_INCREMENT PRIMARY KEY,
45
                article VARCHAR(255) NOT NULL
46
                )";
47
            $this->conn->exec($sql);
48
        }
49
    }
50
    public function conn($server, $user, $pw, $db)
51
    {
52
        try
53
        {
54
            $conn = new PDO("mysql:host=$server;dbname=$db", $user, $pw);
55
            $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
56
        }
57
        catch(PDOException $e)
58
        {
59
            echo "Error: " . $e->getMessage();
60
        }
61
        $this->conn = $conn;
62
    }
63
    public function check($limit, $article, $goal)
64
    {
65
        if(!isset($limit) || !isset($article) || !isset($goal)) {
66
            show_error('bad');
67
        }
68
        if($limit <= 0 || $limit > 50) {
69
            show_error('bad');
70
        }
71
        $article = $this->get_quotes_string($article);
72
        if($this->check_redirect($article)) {
73
            $article = $this->get_redirect_link($article);
74
            $article = $this->get_quotes_string($article);
75
        }
76
        if($article === 'err_page_missing') {
77
            $this->show_error('err_page_missing');
78
        }
79
        $links = $this->get_links($article);
80
        $final = $this->get_final_links($links, $limit);
81
        if(count($final) == 0) {
82
            $this->show_error('err_page_missing');
83
        }
84
        if(!in_array($goal, $links)) {
85
            echo json_encode($final, JSON_UNESCAPED_UNICODE);
86
        }
87
        else
88
        {
89
            echo json_encode(['found_article']);
90
        }
91
    }
92
    public function get_start($limit, $type, $specific)
93
    {
94
        $articles = array();
95
        $a_links = array();
96
        if(!isset($type) || !isset($limit)) {
97
            $this->show_error('bad');
98
            return;
99
        }
100
        if($limit <= 0 || $limit > 50) {
101
            $this->show_error('bad');
102
            return;
103
        }
104
        switch($type)
105
        {
106
        case 'rand_pop':
107
            $article_goal = $this->get_random_popular();
108
            $article_goal = str_replace(" ", "_", $article_goal);
109
            break;
110
        case 'rand':
111
            $article_goal = $this->get_redirect();
112
            $article_goal = str_replace("_", " ", $article_goal);
113
            break;
114
        case 'specific':
115
            $article_goal = $specific;
116
            $rep = str_replace(" ", "_", $specific);
117
            $article_goal_link = 'https://en.wikipedia.org/wiki/' . $rep;
0 ignored issues
show
Unused Code introduced by
$article_goal_link 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...
118
            break;
119
        default:
120
            $this->show_error('bad');
121
            return;
122
        }
123
        $start = $this->get_redirect();
124
        $article_start = str_replace("_", " ", $start);
125
        $link_start = 'https://en.wikipedia.org/wiki/' . $start;
126
        $link_goal = 'https://en.wikipedia.org/wiki/' . $article_goal;
127
        $article_str = $this->get_quotes_string($start);
128
        $links = $this->get_links($article_str);
129
        $final = $this->get_final_links($links, $limit);
130
        $articles[] = $article_start;
131
        $articles[] = $article_goal;
132
        $a_links[] = $link_start;
133
        $a_links[] = $link_goal;
134
        $json[] = $articles;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$json was never initialized. Although not strictly required by PHP, it is generally a good practice to add $json = 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...
135
        $json[] = $a_links;
136
        if(!in_array($start, $links)) {
137
            $json[] = $final;
138
        }
139
        else
140
        {
141
            $json[] = ['found_article'];
142
        }
143
        echo json_encode($json, JSON_UNESCAPED_UNICODE);
144
    }
145
    private function get_links($article_str)
146
    {
147
        $links = array();
148
        $link_start_idx;
0 ignored issues
show
Bug introduced by
The variable $link_start_idx seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
149
        $link_end_idx;
0 ignored issues
show
Bug introduced by
The variable $link_end_idx seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
150
        $link_size;
0 ignored issues
show
Bug introduced by
The variable $link_size seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
151
        $link_set = false;
152
        $size = strlen($article_str) - 1;
153
        $index = 0;
154
        while($index != $size)
155
        {
156
            $fidx = $article_str[$index];
157
            $sidx = $article_str[$index + 1];
158
            if($fidx == '[' && $sidx == '[') {
159
                $link_start_idx = $index + 2;
160
                $link_set = true;
161
            }
162
            if($fidx == ']' && $sidx == ']' && $link_set == true) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
163
                $link_end_idx = $index;
164
                $link_size = $link_end_idx - $link_start_idx;
0 ignored issues
show
Bug introduced by
The variable $link_start_idx 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...
165
                $found_link = substr($article_str, $link_start_idx, $link_size);
166
                if(!$this->bad_link_check($found_link) 
167
                    && !in_array($found_link, $links)
168
                ) {
169
                    $links[] = $found_link;
170
                }
171
                $link_set = false;
172
            }
173
            $index++;
174
        }
175
        return $links;
176
    }
177
    private function bad_link_check($found_link)
178
    {
179
        $bad = [':', 'http', '\\', '<', '#'];
180
        $is_bad = false;
181
        foreach($bad as $check)
182
        {
183
            if(strpos($found_link, $check) !== false) {
184
                $is_bad = true;
185
                break;
186
            }
187
        }
188
        return $is_bad;
189
    }
190 View Code Duplication
    private function fix_link($link)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
191
    {
192
        if(strpos($link, "|") !== false) {
193
            $line = strpos($link, "|");
194
            $link = substr($link, 0, $line);
195
        }
196
        return $link;
197
    }
198 View Code Duplication
    private function fix_h($link)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
199
    {
200
        if(strpos($link, "#") !== false) {
201
            $line = strpos($link, "#");
202
            $link = substr($link, 0, $line);
203
        }
204
        return $link;
205
    }
206
    private function get_quotes_string($redirect)
207
    {
208
        $quotes;
0 ignored issues
show
Bug introduced by
The variable $quotes seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
209
        $redirect = str_replace(" ", "_", $redirect);
210
        $redirect = $this->fix_h($redirect);
211
        $url = 'https://en.wikipedia.org/w/api.php?action=query' .
212
            '&titles=' . $redirect . '&prop=revisions&rvprop=content' .
213
            '&format=json&formatversion=2';
214
        $data = file_get_contents($url, false, $this->context);
215
        $wiki = json_decode($data, true);
216
        if(isset($wiki['query']['pages'][0]['missing'])) {
217
            $quotes = 'err_page_missing';
218
        }
219
        else
220
        {
221
            $quotes = $wiki['query']['pages'][0]['revisions'][0]['content'];
222
        }
223
        return $quotes;
224
    }
225
    private function get_redirect_url($url)
226
    {
227
        $r = array('http' => array('method' => 'HEAD'));
228
        stream_context_set_default($r);
229
        $headers = get_headers($url, 1);
230
        if($headers !== false && isset($headers['Location'])) {
231
            return $headers['Location'];
232
        }
233
        return false;
234
    }
235
    private function get_redirect()
236
    {
237
        $wiki_rand = 'https://en.wikipedia.org/wiki/Special:Random';
238
        $replace = 'https://en.wikipedia.org/wiki/';
239
        $url = $this->get_redirect_url($wiki_rand);
240
        return str_replace($replace, '', $url);
241
    }
242
    private function check_redirect($article)
243
    {
244
        $redirect = false;
245
        if(strpos($article, "#REDIRECT") !== false) {
246
            $redirect = true;
247
        }
248
        return $redirect;
249
    }
250
    public function get_redirect_link($article)
251
    {
252
        $ret;
0 ignored issues
show
Bug introduced by
The variable $ret seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
253
        if(count($this->get_links($article)) == 0) {
254
            $ret = 'no_links';
255
        }
256
        else
257
        {
258
            $ret = $this->get_links($article)[0];
259
        }
260
        return $ret;
261
    }
262
    private function get_final_links($links, $limit)
263
    {
264
        $final = array();
265
        $rands = array();
266
        $link_count = count($links);
267
        if($link_count > $limit) {
268
            for($i = 0; $i < $limit; $i++)
269
            {
270
                $rand_val = rand(0, $link_count - 1);
271
                if(!in_array($rand_val, $rands)) {
272
                    $rands[] = $rand_val;
273
                }
274
            }
275
        }
276
        else
277
        {
278
            for($i = 0; $i < count($links); $i++)
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
279
            {
280
                $rands[] = $i;
281
            }
282
        }
283
        for($i = 0; $i < count($rands); $i++)
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
284
        {
285
            $r = $rands[$i];
286
            $link = $links[$r];
287
            $link = $this->fix_link($link);
288
            $link = trim($link);
289
            $final[] = $link;
290
        }
291
        return $final;
292
    }
293
    private function clean_popular_link($link)
294
    {
295
        if($link[0] == ':') {
296
            $link = str_replace(':', '', $link);
297
        }
298
        $link = $this->fix_link($link);
299
        $link = trim($link);
300
        return $link;
301
    }
302
    private function get_random_popular()
303
    {
304
        $sql = 'SELECT article FROM popular ORDER BY RAND() LIMIT 1, 1';
305
        $stmt = $this->conn->query($sql);
306
        while($row = $stmt->fetch())
307
        {
308
            $article = $row['article'];
309
        }
310
        return $article;
0 ignored issues
show
Bug introduced by
The variable $article 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...
311
    }
312
    private function show_error($notice)
313
    {
314
        echo json_encode([$notice]);
315
    }
316
}