Af_RedditImgur::testurl()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 25
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 15
c 0
b 0
f 0
nc 2
nop 0
dl 0
loc 25
rs 9.7666
1
<?php
2
class Af_RedditImgur extends Plugin {
3
4
    /* @var PluginHost $host */
5
    private $host;
6
7
    public function about() {
8
        return array(1.0,
9
            "Inline images (and other content) in Reddit RSS feeds",
10
            "fox");
11
    }
12
13
    public function flags() {
14
        return array("needs_curl" => true);
15
    }
16
17
    public function init($host) {
18
        $this->host = $host;
19
20
        $host->add_hook($host::HOOK_ARTICLE_FILTER, $this);
21
        $host->add_hook($host::HOOK_PREFS_TAB, $this);
22
    }
23
24
    public function hook_prefs_tab($args) {
25
        if ($args != "prefFeeds") {
26
            return;
27
        }
28
29
        print "<div dojoType=\"dijit.layout.AccordionPane\"
30
			title=\"<i class='material-icons'>extension</i> ".__('Reddit content settings (af_redditimgur)')."\">";
31
32
        $enable_readability = $this->host->get($this, "enable_readability");
33
        $enable_content_dupcheck = $this->host->get($this, "enable_content_dupcheck");
34
35
        if (version_compare(PHP_VERSION, '5.6.0', '<')) {
36
            print_error("Readability requires PHP version 5.6.");
0 ignored issues
show
Deprecated Code introduced by
The function print_error() has been deprecated: Use twig function errorMessage ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

36
            /** @scrutinizer ignore-deprecated */ print_error("Readability requires PHP version 5.6.");

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
Unused Code introduced by
The call to print_error() has too many arguments starting with 'Readability requires PHP version 5.6.'. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

36
            /** @scrutinizer ignore-call */ 
37
            print_error("Readability requires PHP version 5.6.");

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
37
        }
38
39
        print "<form dojoType='dijit.form.Form'>";
40
41
        print "<script type='dojo/method' event='onSubmit' args='evt'>
42
			evt.preventDefault();
43
			if (this.validate()) {
44
				console.log(dojo.objectToQuery(this.getValues()));
45
				new Ajax.Request('backend.php', {
46
					parameters: dojo.objectToQuery(this.getValues()),
47
					onComplete: function(transport) {
48
						Notify.info(transport.responseText);
49
					}
50
				});
51
				//this.reset();
52
			}
53
			</script>";
54
55
        print_hidden("op", "pluginhandler");
56
        print_hidden("method", "save");
57
        print_hidden("plugin", "af_redditimgur");
58
59
        print "<fieldset class='narrow'>";
60
        print "<label class='checkbox'>";
61
        print_checkbox("enable_readability", $enable_readability);
62
        print " ".__("Extract missing content using Readability (requires af_readability)")."</label>";
63
        print "</fieldset>";
64
65
        print "<fieldset class='narrow'>";
66
        print "<label class='checkbox'>";
67
        print_checkbox("enable_content_dupcheck", $enable_content_dupcheck);
68
        print " ".__("Enable additional duplicate checking")."</label>";
69
        print "</fieldset>";
70
71
        print_button("submit", __("Save"), 'class="alt-primary"');
72
        print "</form>";
73
74
        print "</div>";
75
    }
76
77
    public function save() {
78
        $enable_readability = checkbox_to_sql_bool($_POST["enable_readability"]);
79
        $enable_content_dupcheck = checkbox_to_sql_bool($_POST["enable_content_dupcheck"]);
80
81
        $this->host->set($this, "enable_readability", $enable_readability, false);
82
        $this->host->set($this, "enable_content_dupcheck", $enable_content_dupcheck);
83
84
        echo __("Configuration saved");
85
    }
86
87
    /**
88
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
89
     */
90
    private function inline_stuff($article, &$doc, $xpath) {
0 ignored issues
show
Unused Code introduced by
The parameter $article is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

90
    private function inline_stuff(/** @scrutinizer ignore-unused */ $article, &$doc, $xpath) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
91
92
        $entries = $xpath->query('(//a[@href]|//img[@src])');
93
        $img_entries = $xpath->query("(//img[@src])");
94
95
        $found = false;
96
        //$debug = 1;
97
98
        foreach ($entries as $entry) {
99
            if ($entry->hasAttribute("href") && strpos($entry->getAttribute("href"), "reddit.com") === false) {
100
101
                Debug::log("processing href: ".$entry->getAttribute("href"), Debug::$LOG_VERBOSE);
102
103
                $matches = array();
104
105
                if (!$found && preg_match("/^https?:\/\/twitter.com\/(.*?)\/status\/(.*)/", $entry->getAttribute("href"), $matches)) {
106
                    Debug::log("handling as twitter: ".$matches[1]." ".$matches[2], Debug::$LOG_VERBOSE);
107
108
                    $oembed_result = fetch_file_contents("https://publish.twitter.com/oembed?url=".urlencode($entry->getAttribute("href")));
109
110
                    if ($oembed_result) {
111
                        $oembed_result = json_decode($oembed_result, true);
0 ignored issues
show
Bug introduced by
It seems like $oembed_result can also be of type true; however, parameter $json of json_decode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

111
                        $oembed_result = json_decode(/** @scrutinizer ignore-type */ $oembed_result, true);
Loading history...
112
113
                        if ($oembed_result && isset($oembed_result["html"])) {
114
115
                            $tmp = new DOMDocument();
116
                            if ($tmp->loadHTML('<?xml encoding="utf-8" ?>'.$oembed_result["html"])) {
117
                                $p = $doc->createElement("p");
118
119
                                $p->appendChild($doc->importNode(
120
                                    $tmp->getElementsByTagName("blockquote")->item(0), true));
121
122
                                $br = $doc->createElement('br');
123
                                $entry->parentNode->insertBefore($p, $entry);
124
                                $entry->parentNode->insertBefore($br, $entry);
125
126
                                $found = 1;
127
                            }
128
                        }
129
                    }
130
                }
131
132
                if (!$found && preg_match("/\.gfycat.com\/([a-z]+)?(\.[a-z]+)$/i", $entry->getAttribute("href"), $matches)) {
133
                    $entry->setAttribute("href", "http://www.gfycat.com/".$matches[1]);
134
                }
135
136
                if (!$found && preg_match("/https?:\/\/(www\.)?gfycat.com\/([a-z]+)$/i", $entry->getAttribute("href"), $matches)) {
137
138
                    Debug::log("Handling as Gfycat", Debug::$LOG_VERBOSE);
139
140
                    $source_stream = 'https://giant.gfycat.com/'.$matches[2].'.mp4';
141
                    $poster_url = 'https://thumbs.gfycat.com/'.$matches[2].'-mobile.jpg';
142
143
                    $content_type = $this->get_content_type($source_stream);
144
145
                    if (strpos($content_type, "video/") !== false) {
0 ignored issues
show
Bug introduced by
It seems like $content_type can also be of type false; however, parameter $haystack of strpos() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

145
                    if (strpos(/** @scrutinizer ignore-type */ $content_type, "video/") !== false) {
Loading history...
146
                        $this->handle_as_video($doc, $entry, $source_stream, $poster_url);
147
                        $found = 1;
148
                    }
149
                }
150
151
                if (!$found && preg_match("/https?:\/\/v\.redd\.it\/(.*)$/i", $entry->getAttribute("href"), $matches)) {
152
153
                    Debug::log("Handling as reddit inline video", Debug::$LOG_VERBOSE);
154
155
                    $img = $img_entries->item(0);
156
157
                    if ($img) {
158
                        $poster_url = $img->getAttribute("src");
159
                    } else {
160
                        $poster_url = false;
161
                    }
162
163
                    // Get original article URL from v.redd.it redirects
164
                    $source_article_url = $this->get_location($matches[0]);
165
                    Debug::log("Resolved ".$matches[0]." to ".$source_article_url, Debug::$LOG_VERBOSE);
0 ignored issues
show
Bug introduced by
Are you sure $source_article_url of type false|mixed can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

165
                    Debug::log("Resolved ".$matches[0]." to "./** @scrutinizer ignore-type */ $source_article_url, Debug::$LOG_VERBOSE);
Loading history...
166
167
                    $source_stream = false;
168
169
                    if ($source_article_url) {
170
                        $j = json_decode(fetch_file_contents($source_article_url.".json"), true);
171
172
                        if ($j) {
173
                            foreach ($j as $listing) {
174
                                foreach ($listing["data"]["children"] as $child) {
175
                                    if ($child["data"]["url"] == $matches[0]) {
176
                                        try {
177
                                            $source_stream = $child["data"]["media"]["reddit_video"]["fallback_url"];
178
                                        } catch (Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
179
                                        }
180
                                        break 2;
181
                                    }
182
                                }
183
                            }
184
                        }
185
                    }
186
187
                    if (!$source_stream) {
188
                        $source_stream = "https://v.redd.it/".$matches[1]."/DASH_600_K";
189
                    }
190
191
                    $this->handle_as_video($doc, $entry, $source_stream, $poster_url);
192
                    $found = 1;
193
                }
194
195
                if (!$found && preg_match("/https?:\/\/(www\.)?streamable.com\//i", $entry->getAttribute("href"))) {
196
197
                    Debug::log("Handling as Streamable", Debug::$LOG_VERBOSE);
198
199
                    $tmp = fetch_file_contents($entry->getAttribute("href"));
200
201
                    if ($tmp) {
202
                        $tmpdoc = new DOMDocument();
203
204
                        if (@$tmpdoc->loadHTML($tmp)) {
0 ignored issues
show
Bug introduced by
It seems like $tmp can also be of type true; however, parameter $source of DOMDocument::loadHTML() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

204
                        if (@$tmpdoc->loadHTML(/** @scrutinizer ignore-type */ $tmp)) {
Loading history...
205
                            $tmpxpath = new DOMXPath($tmpdoc);
206
207
                            $source_node = $tmpxpath->query("//video[contains(@class,'video-player-tag')]//source[contains(@src, '.mp4')]")->item(0);
208
                            $poster_node = $tmpxpath->query("//video[contains(@class,'video-player-tag') and @poster]")->item(0);
209
210
                            if ($source_node && $poster_node) {
211
                                $source_stream = $source_node->getAttribute("src");
212
                                $poster_url = $poster_node->getAttribute("poster");
213
214
                                $this->handle_as_video($doc, $entry, $source_stream, $poster_url);
215
                                $found = 1;
216
                            }
217
                        }
218
                    }
219
                }
220
221
                // imgur .gif -> .gifv
222
                if (!$found && preg_match("/i\.imgur\.com\/(.*?)\.gif$/i", $entry->getAttribute("href"))) {
223
                    Debug::log("Handling as imgur gif (->gifv)", Debug::$LOG_VERBOSE);
224
225
                    $entry->setAttribute("href",
226
                        str_replace(".gif", ".gifv", $entry->getAttribute("href")));
227
                }
228
229
                if (!$found && preg_match("/\.(gifv|mp4)$/i", $entry->getAttribute("href"))) {
230
                    Debug::log("Handling as imgur gifv", Debug::$LOG_VERBOSE);
231
232
                    $source_stream = str_replace(".gifv", ".mp4", $entry->getAttribute("href"));
233
234
                    if (strpos($source_stream, "imgur.com") !== false) {
235
                                            $poster_url = str_replace(".mp4", "h.jpg", $source_stream);
236
                    }
237
238
                    $this->handle_as_video($doc, $entry, $source_stream, $poster_url);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $poster_url does not seem to be defined for all execution paths leading up to this point.
Loading history...
239
240
                    $found = true;
241
                }
242
243
                $matches = array();
244
                if (!$found && preg_match("/youtube\.com\/v\/([\w-]+)/", $entry->getAttribute("href"), $matches) ||
245
                    preg_match("/youtube\.com\/.*?[\&\?]v=([\w-]+)/", $entry->getAttribute("href"), $matches) ||
246
                    preg_match("/youtube\.com\/watch\?v=([\w-]+)/", $entry->getAttribute("href"), $matches) ||
247
                    preg_match("/\/\/youtu.be\/([\w-]+)/", $entry->getAttribute("href"), $matches)) {
248
249
                    $vid_id = $matches[1];
250
251
                    Debug::log("Handling as youtube: $vid_id", Debug::$LOG_VERBOSE);
252
253
                    $iframe = $doc->createElement("iframe");
254
                    $iframe->setAttribute("class", "youtube-player");
255
                    $iframe->setAttribute("type", "text/html");
256
                    $iframe->setAttribute("width", "640");
257
                    $iframe->setAttribute("height", "385");
258
                    $iframe->setAttribute("src", "https://www.youtube.com/embed/$vid_id");
259
                    $iframe->setAttribute("allowfullscreen", "1");
260
                    $iframe->setAttribute("frameborder", "0");
261
262
                    $br = $doc->createElement('br');
263
                    $entry->parentNode->insertBefore($iframe, $entry);
264
                    $entry->parentNode->insertBefore($br, $entry);
265
266
                    $found = true;
267
                }
268
269
                if (!$found && preg_match("/\.(jpg|jpeg|gif|png)(\?[0-9][0-9]*)?$/i", $entry->getAttribute("href")) ||
270
                    mb_strpos($entry->getAttribute("href"), "i.reddituploads.com") !== false ||
271
                    mb_strpos($this->get_content_type($entry->getAttribute("href")), "image/") !== false) {
0 ignored issues
show
Bug introduced by
It seems like $this->get_content_type(...->getAttribute('href')) can also be of type false; however, parameter $haystack of mb_strpos() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

271
                    mb_strpos(/** @scrutinizer ignore-type */ $this->get_content_type($entry->getAttribute("href")), "image/") !== false) {
Loading history...
272
273
                    Debug::log("Handling as a picture", Debug::$LOG_VERBOSE);
274
275
                    $img = $doc->createElement('img');
276
                    $img->setAttribute("src", $entry->getAttribute("href"));
277
278
                    $br = $doc->createElement('br');
279
                    $entry->parentNode->insertBefore($img, $entry);
280
                    $entry->parentNode->insertBefore($br, $entry);
281
282
                    $found = true;
283
                }
284
285
                // imgur via link rel="image_src" href="..."
286
                if (!$found && preg_match("/imgur/", $entry->getAttribute("href"))) {
287
288
                    Debug::log("handling as imgur page/whatever", Debug::$LOG_VERBOSE);
289
290
                    $content = fetch_file_contents(["url" => $entry->getAttribute("href"),
291
                        "http_accept" => "text/*"]);
292
293
                    if ($content) {
294
                        $cdoc = new DOMDocument();
295
296
                        if (@$cdoc->loadHTML($content)) {
297
                            $cxpath = new DOMXPath($cdoc);
298
299
                            $rel_image = $cxpath->query("//link[@rel='image_src']")->item(0);
300
301
                            if ($rel_image) {
302
303
                                $img = $doc->createElement('img');
304
                                $img->setAttribute("src", $rel_image->getAttribute("href"));
305
306
                                $br = $doc->createElement('br');
307
                                $entry->parentNode->insertBefore($img, $entry);
308
                                $entry->parentNode->insertBefore($br, $entry);
309
310
                                $found = true;
311
                            }
312
                        }
313
                    }
314
                }
315
316
                // wtf is this even
317
                if (!$found && preg_match("/^https?:\/\/gyazo\.com\/([^\.\/]+$)/", $entry->getAttribute("href"), $matches)) {
318
                    $img_id = $matches[1];
319
320
                    Debug::log("handling as gyazo: $img_id", Debug::$LOG_VERBOSE);
321
322
                    $img = $doc->createElement('img');
323
                    $img->setAttribute("src", "https://i.gyazo.com/$img_id.jpg");
324
325
                    $br = $doc->createElement('br');
326
                    $entry->parentNode->insertBefore($img, $entry);
327
                    $entry->parentNode->insertBefore($br, $entry);
328
329
                    $found = true;
330
                }
331
332
                // let's try meta properties
333
                if (!$found) {
334
                    Debug::log("looking for meta og:image", Debug::$LOG_VERBOSE);
335
336
                    $content = fetch_file_contents(["url" => $entry->getAttribute("href"),
337
                        "http_accept" => "text/*"]);
338
339
                    if ($content) {
340
                        $cdoc = new DOMDocument();
341
342
                        if (@$cdoc->loadHTML($content)) {
343
                            $cxpath = new DOMXPath($cdoc);
344
345
                            $og_image = $cxpath->query("//meta[@property='og:image']")->item(0);
346
                            $og_video = $cxpath->query("//meta[@property='og:video']")->item(0);
347
348
                            if ($og_video) {
349
350
                                $source_stream = $og_video->getAttribute("content");
351
352
                                if ($source_stream) {
353
354
                                    if ($og_image) {
355
                                        $poster_url = $og_image->getAttribute("content");
356
                                    } else {
357
                                        $poster_url = false;
358
                                    }
359
360
                                    $this->handle_as_video($doc, $entry, $source_stream, $poster_url);
361
                                    $found = true;
362
                                }
363
364
                            } else if ($og_image) {
365
366
                                $og_src = $og_image->getAttribute("content");
367
368
                                if ($og_src) {
369
                                    $img = $doc->createElement('img');
370
                                    $img->setAttribute("src", $og_src);
371
372
                                    $br = $doc->createElement('br');
373
                                    $entry->parentNode->insertBefore($img, $entry);
374
                                    $entry->parentNode->insertBefore($br, $entry);
375
376
                                    $found = true;
377
                                }
378
                            }
379
                        }
380
                    }
381
                }
382
383
            }
384
385
            // remove tiny thumbnails
386
            if ($entry->hasAttribute("src")) {
387
                if ($entry->parentNode && $entry->parentNode->parentNode) {
388
                    $entry->parentNode->parentNode->removeChild($entry->parentNode);
389
                }
390
            }
391
        }
392
393
        return $found;
394
    }
395
396
    public function hook_article_filter($article) {
397
398
        if (strpos($article["link"], "reddit.com/r/") !== false) {
399
            $doc = new DOMDocument();
400
            @$doc->loadHTML($article["content"]);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for loadHTML(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

400
            /** @scrutinizer ignore-unhandled */ @$doc->loadHTML($article["content"]);

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...
401
            $xpath = new DOMXPath($doc);
402
403
            $content_link = $xpath->query("(//a[contains(., '[link]')])")->item(0);
404
405
            if ($this->host->get($this, "enable_content_dupcheck")) {
406
407
                if ($content_link) {
408
                    $content_href = $content_link->getAttribute("href");
409
                    $entry_guid = $article["guid_hashed"];
410
                    $owner_uid = $article["owner_uid"];
411
412
                    if (DB_TYPE == "pgsql") {
0 ignored issues
show
Bug introduced by
The constant DB_TYPE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
413
                        $interval_qpart = "date_entered < NOW() - INTERVAL '1 day'";
414
                    } else {
415
                        $interval_qpart = "date_entered < DATE_SUB(NOW(), INTERVAL 1 DAY)";
416
                    }
417
418
                    $sth = $this->pdo->prepare("SELECT COUNT(id) AS cid
419
						FROM ttrss_entries, ttrss_user_entries WHERE
420
							ref_id = id AND
421
							$interval_qpart AND
422
							guid != ? AND
423
							owner_uid = ? AND
424
							content LIKE ?");
425
426
                    $sth->execute([$entry_guid, $owner_uid, "%href=\"$content_href\">[link]%"]);
427
428
                    if ($row = $sth->fetch()) {
429
                        $num_found = $row['cid'];
430
431
                        if ($num_found > 0) {
432
                            $article["force_catchup"] = true;
433
                        }
434
                    }
435
                }
436
            }
437
438
            $found = $this->inline_stuff($article, $doc, $xpath);
439
440
            $node = $doc->getElementsByTagName('body')->item(0);
441
442
            if ($node && $found) {
443
                $article["content"] = $doc->saveHTML($node);
444
            } else if ($content_link) {
445
                $article = $this->readability($article, $content_link->getAttribute("href"), $doc, $xpath);
446
            }
447
        }
448
449
        return $article;
450
    }
451
452
    public function api_version() {
453
        return 2;
454
    }
455
456
    private function handle_as_video($doc, $entry, $source_stream, $poster_url = false) {
457
458
        Debug::log("handle_as_video: $source_stream", Debug::$LOG_VERBOSE);
459
460
        $video = $doc->createElement('video');
461
        $video->setAttribute("autoplay", "1");
462
        $video->setAttribute("controls", "1");
463
        $video->setAttribute("loop", "1");
464
465
        if ($poster_url) {
466
            $video->setAttribute("poster", $poster_url);
467
        }
468
469
        $source = $doc->createElement('source');
470
        $source->setAttribute("src", $source_stream);
471
        $source->setAttribute("type", "video/mp4");
472
473
        $video->appendChild($source);
474
475
        $br = $doc->createElement('br');
476
        $entry->parentNode->insertBefore($video, $entry);
477
        $entry->parentNode->insertBefore($br, $entry);
478
479
        $img = $doc->createElement('img');
480
        $img->setAttribute("src",
481
            "data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs%3D");
482
483
        $entry->parentNode->insertBefore($img, $entry);
484
    }
485
486
    public function testurl() {
487
        $url = htmlspecialchars($_REQUEST["url"]);
488
489
        header("Content-type: text/plain");
490
491
        print "URL: $url\n";
492
493
        $doc = new DOMDocument();
494
        @$doc->loadHTML("<html><body><a href=\"$url\">[link]</a></body>");
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for loadHTML(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

494
        /** @scrutinizer ignore-unhandled */ @$doc->loadHTML("<html><body><a href=\"$url\">[link]</a></body>");

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...
495
        $xpath = new DOMXPath($doc);
496
497
        $found = $this->inline_stuff([], $doc, $xpath);
498
499
        print "Inline result: $found\n";
500
501
        if (!$found) {
502
            print "\nReadability result:\n";
503
504
            $article = $this->readability([], $url, $doc, $xpath);
505
506
            print_r($article);
507
        } else {
508
            print "\nResulting HTML:\n";
509
510
            print $doc->saveHTML();
511
        }
512
    }
513
514
    private function get_header($url, $useragent = SELF_USER_AGENT, $header) {
515
        $ret = false;
516
517
        if (function_exists("curl_init") && !defined("NO_CURL")) {
518
            $ch = curl_init($url);
519
            curl_setopt($ch, CURLOPT_TIMEOUT, 5);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_setopt() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

519
            curl_setopt(/** @scrutinizer ignore-type */ $ch, CURLOPT_TIMEOUT, 5);
Loading history...
520
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
521
            curl_setopt($ch, CURLOPT_HEADER, true);
522
            curl_setopt($ch, CURLOPT_NOBODY, true);
523
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, !ini_get("open_basedir"));
524
            curl_setopt($ch, CURLOPT_USERAGENT, $useragent);
525
526
            @curl_exec($ch);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for curl_exec(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

526
            /** @scrutinizer ignore-unhandled */ @curl_exec($ch);

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...
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_exec() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

526
            @curl_exec(/** @scrutinizer ignore-type */ $ch);
Loading history...
527
            $ret = curl_getinfo($ch, $header);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_getinfo() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

527
            $ret = curl_getinfo(/** @scrutinizer ignore-type */ $ch, $header);
Loading history...
528
        }
529
530
        return $ret;
531
    }
532
533
    private function get_content_type($url, $useragent = SELF_USER_AGENT) {
534
        return $this->get_header($url, $useragent, CURLINFO_CONTENT_TYPE);
535
    }
536
537
    private function get_location($url, $useragent = SELF_USER_AGENT) {
538
        return $this->get_header($url, $useragent, CURLINFO_EFFECTIVE_URL);
539
    }
540
541
    /**
542
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
543
     */
544
    private function readability($article, $url, $doc, $xpath, $debug = false) {
0 ignored issues
show
Unused Code introduced by
The parameter $debug is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

544
    private function readability($article, $url, $doc, $xpath, /** @scrutinizer ignore-unused */ $debug = false) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $doc is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

544
    private function readability($article, $url, /** @scrutinizer ignore-unused */ $doc, $xpath, $debug = false) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $xpath is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

544
    private function readability($article, $url, $doc, /** @scrutinizer ignore-unused */ $xpath, $debug = false) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
545
546
        if (!defined('NO_CURL') && function_exists("curl_init") && $this->host->get($this, "enable_readability") &&
547
            mb_strlen(strip_tags($article["content"])) <= 150) {
548
549
            // do not try to embed posts linking back to other reddit posts
550
            // readability.php requires PHP 5.6
551
            if ($url && strpos($url, "reddit.com") === false && version_compare(PHP_VERSION, '5.6.0', '>=')) {
552
553
                /* link may lead to a huge video file or whatever, we need to check content type before trying to
554
				parse it which p much requires curl */
555
556
                $useragent_compat = "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)";
557
                $content_type = $this->get_content_type($url, $useragent_compat);
558
559
                if ($content_type && strpos($content_type, "text/html") !== false) {
560
561
                    foreach ($this->host->get_hooks(PluginHost::HOOK_GET_FULL_TEXT) as $p) {
562
                        $extracted_content = $p->hook_get_full_text($url);
563
564
                        if ($extracted_content) {
565
                            $article["content"] = $extracted_content;
566
                            break;
567
                        }
568
                    }
569
                }
570
            }
571
        }
572
573
        return $article;
574
    }
575
}
576