Completed
Push — master ( c636bf...a4295f )
by Angus
03:45
created

Batoto::isValidTitleURL()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 1
dl 0
loc 5
ccs 0
cts 0
cp 0
crap 6
rs 9.4285
c 0
b 0
f 0
1
<?php declare(strict_types=1); defined('BASEPATH') OR exit('No direct script access allowed');
2
3
abstract class Site_Model extends CI_Model {
4 102
	public function __construct() {
5 102
		parent::__construct();
6
7 102
		$this->load->database();
8 102
	}
9
10
	abstract public function getFullTitleURL(string $title_url) : string;
11
12
	abstract public function getChapterData(string $title_url, string $chapter) : array;
13
14
	//TODO: When ci-phpunit-test supports PHP Parser 3.x, add " : ?array"
15
	abstract public function getTitleData(string $title_url);
16
17
	abstract public function isValidTitleURL(string $title_url) : bool;
18
	abstract public function isValidChapter(string $chapter) : bool;
19
20 14
	final protected function get_content(string $url, string $cookie_string = "", string $cookiejar_path = "", bool $follow_redirect = FALSE) {
21 14
		$ch = curl_init();
22 14
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
23 14
		curl_setopt($ch, CURLOPT_ENCODING , "gzip");
24
		//curl_setopt($ch, CURLOPT_VERBOSE, 1);
25 14
		curl_setopt($ch, CURLOPT_HEADER, 1);
26
27 14
		if($follow_redirect)        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
28
29 14
		if(!empty($cookie_string))  curl_setopt($ch, CURLOPT_COOKIE, $cookie_string);
30 14
		if(!empty($cookiejar_path)) curl_setopt($ch, CURLOPT_COOKIEFILE, $cookiejar_path);
31
32
		//Some sites check the useragent for stuff, use a pre-defined user-agent to avoid stuff.
33 14
		curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2824.0 Safari/537.36');
34
35
		//TODO: Check in a while if this being enabled still causes issues
36
		//curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); //FIXME: This isn't safe, but it allows us to grab SSL URLs
37
38 14
		curl_setopt($ch, CURLOPT_URL, $url);
39 14
		$response = curl_exec($ch);
40 14
		if($response === FALSE) {
41
			log_message('error', "curl failed with error: ".curl_errno($ch)." | ".curl_error($ch));
42
			return FALSE;
43
		}
44
45 14
		$status_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
46 14
		$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
47 14
		$header      = http_parse_headers(substr($response, 0, $header_size));
48 14
		$body        = substr($response, $header_size);
49 14
		curl_close($ch);
50
51
		return [
52 14
			'headers'     => $header,
53 14
			'status_code' => $status_code,
54 14
			'body'        => $body
55
		];
56
	}
57
58
	/**
59
	 * @param array  $content
60
	 * @param string $site
61
	 * @param string $title_url
62
	 * @param string $node_title_string
63
	 * @param string $node_row_string
64
	 * @param string $node_latest_string
65
	 * @param string $node_chapter_string
66
	 * @param string $failure_string
67
	 *
68
	 * @return DOMElement[]|false
69
	 */
70 7
	final protected function parseTitleDataDOM(
71
		array $content, string $site, string $title_url,
72
		string $node_title_string, string $node_row_string,
73
		string $node_latest_string, string $node_chapter_string,
74
		string $failure_string = "") {
75
		//list('headers' => $headers, 'status_code' => $status_code, 'body' => $data) = $content; //TODO: PHP 7.1
76 7
		$headers     = $content['headers'];
0 ignored issues
show
Unused Code introduced by
$headers 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...
77 7
		$status_code = $content['status_code'];
78 7
		$data        = $content['body'];
79
80 7
		if(!($status_code >= 200 && $status_code < 300)) {
81 3
			log_message('error', "{$site} : {$title_url} | Bad Status Code ({$status_code})");
82 4
		} else if(empty($data)) {
83
			log_message('error', "{$site} : {$title_url} | Data is empty? (Status code: {$status_code})");
84 4
		} else if($failure_string !== "" && strpos($data, $failure_string) !== FALSE) {
85 1
			log_message('error', "{$site} : {$title_url} | Failure string matched");
86
		} else {
87 3
			$data = $this->cleanTitleDataDOM($data); //This allows us to clean the DOM prior to parsing. It's faster to grab the only part we need THEN parse it.
88
89 3
			$dom = new DOMDocument();
90 3
			libxml_use_internal_errors(TRUE);
91 3
			$dom->loadHTML($data);
92 3
			libxml_use_internal_errors(FALSE);
93
94 3
			$xpath = new DOMXPath($dom);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 7 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
95 3
			$nodes_title = $xpath->query($node_title_string);
96 3
			$nodes_row   = $xpath->query($node_row_string);
97 3
			if($nodes_title->length === 1 && $nodes_row->length === 1) {
98 3
				$firstRow      = $nodes_row->item(0);
99 3
				$nodes_latest  = $xpath->query($node_latest_string,  $firstRow);
100 3
				$nodes_chapter = $xpath->query($node_chapter_string, $firstRow);
101
102 3
				if($nodes_latest->length === 1 && $nodes_chapter->length === 1) {
103
					return [
104 3
						'nodes_title'   => $nodes_title->item(0),
105 3
						'nodes_latest'  => $nodes_latest->item(0),
106 3
						'nodes_chapter' => $nodes_chapter->item(0)
107
					];
108
				} else {
109
					log_message('error', "{$site} : {$title_url} | Invalid amount of nodes (LATEST: {$nodes_latest->length} | CHAPTER: {$nodes_chapter->length})");
110
				}
111
			} else {
112
				log_message('error', "{$site} : {$title_url} | Invalid amount of nodes (TITLE: {$nodes_title->length} | ROW: {$nodes_row->length})");
113
			}
114
		}
115 4
		return FALSE;
116
	}
117
118 3
	public function cleanTitleDataDOM(string $data) : string {
119 3
		return $data;
120
	}
121
}
122
class Sites_Model extends CI_Model {
123
	public $MangaFox;
124
	public $MangaHere;
125
	public $Batoto;
126
	public $DynastyScans;
127
	public $MangaPanda;
128
	public $MangaStream;
129
	public $WebToons;
130
	public $KissManga;
131
	public $KireiCake;
132
	public $GameOfScanlation;
133
	public $MangaCow;
134
	public $SeaOtterScans;
135
	public $HelveticaScans;
136
	public $SenseScans;
137
138 102
	public function __construct() {
139 102
		parent::__construct();
140
141 102
		$this->MangaFox         = new MangaFox();
142 102
		$this->MangaHere        = new MangaHere();
143 102
		$this->Batoto           = new Batoto();
144 102
		$this->DynastyScans     = new DynastyScans();
145 102
		$this->MangaPanda       = new MangaPanda();
146 102
		$this->MangaStream      = new MangaStream();
147 102
		$this->WebToons         = new WebToons();
148 102
		$this->KissManga        = new KissManga();
149 102
		$this->KireiCake        = new KireiCake();
150 102
		$this->GameOfScanlation = new GameOfScanlation();
151 102
		$this->MangaCow         = new MangaCow();
152 102
		$this->SeaOtterScans    = new SeaOtterScans();
153 102
		$this->HelveticaScans   = new HelveticaScans();
154 102
		$this->SenseScans       = new SenseScans();
155 102
	}
156
}
157
158
class MangaFox extends Site_Model {
159 2
	public function getFullTitleURL(string $title_url) : string {
160 2
		return "http://mangafox.me/manga/{$title_url}/";
161
	}
162
163
	public function isValidTitleURL(string $title_url) : bool {
164
		$success = (bool) preg_match('/^[a-z0-9_]+$/', $title_url);
165
		if(!$success) log_message('error', "Invalid Title URL (MangaFox): {$title_url}");
166
		return $success;
167
	}
168
	public function isValidChapter(string $chapter) : bool {
169
		$success = (bool) preg_match('/^(?:v[0-9a-zA-Z]+\/)?c[0-9\.]+$/', $chapter);
170
		if(!$success) log_message('error', 'Invalid Chapter (MangaFox): '.$chapter);
171
		return $success;
172
	}
173
174
	public function getChapterData(string $title_url, string $chapter) : array {
175
		return [
176
			'url'    => "http://mangafox.me/manga/{$title_url}/{$chapter}/",
177
			'number' => $chapter
178
		];
179
	}
180
181 2
	public function getTitleData(string $title_url) {
182 2
		$titleData = [];
183
184 2
		$fullURL = $this->getFullTitleURL($title_url);
185 2
		$content = $this->get_content($fullURL);
186
187 2
		$data = $this->parseTitleDataDOM(
188
			$content,
0 ignored issues
show
Security Bug introduced by
It seems like $content defined by $this->get_content($fullURL) on line 185 can also be of type false; however, Site_Model::parseTitleDataDOM() does only seem to accept array, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
189 2
			'MangaFox',
190
			$title_url,
191 2
			"//meta[@property='og:title']/@content",
192 2
			"//body/div[@id='page']/div[@class='left']/div[@id='chapters']/ul[1]/li[1]",
193 2
			"div/span[@class='date']",
194 2
			"div/h3/a"
195
		);
196 2
		if($data) {
197 1
			$titleData['title'] = html_entity_decode(substr($data['nodes_title']->textContent, 0, -6));
198
199 1
			$link = preg_replace('/^(.*\/)(?:[0-9]+\.html)?$/', '$1', (string) $data['nodes_chapter']->getAttribute('href'));
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 24 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
200 1
			$chapterURLSegments = explode('/', $link);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 10 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
201 1
			$titleData['latest_chapter'] = $chapterURLSegments[5] . (isset($chapterURLSegments[6]) && !empty($chapterURLSegments[6]) ? "/{$chapterURLSegments[6]}" : "");
202 1
			$titleData['last_updated'] =  date("Y-m-d H:i:s", strtotime((string) $data['nodes_latest']->nodeValue));
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 3 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
203
		}
204
205 2
		return (!empty($titleData) ? $titleData : NULL);
206
	}
207
}
208
209
class MangaHere extends Site_Model {
210 2
	public function getFullTitleURL(string $title_url) : string {
211 2
		return "http://www.mangahere.co/manga/{$title_url}/";
212
	}
213
214
	public function isValidTitleURL(string $title_url) : bool {
215
		$success = (bool) preg_match('/^[a-z0-9_]+$/', $title_url);
216
		if(!$success) log_message('error', "Invalid Title URL (MangaFox): {$title_url}");
217
		return $success;
218
	}
219
	public function isValidChapter(string $chapter) : bool {
220
		$success = (bool) preg_match('/^(?:v[0-9]+\/)?c[0-9]+(?:\.[0-9]+)?$/', $chapter);
221
		if(!$success) log_message('error', 'Invalid Chapter (MangaFox): '.$chapter);
222
		return $success;
223
	}
224
225
	public function getChapterData(string $title, string $chapter) : array {
226
		return [
227
			'url'    => "http://www.mangahere.co/manga/{$title}/{$chapter}/",
228
			'number' => $chapter
229
		];
230
	}
231
232 2
	public function getTitleData(string $title_url) {
233 2
		$titleData = [];
234
235 2
		$fullURL = $this->getFullTitleURL($title_url);
236 2
		$content = $this->get_content($fullURL);
237
238 2
		$data = $this->parseTitleDataDOM(
239
			$content,
0 ignored issues
show
Security Bug introduced by
It seems like $content defined by $this->get_content($fullURL) on line 236 can also be of type false; however, Site_Model::parseTitleDataDOM() does only seem to accept array, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
240 2
			'MangaHere',
241
			$title_url,
242 2
			"//meta[@property='og:title']/@content",
243 2
			"//body/section/article/div/div[@class='manga_detail']/div[@class='detail_list']/ul[1]/li[1]",
244 2
			"span[@class='right']",
245 2
			"span[@class='left']/a",
246 2
			"<div class=\"error_text\">Sorry, the page you have requested can’t be found."
247
		);
248 2
		if($data) {
249 1
			$titleData['title'] = $data['nodes_title']->textContent;
250
251 1
			$link = preg_replace('/^(.*\/)(?:[0-9]+\.html)?$/', '$1', (string) $data['nodes_chapter']->getAttribute('href'));
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 24 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
252 1
			$chapterURLSegments = explode('/', $link);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 10 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
253 1
			$titleData['latest_chapter'] = $chapterURLSegments[5] . (isset($chapterURLSegments[6]) && !empty($chapterURLSegments[6]) ? "/{$chapterURLSegments[6]}" : "");
254 1
			$titleData['last_updated'] =  date("Y-m-d H:i:s", strtotime((string) $data['nodes_latest']->nodeValue));
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 3 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
255
		}
256
257 2
		return (!empty($titleData) ? $titleData : NULL);
258
	}
259
}
260
261
class Batoto extends Site_Model {
262
	//Batoto is a bit tricky to track. Unlike MangaFox and MangaHere, it doesn't store anything in the title_url, which means we have to get the data via other methods.
263
	//One problem we have though, is the tracker must support multiple sites, so this means we need to do some weird things to track Batoto.
264
	//title_url is stored like: "TITLE_URL:--:LANGUAGE"
265
	//chapter_urls are stored like "CHAPTER_ID:--:CHAPTER_NUMBER"
266
267 1
	public function getFullTitleURL(string $title_string) : string {
268
		//FIXME: This does not point to the language specific title page. Should ask if it is possible to set LANG as arg?
269
		//FIXME: This points to a generic URL which will redirect according to the ID. Preferably we'd try and get the exact URL from the title, but we can't pass it here.
270 1
		$title_parts = explode(':--:', $title_string);
271 1
		return "http://bato.to/comic/_/comics/-r".$title_parts[0];
272
	}
273
274
	public function isValidTitleURL(string $title_url) : bool {
275
		$success = (bool) preg_match('/^[0-9]+:--:(?:English|Spanish|French|German|Portuguese|Turkish|Indonesian|Greek|Filipino|Italian|Polish|Thai|Malay|Hungarian|Romanian|Arabic|Hebrew|Russian|Vietnamese|Dutch)$/', $title_url);
276
		if(!$success) log_message('error', "Invalid Title URL (Batoto): {$title_url}");
277
		return $success;
278
	}
279
	public function isValidChapter(string $chapter) : bool {
280
		//FIXME: We're not validating the chapter name since we don't know what all the possible valid characters can be
281
		//       Preferably we'd just use /^[0-9a-z]+:--:(v[0-9]+\/)?c[0-9]+(\.[0-9]+)?$/
282
283
		$success = (bool) preg_match('/^[0-9a-z]+:--:.+$/', $chapter);
284
		if(!$success) log_message('error', 'Invalid Chapter (Batoto): '.$chapter);
285
		return $success;
286
	}
287
288 View Code Duplication
	public function getChapterData(string $title_string, string $chapter) : array {
289
		//$title_string isn't used here.
290
291
		$chapter_parts = explode(':--:', $chapter);
292
		return [
293
			'url'    => "http://bato.to/reader#" . $chapter_parts[0],
294
			'number' => $chapter_parts[1]
295
		];
296
	}
297
298 1
	public function getTitleData(string $title_url) {
299 1
		$titleData = [];
300
301 1
		$title_parts = explode(':--:', $title_url);
302 1
		$fullURL     = $this->getFullTitleURL($title_url);
303 1
		$lang        = $title_parts[1]; //TODO: Validate title_lang from array?
304
305
306
		//Bato.to is annoying and locks stuff behind auth. See: https://github.com/DakuTree/manga-tracker/issues/14#issuecomment-233830855
307
		$cookies = [
308 1
			"lang_option={$lang}",
309 1
			"member_id={$this->config->item('batoto_cookie_member_id')}",
310 1
			"pass_hash={$this->config->item('batoto_cookie_pass_hash')}"
311
		];
312 1
		$content = $this->get_content($fullURL, implode("; ", $cookies), "", TRUE);
313
314 1
		$data = $this->parseTitleDataDOM(
315
			$content,
0 ignored issues
show
Security Bug introduced by
It seems like $content defined by $this->get_content($full...', $cookies), '', TRUE) on line 312 can also be of type false; however, Site_Model::parseTitleDataDOM() does only seem to accept array, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
316 1
			'Batoto',
317
			$title_url,
318 1
			"//h1[@class='ipsType_pagetitle']",
319 1
			"//table[contains(@class, 'chapters_list')]/tbody/tr[2]",
320 1
			"td[last()]",
321 1
			"td/a[contains(@href,'reader')]",
322 1
			">Register now<"
323
		);
324 1
		if($data) {
325
			$titleData['title'] = html_entity_decode(trim($data['nodes_title']->textContent));
326
327
			///^(?:Vol\.(?<volume>\S+) )?(?:Ch.(?<chapter>[^\s:]+)(?:\s?-\s?(?<extra>[0-9]+))?):?.*/
328
			preg_match('/^(?:Vol\.(?<volume>\S+) )?(?:Ch.(?<chapter>[^\s:]+)(?:\s?-\s?(?<extra>[0-9]+))?):?.*/', trim($data['nodes_chapter']->nodeValue), $text);
329
			$titleData['latest_chapter'] = substr($data['nodes_chapter']->getAttribute('href'), 22) . ':--:' . ((!empty($text['volume']) ? 'v'.$text['volume'].'/' : '') . 'c'.$text['chapter'] . (!empty($text['extra']) ? '-'.$text['extra'] : ''));
330
331
			$dateString = $data['nodes_latest']->nodeValue;
332
			if($dateString == 'An hour ago') {
333
				$dateString = '1 hour ago';
334
			}
335
			$titleData['last_updated']   = date("Y-m-d H:i:s", strtotime(preg_replace('/ (-|\[A\]).*$/', '', $dateString)));
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned correctly; expected 1 space but found 3 spaces

This check looks for improperly formatted assignments.

Every assignment must have exactly one space before and one space after the equals operator.

To illustrate:

$a = "a";
$ab = "ab";
$abc = "abc";

will have no issues, while

$a   = "a";
$ab  = "ab";
$abc = "abc";

will report issues in lines 1 and 2.

Loading history...
336
		}
337
338 1
		return (!empty($titleData) ? $titleData : NULL);
339
	}
340
341
	public function cleanTitleDataDOM(string $data) : string {
342
		$data = preg_replace('/^[\s\S]+<!-- ::: CONTENT ::: -->/', '<!-- ::: CONTENT ::: -->', $data);
343
		$data = preg_replace('/<!-- end mainContent -->[\s\S]+$/', '<!-- end mainContent -->', $data);
344
		$data = preg_replace('/<div id=\'commentsStart\' class=\'ipsBox\'>[\s\S]+$/', '</div></div><!-- end mainContent -->', $data);
345
346
		return $data;
347
	}
348
}
349
350
//FIXME: Convert DynastyScans to new format.
351
class DynastyScans extends Site_Model {
352
	//FIXME: This has some major issues. SEE: https://github.com/DakuTree/manga-tracker/issues/58
353
	public function getFullTitleURL(string $title_string) : string {
354
		$title_parts = explode(':--:', $title_string);
355
		$url_type = ($title_parts[1] == '0' ? 'series' : 'chapters');
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
356
357
		return 'http://dynasty-scans.com/'.$url_type.'/'.$title_parts[0];
358
	}
359
360
	public function isValidTitleURL(string $title_url) : bool {
361
		$success = (bool) preg_match('/^[a-z0-9_]+:--:(?:0|1)$/', $title_url);
362
		if(!$success) log_message('error', "Invalid Title URL (DynastyScans): {$title_url}");
363
		return $success;
364
	}
365
	public function isValidChapter(string $chapter) : bool {
366
		$success = (bool) preg_match('/^[0-9a-z_]+$/', $chapter);
367
		if(!$success) log_message('error', 'Invalid Chapter (DynastyScans): '.$chapter);
368
		return $success;
369
	}
370
371
	public function getChapterData(string $title_string, string $chapter) : array {
372
		$title_parts = explode(':--:', $title_string);
373
		/* Known chapter url formats (# is numbers):
374
		       chapters_#A_#B - Ch#A-#B
375
		       ch_#A          - Ch#A
376
		       ch_#A_#B       - Ch#A.#B
377
		       <NOTHING>      - Oneshot (This is passed as "oneshot")
378
		*/
379
380
		$chapterData = [
381
			'url'    => 'http://dynasty-scans.com/chapters/' . $title_parts[0].'_'.$chapter,
382
			'number' => ''
383
		];
384
385
		if($chapter == 'oneshot') {
386
			$chapterData['number'] = 'oneshot';
387
		} else {
388
			$chapter = preg_replace("/^([a-zA-Z]+)/", '$1_', $chapter);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 9 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
389
			$chapterSegments = explode('_', $chapter);
390
			switch($chapterSegments[0]) {
391
				case 'ch':
392
					$chapterData['number'] = 'c'.$chapterSegments[1].(isset($chapterSegments[2]) && !empty($chapterSegments[2]) ? '.'.$chapterSegments[2] : '');
393
					break;
394
395
				case 'chapters':
396
					//This is barely ever used, but I have seen it.
397
					$chapterData['number'] = 'c'.$chapterSegments[1].'-'.$chapterSegments[2];
398
					break;
399
400
				default:
401
					//TODO: FALLBACK, ALERT ADMIN?
402
					$chapterData['number'] = $chapter;
403
					break;
404
			}
405
		}
406
		return $chapterData;
407
	}
408
409 1
	public function getTitleData(string $title_string) {
410 1
		$title_parts = explode(':--:', $title_string);
411 1
		$title_url   = $title_parts[0];
412
413 1
		$titleData = [];
414
		//FIXME: Using regex here is probably a terrible idea, but we're doing it anyway....
415
		//FIXME (ASAP): All the regex here should be checked to see if it even returns something, and we should probably error if possible.
416 1
		if($title_parts[1] == '0') {
417 1
			$content = $this->get_content('http://dynasty-scans.com/series/'.$title_url);
418 1
			$data = $content['body'];
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
419
420 1
			preg_match('/<b>.*<\/b>/', $data, $matchesT);
421 1
			preg_match('/\/doujins\/[^"]+">(.+)?(?=<\/a>)<\/a>/', $data, $matchesD);
422 1
			$titleData['title'] = (!empty($matchesD) ? (substr($matchesD[1], 0, -7) !== 'Original' ? substr($matchesD[1], 0, -7).' - ' : '') : '') . substr($matchesT[0], 3, -4);
423
424 1
			$data = preg_replace('/^[\S\s]*(<dl class=\'chapter-list\'>[\S\s]*<\/dl>)[\S\s]*$/', '$1', $data);
425 1
			preg_match_all('/<dd>[\s\S]+?(?=<\/dd>)<\/dd>/', $data, $matches);
426 1
			$latest_chapter_html = array_pop($matches[0]);
427
428 1
			preg_match('/\/chapters\/([^"]+)/', $latest_chapter_html, $matches);
429 1
			$titleData['latest_chapter'] = substr($matches[1], strlen($title_url)+1);
430
			//FIXME: THIS IS A TEMP FIX, SEE https://github.com/DakuTree/manga-tracker/issues/58
431 1
			if(!$titleData['latest_chapter']) {
432
				log_message('error', 'DynastyScans::getTitleData cannot parse title properly as it contains oneshot. || URL: '.$title_url);
433
				return NULL;
434
			}
435
436 1
			preg_match('/<small>released (.*)<\/small>/', $latest_chapter_html, $matches);
437 1
			$titleData['last_updated']   = date("Y-m-d H:i:s", strtotime(str_replace('\'', '', $matches[1])));
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned correctly; expected 1 space but found 3 spaces

This check looks for improperly formatted assignments.

Every assignment must have exactly one space before and one space after the equals operator.

To illustrate:

$a = "a";
$ab = "ab";
$abc = "abc";

will have no issues, while

$a   = "a";
$ab  = "ab";
$abc = "abc";

will report issues in lines 1 and 2.

Loading history...
438
		} elseif($title_parts[1] == '1') {
439
			$content = $this->get_content('http://dynasty-scans.com/chapters/'.$title_url);
440
			$data = $content['body'];
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
441
442
			preg_match('/<b>.*<\/b>/', $data, $matchesT);
443
			preg_match('/\/doujins\/[^"]+">(.+)?(?=<\/a>)<\/a>/', $data, $matchesD);
444
			$titleData['title'] = (!empty($matchesD) ? ($matchesD[1] !== 'Original' ? $matchesD[1].' - ' : '') : '') . substr($matchesT[0], 3, -4);
445
446
			$titleData['latest_chapter'] = 'oneshot'; //This will never change
447
448
			preg_match('/<i class="icon-calendar"><\/i> (.*)<\/span>/', $data, $matches);
449
			$titleData['last_updated']   = date("Y-m-d H:i:s", strtotime($matches[1]));
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned correctly; expected 1 space but found 3 spaces

This check looks for improperly formatted assignments.

Every assignment must have exactly one space before and one space after the equals operator.

To illustrate:

$a = "a";
$ab = "ab";
$abc = "abc";

will have no issues, while

$a   = "a";
$ab  = "ab";
$abc = "abc";

will report issues in lines 1 and 2.

Loading history...
450
451
			//Oneshots are special, and really shouldn't need to be re-tracked
452
			//FIXME: We need to have a specific "no-track" complete param.
453
			$titleData['complete'] = 'Y';
454
		} else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
455
			//FIXME: WTF?
456
		}
457 1
		return (!empty($titleData) ? $titleData : NULL);
458
	}
459
}
460
461
class MangaPanda extends Site_Model {
462 2
	public function getFullTitleURL(string $title_url) : string {
463 2
		return "http://www.mangapanda.com/{$title_url}";
464
	}
465
466
	public function getChapterData(string $title_url, string $chapter) : array {
467
		return [
468
			'url'    => "http://www.mangapanda.com/{$title_url}/{$chapter}/",
469
			'number' => 'c'.$chapter
470
		];
471
	}
472
473
	public function isValidTitleURL(string $title_url) : bool {
474
		//NOTE: MangaPanda has manga pages under the root URL, so we need to filter out pages we know that aren't manga.
475
		$success = (bool) preg_match('/^(?!(?:latest|search|popular|random|alphabetical|privacy)$)([a-z0-9-]+)$/', $title_url);
476
		if(!$success) log_message('error', "Invalid Title URL (MangaPanda): {$title_url}");
477
		return $success;
478
	}
479
	public function isValidChapter(string $chapter) : bool {
480
		$success = (bool) preg_match('/^[0-9]+$/', $chapter);
481
		if(!$success) log_message('error', 'Invalid Chapter (MangaPanda): '.$chapter);
482
		return $success;
483
	}
484
485 2 View Code Duplication
	public function getTitleData(string $title_url) {
486 2
		$titleData = [];
487
488 2
		$fullURL = $this->getFullTitleURL($title_url);
489 2
		$content = $this->get_content($fullURL);
490
491 2
		$data = $this->parseTitleDataDOM(
492
			$content,
0 ignored issues
show
Security Bug introduced by
It seems like $content defined by $this->get_content($fullURL) on line 489 can also be of type false; however, Site_Model::parseTitleDataDOM() does only seem to accept array, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
493 2
			'MangaPanda',
494
			$title_url,
495 2
			"//h2[@class='aname']",
496 2
			"(//table[@id='listing']/tr)[last()]",
497 2
			"td[2]",
498 2
			"td[1]/a"
499
		);
500 2
		if($data) {
501 1
			$titleData['title'] = $data['nodes_title']->textContent;
502
503 1
			$titleData['latest_chapter'] = preg_replace('/^.*\/([0-9]+)$/', '$1', (string) $data['nodes_chapter']->getAttribute('href'));
504
505 1
			$titleData['last_updated'] =  date("Y-m-d H:i:s", strtotime((string) $data['nodes_latest']->nodeValue));
506
		}
507
508 2
		return (!empty($titleData) ? $titleData : NULL);
509
	}
510
}
511
512
class MangaStream extends Site_Model {
513
	public function getFullTitleURL(string $title_url) : string {
514
		return "https://mangastream.com/manga/{$title_url}/";
515
	}
516
517
	public function isValidTitleURL(string $title_url) : bool {
518
		$success = (bool) preg_match('/^[a-z0-9_]+$/', $title_url);
519
		if(!$success) log_message('error', "Invalid Title URL (MangaStream): {$title_url}");
520
		return $success;
521
	}
522
	public function isValidChapter(string $chapter) : bool {
523
		$success = (bool) preg_match('/^(.*?)\/[0-9]+$/', $chapter);
524
		if(!$success) log_message('error', 'Invalid Chapter (MangaStream): '.$chapter);
525
		return $success;
526
	}
527
528
	public function getChapterData(string $title_url, string $chapter) : array {
529
		return [
530
			'url'    => "https://mangastream.com/r/{$title_url}/{$chapter}",
531
			'number' => 'c'.explode('/', $chapter)[0]
532
		];
533
	}
534
535 View Code Duplication
	public function getTitleData(string $title_url) {
536
		$titleData = [];
537
538
		$fullURL = $this->getFullTitleURL($title_url);
539
		$content = $this->get_content($fullURL);
540
541
		$data = $this->parseTitleDataDOM(
542
			$content,
0 ignored issues
show
Security Bug introduced by
It seems like $content defined by $this->get_content($fullURL) on line 539 can also be of type false; however, Site_Model::parseTitleDataDOM() does only seem to accept array, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
543
			'MangaStream',
544
			$title_url,
545
			"//div[contains(@class, 'content')]/div[1]/h1",
546
			"//div[contains(@class, 'content')]/div[1]/table/tr[2]",
547
			"td[2]",
548
			"td[1]/a",
549
			"<h1>Page Not Found</h1>"
550
		);
551
		if($data) {
552
			$titleData['title'] = $data['nodes_title']->textContent;
553
554
			$titleData['latest_chapter'] = preg_replace('/^.*\/(.*?\/[0-9]+)\/[0-9]+$/', '$1', (string) $data['nodes_chapter']->getAttribute('href'));
555
556
			$titleData['last_updated'] =  date("Y-m-d H:i:s", strtotime((string) $data['nodes_latest']->nodeValue));
557
		}
558
559
		return (!empty($titleData) ? $titleData : NULL);
560
	}
561
}
562
563
class WebToons extends Site_Model {
564
	/* Webtoons.com has a very weird and pointless URL format.
565
	   TITLE URL:   /#LANG#/#GENRE#/#TITLE#/list?title_no=#TITLEID#
566
	   RSS URL:     /#LANG#/#GENRE#/#TITLE#/rss?title_no=#TITLEID#
567
	   CHAPTER URL: /#LANG#/#GENRE#/#TITLE#/#CHAPTER#/viewer?title_no=#TITLEID#&episode_no=#CHAPTERID#
568
569
	   For both the title and chapter URLs, only the TITLEID and CHAPTERID are needed. Everything else can be anything at all (Well, alphanumeric at least).
570
	   The RSS URL however, requires everything to be exactly correct. I have no idea why this is, but it does mean we need to store all that info too.
571
	   We <could> not use the RSS url, and just parse via the title url, but rss is much better in the long run as it shouldn't change much.
572
573
	   FORMATS:
574
	   TITLE_URL: ID:--:LANG:--:TITLE:--:GENRE
575
	   CHAPTER:   ID:--:CHAPTER_N
576
	*/
577
	//private $validLang = ['en', 'zh-hant', 'zh-hans', 'th', 'id'];
578
579
	public function getFullTitleURL(string $title_url) : string {
580
		$title_parts = explode(':--:', $title_url);
581
		return "http://www.webtoons.com/{$title_parts[1]}/{$title_parts[3]}/{$title_parts[2]}/list?title_no={$title_parts[0]}/";
582
	}
583
584
	public function isValidTitleURL(string $title_url) : bool {
585
		$success = (bool) preg_match('/^[0-9]+:--:(?:en|zh-hant|zh-hans|th|id):--:[a-z0-9-]+:--:(?:drama|fantasy|comedy|action|slice-of-life|romance|superhero|thriller|sports|sci-fi)$/', $title_url);
586
		if(!$success) log_message('error', "Invalid Title URL (WebToons): {$title_url}");
587
		return $success;
588
	}
589
	public function isValidChapter(string $chapter) : bool {
590
		$success = (bool) preg_match('/^[0-9]+:--:.*$/', $chapter);
591
		if(!$success) log_message('error', 'Invalid Chapter (WebToons): '.$chapter);
592
		return $success;
593
	}
594
595
	public function getChapterData(string $title_url, string $chapter) : array {
596
		$title_parts   = explode(':--:', $title_url);
597
		$chapter_parts = explode(':--:', $chapter);
598
599
		return [
600
			'url'    => "http://www.webtoons.com/{$title_parts[1]}/{$title_parts[3]}/{$title_parts[2]}/{$chapter_parts[1]}/viewer?title_no={$title_parts[0]}&episode_no={$chapter_parts[0]}",
601
			'number' => $chapter_parts[1] //TODO: Possibly replace certain formats in here? Since webtoons doesn't have a standard chapter format
602
		];
603
	}
604
605 1
	public function getTitleData(string $title_url) {
606 1
		$titleData = [];
607
608 1
		$title_parts = explode(':--:', $title_url);
609 1
		$fullURL = "http://www.webtoons.com/{$title_parts[1]}/{$title_parts[3]}/{$title_parts[2]}/rss?title_no={$title_parts[0]}";
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 5 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
610
611 1
		$content = $this->get_content($fullURL);
612 1
		$data = $content['body'];
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
613 1
		if($data !== 'Can\'t find the manga series.') { //FIXME: We should check for he proper error here.
614 1
			$xml = simplexml_load_string($data) or die("Error: Cannot create object");
615 1
			if(isset($xml->{'channel'}->item[0])) {
616 1
				$titleData['title'] = trim((string) $xml->{'channel'}->title);
617
618 1
				$chapterURLSegments = explode('/', ((string) $xml->{'channel'}->item[0]->link));
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 10 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
619 1
				$titleData['latest_chapter'] = preg_replace('/^.*?([0-9]+)$/', '$1', $chapterURLSegments[7]) . ':--:' . $chapterURLSegments[6];
620 1
				$titleData['last_updated'] =  date("Y-m-d H:i:s", strtotime((string) $xml->{'channel'}->item[0]->pubDate));
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 3 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
621
			}
622
		} else {
623
			log_message('error', "Series missing? (WebToons): {$title_url}");
624
			return NULL;
625
		}
626
627 1
		return (!empty($titleData) ? $titleData : NULL);
628
	}
629
}
630
631
class KissManga extends Site_Model {
632
	/* This site is a massive pain in the ass. The only reason I'm supporting it is it's one of the few aggregator sites which actually support more risqué manga.
633
	   The main problem with this site is it has some form of bot protection. To view any part of the site normally, you need a cookie set by the bot protection.
634
635
	   To generate this cookie, we need three variables. Two are static, but the other is generated by randomly generated JS on the page.
636
	   The randomly generated JS is the troublesome part. We can't easily parse this with PHP. Both V8JS & SpiderMonkey refuse to build properly for me, so that rules that out.
637
	   The other option is using regex, but that is a rabbit hole I don't want to touch with a ten-foot pole.
638
639
	   To make the entire site work, I've built a python script to handle grabbing this cookie. This is grabbed & updated at the same time the manga are updated. The script saves the cookiejar which the PHP later reads.
640
	   The cookie has a length of 1 year, but I don't think it actually lasts that long, so we update every 6hours instead.
641
	   I should probably also mention that the cookie generated also uses your user-agent, so if it changes the cookie will break.
642
	*/
643
644
	public function getFullTitleURL(string $title_url) : string {
645
		return "http://kissmanga.com/Manga/{$title_url}";
646
	}
647
648
	public function isValidTitleURL(string $title_url) : bool {
649
		$success = (bool) preg_match('/^[A-Za-z0-9-]+/', $title_url);
650
		if(!$success) log_message('error', "Invalid Title URL (KissManga): {$title_url}");
651
		return $success;
652
	}
653
	public function isValidChapter(string $chapter) : bool {
654
		$success = (bool) preg_match('/^.*?:--:[0-9]+$/', $chapter);
655
		if(!$success) log_message('error', 'Invalid Chapter (KissManga): '.$chapter);
656
		return $success;
657
	}
658
659 View Code Duplication
	public function getChapterData(string $title_url, string $chapter) : array {
660
		$chapter_parts = explode(':--:', $chapter);
661
662
		return [
663
			'url'    => "http://kissmanga.com/Manga/{$title_url}/{$chapter_parts[0]}?id={$chapter_parts[1]}",
664
			//FIXME: KM has an extremely inconsistant chapter format which makes it difficult to parse.
665
			'number' => /*preg_replace('/--.*?$/', '', */$chapter_parts[0]/*)*/
666
		];
667
	}
668
669
	public function getTitleData(string $title_url) {
670
		$titleData = [];
671
672
		//Check if cookiejar is a day old (so we can know if something went wrong)
673
		$cookiejar_path = str_replace("public/", "_scripts/cookiejar", FCPATH);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 6 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
674
		$cookie_last_updated = filemtime($cookiejar_path);
675
		if($cookie_last_updated && ((time() - 86400) < $cookie_last_updated)) {
676
677
			$fullURL = $this->getFullTitleURL($title_url);
678
679
			$content = $this->get_content($fullURL, '', $cookiejar_path);
680
			$data = $content['body'];
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
681
			if(strpos($data, 'containerRoot') !== FALSE) {
682
				//FIXME: For whatever reason, we can't grab the entire div without simplexml shouting at us
683
				$data = preg_replace('/^[\S\s]*(<div id="leftside">[\S\s]*)<div id="rightside">[\S\s]*$/', '$1', $data);
684
685
				$dom = new DOMDocument();
686
				libxml_use_internal_errors(true);
687
				$dom->loadHTML($data);
688
				libxml_use_internal_errors(false);
689
690
				$xpath = new DOMXPath($dom);
691
692
				$nodes_title = $xpath->query("//a[@class='bigChar']");
693
				$nodes_row   = $xpath->query("//table[@class='listing']/tr[3]");
694
				if($nodes_title->length === 1 && $nodes_row->length === 1) {
695
					$titleData['title'] = $nodes_title->item(0)->textContent;
696
697
					$firstRow      = $nodes_row->item(0);
698
					$nodes_latest  = $xpath->query("td[2]",   $firstRow);
699
					$nodes_chapter = $xpath->query("td[1]/a", $firstRow);
700
701
					$link = (string) $nodes_chapter->item(0)->getAttribute('href');
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 24 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
702
					$chapterURLSegments = explode('/', preg_replace('/\?.*$/', '', $link));
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 10 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
703
					$titleData['latest_chapter'] = $chapterURLSegments[3] . ':--:' . preg_replace('/.*?([0-9]+)$/', '$1', $link);
704
					$titleData['last_updated'] =  date("Y-m-d H:i:s", strtotime((string) $nodes_latest->item(0)->textContent));
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 3 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
705
				}
706
			} else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
707
				//TODO: Throw ERRORS;
708
			}
709
		} else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
710
			//Do nothing, wait until next update.
711
			//TODO: NAG ADMIN??
712
		}
713
714
		return (!empty($titleData) ? $titleData : NULL);
715
	}
716
}
717
718
class KireiCake extends Site_Model {
719 1
	public function getFullTitleURL(string $title_url) : string {
720 1
		return "https://reader.kireicake.com/series/{$title_url}";
721
	}
722
723
	public function isValidTitleURL(string $title_url) : bool {
724
		$success = (bool) preg_match('/^[a-z0-9_]+/', $title_url);
725
		if(!$success) log_message('error', "Invalid Title URL (KireiCake): {$title_url}");
726
		return $success;
727
	}
728
	public function isValidChapter(string $chapter) : bool {
729
		$success = (bool) preg_match('/^en\/[0-9]+(?:\/[0-9]+(?:\/[0-9]+(?:\/[0-9]+)?)?)?$/', $chapter);
730
		if(!$success) log_message('error', 'Invalid Chapter (KireiCake): '.$chapter);
731
		return $success;
732
	}
733
734
	public function getChapterData(string $title_url, string $chapter) : array {
735
		//LANG/VOLUME/CHAPTER/CHAPTER_EXTRA(/page/)
736
		$chapter_parts = explode('/', $chapter);
737
		return [
738
			'url'    => "https://reader.kireicake.com/read/{$title_url}/{$chapter}/",
739
			'number' => ($chapter_parts[1] !== '0' ? "v{$chapter_parts[1]}/" : '') . "c{$chapter_parts[2]}" . (isset($chapter_parts[3]) ? ".{$chapter_parts[3]}" : '')/*)*/
740
		];
741
	}
742
743 1
	public function getTitleData(string $title_url) {
744 1
		$titleData = [];
745
746 1
		$fullURL = $this->getFullTitleURL($title_url);
747
748 1
		$content = $this->get_content($fullURL);
749 1
		$data = $content['body'];
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
750 1
		if(strpos($data, '404 Page Not Found') === FALSE) {
751
			//FIXME: For whatever reason, we can't grab the entire div without simplexml shouting at us
752 1
			$data = preg_replace('/^[\S\s]*(<article>[\S\s]*)<\/article>[\S\s]*$/', '$1', $data);
753
754 1
			$dom = new DOMDocument();
755 1
			libxml_use_internal_errors(true);
756 1
			$dom->loadHTML($data);
757 1
			libxml_use_internal_errors(false);
758
759 1
			$xpath = new DOMXPath($dom);
760
761 1
			$nodes_title = $xpath->query("//div[@class='large comic']/h1[@class='title']");
762 1
			$nodes_row   = $xpath->query("//div[@class='list']/div[@class='element'][1]");
763 1
			if($nodes_title->length === 1 && $nodes_row->length === 1) {
764 1
				$titleData['title'] = trim($nodes_title->item(0)->textContent);
765
766 1
				$firstRow      = $nodes_row->item(0);
767 1
				$nodes_latest  = $xpath->query("div[@class='meta_r']",  $firstRow);
768 1
				$nodes_chapter = $xpath->query("div[@class='title']/a", $firstRow);
769
770 1
				$link = (string) $nodes_chapter->item(0)->getAttribute('href');
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 24 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
771 1
				$titleData['latest_chapter'] = preg_replace('/.*\/read\/.*?\/(.*?)\/$/', '$1', $link);
772 1
				$titleData['last_updated'] =  date("Y-m-d H:i:s", strtotime((string) str_replace('.', '', explode(',', $nodes_latest->item(0)->textContent)[1])));
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 3 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
773
			}
774
		} else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
775
			//TODO: Throw ERRORS;
776
		}
777
778 1
		return (!empty($titleData) ? $titleData : NULL);
779
	}
780
}
781
782
class GameOfScanlation extends Site_Model {
783
	public function getFullTitleURL(string $title_url) : string {
784
		return "https://gameofscanlation.moe/forums/{$title_url}/";
785
	}
786
787
	public function isValidTitleURL(string $title_url) : bool {
788
		$success = (bool) preg_match('/^[a-z0-9-]+/', $title_url);
789
		if(!$success) log_message('error', "Invalid Title URL (GameOfScanlation): {$title_url}");
790
		return $success;
791
	}
792
	public function isValidChapter(string $chapter) : bool {
793
		$success = (bool) preg_match('/^[a-z0-9\.-]+$/', $chapter);
794
		if(!$success) log_message('error', 'Invalid Chapter (GameOfScanlation): '.$chapter);
795
		return $success;
796
	}
797
798
	public function getChapterData(string $title_url, string $chapter) : array {
799
		return [
800
			'url'    => "https://gameofscanlation.moe/projects/".preg_replace("/\\.[0-9]+$/", "", $title_url).'/'.$chapter.'/',
801
			'number' => preg_replace("/chapter-/", "c", preg_replace("/\\.[0-9]+$/", "", $chapter))
802
		];
803
	}
804
805
	public function getTitleData(string $title_url) {
806
		$titleData = [];
807
808
		$fullURL = $this->getFullTitleURL($title_url);
809
810
		$content = $this->get_content($fullURL);
811
		$data = $content['body'];
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
812
		if(strpos($data, '404 Page Not Found') === FALSE) {
813
			//$data = preg_replace('/^[\S\s]*(<ol[\S\s]*)<\/ol>[\S\s]*$/', '$1', $data);
814
815
			$dom = new DOMDocument();
816
			libxml_use_internal_errors(true);
817
			$dom->loadHTML($data);
818
			libxml_use_internal_errors(false);
819
820
			$xpath = new DOMXPath($dom);
821
822
			$nodes_title = $xpath->query("//meta[@property='og:title']");
823
			$nodes_row   = $xpath->query("//ol[@class='discussionListItems']/li[1]/div[@class='home_list']/ul/li/div[@class='list_press_text']");
824
			if($nodes_title->length === 1 && $nodes_row->length === 1) {
825
				$titleData['title'] = html_entity_decode($nodes_title->item(0)->getAttribute('content'));
826
827
				$firstRow      = $nodes_row->item(0);
828
				$nodes_latest  = $xpath->query("p[@class='author']/span|p[@class='author']/abbr", $firstRow);
829
				$nodes_chapter = $xpath->query("p[@class='text_work']/a",                         $firstRow);
830
831
				$link = (string) $nodes_chapter->item(0)->getAttribute('href');
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 24 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
832
				$titleData['latest_chapter'] = preg_replace('/^projects\/.*?\/(.*?)\/$/', '$1', $link);
833
				$titleData['last_updated'] =  date("Y-m-d H:i:s", (int) $nodes_latest->item(0)->getAttribute('data-time'));
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 3 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
834
			} else {
835
				log_message('error', "GameOfScanlation: Unable to find nodes.");
836
				return NULL;
837
			}
838
		} else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
839
			//TODO: Throw ERRORS;
840
		}
841
842
		return (!empty($titleData) ? $titleData : NULL);
843
	}
844
}
845
846
class MangaCow extends Site_Model {
847 1
	public function getFullTitleURL(string $title_url) : string {
848 1
		return "http://mngcow.co/{$title_url}/";
849
	}
850
851
	public function isValidTitleURL(string $title_url) : bool {
852
		$success = (bool) preg_match('/^[a-zA-Z0-9_]+/', $title_url);
853
		if(!$success) log_message('error', "Invalid Title URL (MangaCow): {$title_url}");
854
		return $success;
855
	}
856
	public function isValidChapter(string $chapter) : bool {
857
		$success = (bool) preg_match('/^[0-9]+$/', $chapter);
858
		if(!$success) log_message('error', 'Invalid Chapter (MangaCow): '.$chapter);
859
		return $success;
860
	}
861
862
	public function getChapterData(string $title_url, string $chapter) : array {
863
		return [
864
			'url'    => $this->getFullTitleURL($title_url).$chapter.'/',
865
			'number' => "c{$chapter}"
866
		];
867
	}
868
869 1
	public function getTitleData(string $title_url) {
870 1
		$titleData = [];
871
872 1
		$fullURL = $this->getFullTitleURL($title_url);
873
874 1
		$content = $this->get_content($fullURL);
875 1
		$data = $content['body'];
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
876 1
		if(strpos($data, '404 Page Not Found') === FALSE) {
877 1
			$dom = new DOMDocument();
878 1
			libxml_use_internal_errors(true);
879 1
			$dom->loadHTML($data);
880 1
			libxml_use_internal_errors(false);
881
882 1
			$xpath = new DOMXPath($dom);
883
884 1
			$nodes_title = $xpath->query("//h4");
885 1
			$nodes_row   = $xpath->query("//ul[contains(@class, 'mng_chp')]/li[1]/a[1]");
886 1
			if($nodes_title->length === 1 && $nodes_row->length === 1) {
887 1
				$titleData['title'] = trim($nodes_title->item(0)->nodeValue);
888
889 1
				$nodes_chapter = $nodes_row;
890 1
				$nodes_latest  = $xpath->query("b[@class='dte']", $nodes_row->item(0));
891
892 1
				$link = (string) $nodes_chapter->item(0)->getAttribute('href');
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 24 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
893 1
				$titleData['latest_chapter'] = preg_replace('/^.*\/([0-9]+)\/$/', '$1', $link);
894 1
				$titleData['last_updated'] =  date("Y-m-d H:i:s", strtotime((string) substr($nodes_latest->item(0)->getAttribute('title'), 13)));
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 3 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
895
			} else {
896
				log_message('error', "MangaCow: Unable to find nodes.");
897 1
				return NULL;
898
			}
899
		} else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
900
			//TODO: Throw ERRORS;
901
		}
902
903 1
		return (!empty($titleData) ? $titleData : NULL);
904
	}
905
}
906
907 View Code Duplication
class SeaOtterScans extends Site_Model {
0 ignored issues
show
Duplication introduced by
This class 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...
908 1
	public function getFullTitleURL(string $title_url) : string {
909 1
		return "https://reader.seaotterscans.com/series/{$title_url}";
910
	}
911
912
	public function isValidTitleURL(string $title_url) : bool {
913
		$success = (bool) preg_match('/^[a-z0-9_]+/', $title_url);
914
		if(!$success) log_message('error', "Invalid Title URL (SeaOtterScans): {$title_url}");
915
		return $success;
916
	}
917
	public function isValidChapter(string $chapter) : bool {
918
		$success = (bool) preg_match('/^en\/[0-9]+(?:\/[0-9]+(?:\/[0-9]+(?:\/[0-9]+)?)?)?$/', $chapter);
919
		if(!$success) log_message('error', 'Invalid Chapter (SeaOtterScans): '.$chapter);
920
		return $success;
921
	}
922
923
	public function getChapterData(string $title_url, string $chapter) : array {
924
		//LANG/VOLUME/CHAPTER/CHAPTER_EXTRA(/page/)
925
		$chapter_parts = explode('/', $chapter);
926
		return [
927
			'url'    => "https://reader.seaotterscans.com/read/{$title_url}/{$chapter}/",
928
			'number' => ($chapter_parts[1] !== '0' ? "v{$chapter_parts[1]}/" : '') . "c{$chapter_parts[2]}" . (isset($chapter_parts[3]) ? ".{$chapter_parts[3]}" : '')/*)*/
929
		];
930
	}
931
932 1
	public function getTitleData(string $title_url) {
933 1
		$titleData = [];
934
935 1
		$fullURL = $this->getFullTitleURL($title_url);
936
937 1
		$content = $this->get_content($fullURL);
938 1
		$data = $content['body'];
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
939 1
		if(strpos($data, '404 Page Not Found') === FALSE) {
940
			//FIXME: For whatever reason, we can't grab the entire div without simplexml shouting at us
941 1
			$data = preg_replace('/^[\S\s]*(<article[\S\s]*)<\/article>[\S\s]*$/', '$1', $data);
942
943 1
			$dom = new DOMDocument();
944 1
			libxml_use_internal_errors(true);
945 1
			$dom->loadHTML($data);
946 1
			libxml_use_internal_errors(false);
947
948 1
			$xpath = new DOMXPath($dom);
949
950 1
			$nodes_title = $xpath->query("//div[@class='large comic']/h1[@class='title']");
951
952
			//SOO sometimes uses volume groups which are above recent chapters (if they haven't been grouped yet), so make sure we check for both.
953 1
			$nodes_row   = $xpath->query("//div[@class='list']/div[@class='group']/div[@class='title' and text() = 'Chapters']/following-sibling::div[@class='element'][1]");
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned correctly; expected 1 space but found 3 spaces

This check looks for improperly formatted assignments.

Every assignment must have exactly one space before and one space after the equals operator.

To illustrate:

$a = "a";
$ab = "ab";
$abc = "abc";

will have no issues, while

$a   = "a";
$ab  = "ab";
$abc = "abc";

will report issues in lines 1 and 2.

Loading history...
954 1
			if($nodes_row->length !== 1) {
955 1
				$nodes_row   = $xpath->query("//div[@class='list']/div[@class='group'][1]/div[@class='element'][1]");
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned correctly; expected 1 space but found 3 spaces

This check looks for improperly formatted assignments.

Every assignment must have exactly one space before and one space after the equals operator.

To illustrate:

$a = "a";
$ab = "ab";
$abc = "abc";

will have no issues, while

$a   = "a";
$ab  = "ab";
$abc = "abc";

will report issues in lines 1 and 2.

Loading history...
956
			}
957 1
			if($nodes_title->length === 1 && $nodes_row->length === 1) {
958 1
				$titleData['title'] = trim($nodes_title->item(0)->textContent);
959
960 1
				$firstRow = $nodes_row->item(0);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 6 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
961 1
				$nodes_latest  = $xpath->query("div[@class='meta_r']",  $firstRow);
962 1
				$nodes_chapter = $xpath->query("div[@class='title']/a", $firstRow);
963
964 1
				$link = (string) $nodes_chapter->item(0)->getAttribute('href');
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 24 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
965 1
				$titleData['latest_chapter'] = preg_replace('/.*\/read\/.*?\/(.*?)\/$/', '$1', $link);
966 1
				$titleData['last_updated'] = date("Y-m-d H:i:s", strtotime(((string) str_replace('.', '', explode(',', $nodes_latest[0]->textContent)[1]))));
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 3 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
967
			}
968
		} else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
969
			//TODO: Throw ERRORS;
970
		}
971
972 1
		return (!empty($titleData) ? $titleData : NULL);
973
	}
974
}
975
976 View Code Duplication
class HelveticaScans extends Site_Model {
0 ignored issues
show
Duplication introduced by
This class 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...
977 1
	public function getFullTitleURL(string $title_url) : string {
978 1
		return "http://helveticascans.com/reader/series/{$title_url}";
979
	}
980
981
	public function isValidTitleURL(string $title_url) : bool {
982
		$success = (bool) preg_match('/^[a-z0-9_]+/', $title_url);
983
		if(!$success) log_message('error', "Invalid Title URL (HelveticaScans): {$title_url}");
984
		return $success;
985
	}
986
	public function isValidChapter(string $chapter) : bool {
987
		$success = (bool) preg_match('/^en\/[0-9]+(?:\/[0-9]+(?:\/[0-9]+(?:\/[0-9]+)?)?)?$/', $chapter);
988
		if(!$success) log_message('error', 'Invalid Chapter (HelveticaScans): '.$chapter);
989
		return $success;
990
	}
991
992
	public function getChapterData(string $title_url, string $chapter) : array {
993
		//LANG/VOLUME/CHAPTER/CHAPTER_EXTRA(/page/)
994
		$chapter_parts = explode('/', $chapter);
995
		return [
996
			'url'    => "http://helveticascans.com/reader/read/{$title_url}/{$chapter}/",
997
			'number' => ($chapter_parts[1] !== '0' ? "v{$chapter_parts[1]}/" : '') . "c{$chapter_parts[2]}" . (isset($chapter_parts[3]) ? ".{$chapter_parts[3]}" : '')/*)*/
998
		];
999
	}
1000
1001 1
	public function getTitleData(string $title_url) {
1002 1
		$titleData = [];
1003
1004 1
		$fullURL = $this->getFullTitleURL($title_url);
1005
1006 1
		$content = $this->get_content($fullURL);
1007 1
		$data = $content['body'];
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
1008 1
		if(strpos($data, '404 Page Not Found') === FALSE) {
1009
			//FIXME: For whatever reason, we can't grab the entire div without simplexml shouting at us
1010 1
			$data = preg_replace('/^[\S\s]*(<article[\S\s]*)<\/article>[\S\s]*$/', '$1', $data);
1011
1012 1
			$dom = new DOMDocument();
1013 1
			libxml_use_internal_errors(true);
1014 1
			$dom->loadHTML($data);
1015 1
			libxml_use_internal_errors(false);
1016
1017 1
			$xpath = new DOMXPath($dom);
1018
1019 1
			$nodes_title = $xpath->query("//div[@class='large comic']/h1[@class='title']");
1020 1
			$nodes_row   = $xpath->query("//div[@class='list']/div[@class='group']/div[@class='title' and text() = 'Chapters']/following-sibling::div[@class='element'][1]");
1021 1
			if($nodes_row->length !== 1) {
1022
				$nodes_row   = $xpath->query("//div[@class='list']/div[@class='group'][1]/div[@class='element'][1]");
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned correctly; expected 1 space but found 3 spaces

This check looks for improperly formatted assignments.

Every assignment must have exactly one space before and one space after the equals operator.

To illustrate:

$a = "a";
$ab = "ab";
$abc = "abc";

will have no issues, while

$a   = "a";
$ab  = "ab";
$abc = "abc";

will report issues in lines 1 and 2.

Loading history...
1023
			}
1024 1
			if($nodes_title->length === 1 && $nodes_row->length === 1) {
1025 1
				$titleData['title'] = trim($nodes_title->item(0)->textContent);
1026
1027
1028 1
				$nodes_latest  = $xpath->query("div[@class='meta_r']", $nodes_row[0]);
1029 1
				$nodes_chapter = $xpath->query("div[@class='title']/a", $nodes_row[0]);
1030
1031 1
				$link = (string) $nodes_chapter->item(0)->getAttribute('href');
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 24 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
1032 1
				$titleData['latest_chapter'] = preg_replace('/.*\/read\/.*?\/(.*?)\/$/', '$1', $link);
1033 1
				$titleData['last_updated'] =  date("Y-m-d H:i:s", strtotime((string) str_replace('.', '', explode(',', $nodes_latest->item(0)->textContent)[1])));
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 3 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
1034
			}
1035
		} else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
1036
			//TODO: Throw ERRORS;
1037
		}
1038
1039 1
		return (!empty($titleData) ? $titleData : NULL);
1040
	}
1041
}
1042
1043 View Code Duplication
class SenseScans extends Site_Model {
0 ignored issues
show
Duplication introduced by
This class 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...
1044 1
	public function getFullTitleURL(string $title_url) : string {
1045 1
		return "http://reader.sensescans.com/series/{$title_url}";
1046
	}
1047
1048
	public function isValidTitleURL(string $title_url) : bool {
1049
		$success = (bool) preg_match('/^[a-z0-9_]+/', $title_url);
1050
		if(!$success) log_message('error', "Invalid Title URL (SenseScans): {$title_url}");
1051
		return $success;
1052
	}
1053
	public function isValidChapter(string $chapter) : bool {
1054
		$success = (bool) preg_match('/^en\/[0-9]+(?:\/[0-9]+(?:\/[0-9]+(?:\/[0-9]+)?)?)?$/', $chapter);
1055
		if(!$success) log_message('error', 'Invalid Chapter (SenseScans): '.$chapter);
1056
		return $success;
1057
	}
1058
1059
	public function getChapterData(string $title_url, string $chapter) : array {
1060
		//LANG/VOLUME/CHAPTER/CHAPTER_EXTRA(/page/)
1061
		$chapter_parts = explode('/', $chapter);
1062
		return [
1063
			'url'    => "http://reader.sensescans.com/read/{$title_url}/{$chapter}/",
1064
			'number' => ($chapter_parts[1] !== '0' ? "v{$chapter_parts[1]}/" : '') . "c{$chapter_parts[2]}" . (isset($chapter_parts[3]) ? ".{$chapter_parts[3]}" : '')/*)*/
1065
		];
1066
	}
1067
1068 1
	public function getTitleData(string $title_url) {
1069 1
		$titleData = [];
1070
1071 1
		$fullURL = $this->getFullTitleURL($title_url);
1072
1073 1
		$content = $this->get_content($fullURL);
1074 1
		$data = $content['body'];
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
1075 1
		if(strpos($data, '404 Page Not Found') === FALSE) {
1076
			//FIXME: For whatever reason, we can't grab the entire div without simplexml shouting at us
1077 1
			$data = preg_replace('/^[\S\s]*(<article[\S\s]*)<\/article>[\S\s]*$/', '$1', $data);
1078
1079 1
			$dom = new DOMDocument();
1080 1
			libxml_use_internal_errors(true);
1081 1
			$dom->loadHTML($data);
1082 1
			libxml_use_internal_errors(false);
1083
1084 1
			$xpath = new DOMXPath($dom);
1085
1086 1
			$nodes_title = $xpath->query("//div[@class='large comic']/h1[@class='title']");
1087 1
			$nodes_row   = $xpath->query("//div[@class='list']/div[@class='group']/div[@class='title' and text() = 'Chapters']/following-sibling::div[@class='element'][1]");
1088 1
			if($nodes_row->length !== 1) {
1089
				$nodes_row   = $xpath->query("//div[@class='list']/div[@class='group'][1]/div[@class='element'][1]");
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned correctly; expected 1 space but found 3 spaces

This check looks for improperly formatted assignments.

Every assignment must have exactly one space before and one space after the equals operator.

To illustrate:

$a = "a";
$ab = "ab";
$abc = "abc";

will have no issues, while

$a   = "a";
$ab  = "ab";
$abc = "abc";

will report issues in lines 1 and 2.

Loading history...
1090
			}
1091 1
			if($nodes_title->length === 1 && $nodes_row->length === 1) {
1092 1
				$titleData['title'] = trim($nodes_title->item(0)->textContent);
1093
1094 1
				$nodes_latest    = $xpath->query("div[@class='meta_r']", $nodes_row[0]);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 2 spaces but found 4 spaces

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
1095 1
				$nodes_chapter   = $xpath->query("div[@class='title']/a", $nodes_row[0]);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 1 space but found 3 spaces

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
1096
1097 1
				$link = (string) $nodes_chapter->item(0)->getAttribute('href');
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 24 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
1098 1
				$titleData['latest_chapter'] = preg_replace('/.*\/read\/.*?\/(.*?)\/$/', '$1', $link);
1099 1
				$titleData['last_updated'] =  date("Y-m-d H:i:s", strtotime((string) str_replace('.', '', explode(',', $nodes_latest->item(0)->textContent)[1])));
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 3 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
1100
			}
1101
		} else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
1102
			//TODO: Throw ERRORS;
1103
		}
1104
1105 1
		return (!empty($titleData) ? $titleData : NULL);
1106
	}
1107
}
1108