Completed
Push — 3.2.x ( 186427...2e2541 )
by Erwan
03:01
created

link   D

Complexity

Total Complexity 166

Size/Duplication

Total Lines 1217
Duplicated Lines 2.22 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 31
Bugs 3 Features 0
Metric Value
wmc 166
c 31
b 3
f 0
lcom 1
cbo 2
dl 27
loc 1217
rs 4.4102

28 Methods

Rating   Name   Duplication   Size   Complexity  
B add() 0 42 6
B edit() 0 49 4
A __construct() 0 18 1
C del() 27 70 9
A view() 0 21 2
C checkurl() 0 41 7
A clean_url() 0 10 4
A display_flag() 0 15 4
B display_note() 0 12 5
B display_vote() 0 14 6
A display_rss() 0 7 3
B display_thumb() 0 18 6
B display_pagerank() 0 27 4
C display_bann() 0 35 8
B add_vote() 0 41 2
B thumb_process() 0 18 5
B _ascreen_exist() 0 12 5
D banner_process() 0 33 16
B _banner_upload() 0 28 3
D _banner_remote() 0 105 25
A _banner_delete() 0 10 2
B pagerank_process() 0 31 4
B get_dir_flag_list() 0 32 5
C recents() 0 74 8
C validate_link_back() 0 37 8
C _check() 0 45 7
B auto_check() 0 27 2
B _update_check() 0 61 5

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like link often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use link, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
*
4
* phpBB Directory extension for the phpBB Forum Software package.
5
*
6
* @copyright (c) 2014 ErnadoO <http://www.phpbb-services.com>
7
* @license GNU General Public License, version 2 (GPL-2.0)
8
*
9
*/
10
11
namespace ernadoo\phpbbdirectory\core;
12
13
class link
14
{
15
	/** @var \phpbb\db\driver\driver_interface */
16
	protected $db;
17
18
	/** @var \phpbb\config\config */
19
	protected $config;
20
21
	/** @var \phpbb\language\language */
22
	protected $language;
23
24
	/** @var \phpbb\template\template */
25
	protected $template;
26
27
	/** @var \phpbb\user */
28
	protected $user;
29
30
	/** @var \phpbb\controller\helper */
31
	protected $helper;
32
33
	/** @var \phpbb\request\request */
34
	protected $request;
35
36
	/** @var \phpbb\auth\auth */
37
	protected $auth;
38
39
	/** @var \phpbb\notification\manager */
40
	protected $notification;
41
42
	/** @var \phpbb\filesystem\filesystem_interface */
43
	protected $filesystem;
44
45
	/** @var \FastImageSize\FastImageSize */
46
	protected $imagesize;
47
48
	/** @var \phpbb\files\factory */
49
	protected $files_factory;
50
51
	/** @var \ernadoo\phpbbdirectory\core\helper */
52
	protected $dir_helper;
53
54
	/** @var string phpBB root path */
55
	protected $root_path;
56
57
	/** @var string phpEx */
58
	protected $php_ext;
59
60
	/**
61
	* Constructor
62
	*
63
	* @param \phpbb\db\driver\driver_interface 					$db					Database object
64
	* @param \phpbb\config\config 								$config				Config object
65
	* @param \phpbb\language\language							$language			Language object
66
	* @param \phpbb\template\template 							$template			Template object
67
	* @param \phpbb\user 										$user				User object
68
	* @param \phpbb\controller\helper 							$helper				Controller helper object
69
	* @param \phpbb\request\request 							$request			Request object
70
	* @param \phpbb\auth\auth 									$auth				Auth object
71
	* @param \phpbb\notification\manager						$notification		Notification object
72
	* @param \phpbb\filesystem\filesystem_interface				$filesystem			phpBB filesystem helper
73
	* @param \FastImageSize\FastImageSize						$imagesize 			FastImageSize class
74
	* @param \phpbb\files\factory								$files_factory		File classes factory
75
	* @param \ernadoo\phpbbdirectory\core\helper				$dir_helper			PhpBB Directory extension helper object
76
	* @param string         									$root_path			phpBB root path
77
	* @param string         									$php_ext			phpEx
78
	*/
79
	public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\config\config $config, \phpbb\language\language $language, \phpbb\template\template $template, \phpbb\user $user, \phpbb\controller\helper $helper, \phpbb\request\request $request, \phpbb\auth\auth $auth, \phpbb\notification\manager $notification, \phpbb\filesystem\filesystem_interface $filesystem, \FastImageSize\FastImageSize $imagesize, \phpbb\files\factory $files_factory, \ernadoo\phpbbdirectory\core\helper $dir_helper, $root_path, $php_ext)
80
	{
81
		$this->db				= $db;
82
		$this->config			= $config;
83
		$this->language			= $language;
84
		$this->template			= $template;
85
		$this->user				= $user;
86
		$this->helper			= $helper;
87
		$this->request			= $request;
88
		$this->auth				= $auth;
89
		$this->notification		= $notification;
90
		$this->filesystem		= $filesystem;
91
		$this->imagesize		= $imagesize;
92
		$this->files_factory 	= $files_factory;
93
		$this->dir_helper		= $dir_helper;
94
		$this->root_path		= $root_path;
95
		$this->php_ext			= $php_ext;
96
	}
97
98
	/**
99
	* Add a link into db
100
	*
101
	* @param	array	$data			Contains all data to insert in db
102
	* @param	bool	$need_approval	Links needs to be approved?
103
	* @return	null
104
	*/
105
	public function add($data, $need_approval)
106
	{
107
		$notification_data = array();
108
109
		$this->db->sql_transaction('begin');
110
111
		$sql = 'INSERT INTO ' . DIR_LINK_TABLE . ' ' . $this->db->sql_build_array('INSERT', $data);
112
		$this->db->sql_query($sql);
113
		$notification_data['link_id'] = $this->db->sql_nextid();
114
115
		if (!$need_approval || $this->auth->acl_get('a_') || $this->auth->acl_get('m_'))
116
		{
117
			$sql = 'UPDATE ' . DIR_CAT_TABLE . '
118
				SET cat_links = cat_links + 1
119
				WHERE cat_id = ' . (int) $data['link_cat'];
120
			$this->db->sql_query($sql);
121
122
			$notification_type = 'ernadoo.phpbbdirectory.notification.type.directory_website';
123
		}
124
		else if ($this->config['dir_mail'])
125
		{
126
			$notification_type = 'ernadoo.phpbbdirectory.notification.type.directory_website_in_queue';
127
		}
128
129
		$this->db->sql_transaction('commit');
130
131
		if (isset($notification_type))
132
		{
133
			$notification_data = array_merge($notification_data,
134
				array(
135
					'user_from'			=> (int) $data['link_user_id'],
136
					'link_name'			=> $data['link_name'],
137
					'link_url'			=> $data['link_url'],
138
					'link_description'	=> $data['link_description'],
139
					'cat_id'			=> (int) $data['link_cat'],
140
					'cat_name'			=> \ernadoo\phpbbdirectory\core\categorie::getname((int) $data['link_cat']),
141
				)
142
			);
143
144
			$this->notification->add_notifications($notification_type, $notification_data);
145
		}
146
	}
147
148
	/**
149
	* Edit a link of the db
150
	*
151
	* @param	array	$data			Contains all data to edit in db
152
	* @param	int		$link_id		is link's id, for WHERE clause
153
	* @param	bool	$need_approval	Links needs to be approved?
154
	* @return	null
155
	*/
156
	public function edit($data, $link_id, $need_approval)
157
	{
158
		$notification_data = array(
159
			'link_id'			=> (int) $link_id,
160
			'user_from'			=> (int) $data['link_user_id'],
161
			'link_name'			=> $data['link_name'],
162
			'link_description'	=> $data['link_description'],
163
			'cat_id'			=> (int) $data['link_cat'],
164
			'cat_name'			=> \ernadoo\phpbbdirectory\core\categorie::getname((int) $data['link_cat']),
165
		);
166
167
		$old_cat = array_pop($data);
168
169
		if ($old_cat != $data['link_cat'] || $need_approval)
170
		{
171
			$this->notification->delete_notifications('ernadoo.phpbbdirectory.notification.type.directory_website', (int) $link_id);
172
173
			$this->db->sql_transaction('begin');
174
175
			$sql = 'UPDATE ' . DIR_CAT_TABLE . '
176
				SET cat_links = cat_links - 1
177
				WHERE cat_id = ' . (int) $old_cat;
178
			$this->db->sql_query($sql);
179
180
			if (!$need_approval)
181
			{
182
				$sql = 'UPDATE ' . DIR_CAT_TABLE . '
183
					SET cat_links = cat_links + 1
184
					WHERE cat_id = ' . (int) $data['link_cat'];
185
				$this->db->sql_query($sql);
186
187
				$notification_type = 'ernadoo.phpbbdirectory.notification.type.directory_website';
188
			}
189
			else
190
			{
191
				$data['link_active'] = false;
192
				$notification_type = 'ernadoo.phpbbdirectory.notification.type.directory_website_in_queue';
193
			}
194
195
			$this->db->sql_transaction('commit');
196
197
			$this->notification->add_notifications($notification_type, $notification_data);
198
		}
199
200
		$sql = 'UPDATE ' . DIR_LINK_TABLE . '
201
			SET ' . $this->db->sql_build_array('UPDATE', $data) . '
202
			WHERE link_id = ' . (int) $link_id;
203
		$this->db->sql_query($sql);
204
	}
205
206
	/**
207
	* Delete a link of the db
208
	*
209
	* @param	int 	$cat_id		The category ID
210
	* @param	mixed 	$link_id	Link's id, for WHERE clause
211
	* @return	null
212
	*/
213
	public function del($cat_id, $link_id)
214
	{
215
		$this->db->sql_transaction('begin');
216
217
		$url_array = is_array($link_id) ? $link_id : array($link_id);
218
219
		// Delete links datas
220
		$link_datas_ary = array(
221
			DIR_LINK_TABLE		=> 'link_id',
222
			DIR_COMMENT_TABLE	=> 'comment_link_id',
223
			DIR_VOTE_TABLE		=> 'vote_link_id',
224
		);
225
226
		$sql = 'SELECT link_banner
227
			FROM ' . DIR_LINK_TABLE . '
228
			WHERE '. $this->db->sql_in_set('link_id', $url_array);
229
		$result = $this->db->sql_query($sql);
230
231
		while ($row = $this->db->sql_fetchrow($result))
232
		{
233 View Code Duplication
			if ($row['link_banner'] && !preg_match('/^(http:\/\/|https:\/\/|ftp:\/\/|ftps:\/\/|www\.).+/si', $row['link_banner']))
234
			{
235
				$banner_img = $this->dir_helper->get_banner_path(basename($row['link_banner']));
236
237
				if (file_exists($banner_img))
238
				{
239
					@unlink($banner_img);
240
				}
241
			}
242
		}
243
244
		foreach ($link_datas_ary as $table => $field)
245
		{
246
			$this->db->sql_query("DELETE FROM $table WHERE ".$this->db->sql_in_set($field, $url_array));
247
		}
248
249
		$sql = 'UPDATE ' . DIR_CAT_TABLE . '
250
			SET cat_links = cat_links - '.sizeof($url_array).'
251
			WHERE cat_id = ' . (int) $cat_id;
252
		$this->db->sql_query($sql);
253
254
		$this->db->sql_transaction('commit');
255
256
		foreach ($url_array as $link_id)
257
		{
258
			$this->notification->delete_notifications(array(
259
				'ernadoo.phpbbdirectory.notification.type.directory_website',
260
				'ernadoo.phpbbdirectory.notification.type.directory_website_in_queue'
261
			), $link_id);
262
		}
263
264 View Code Duplication
		if ($this->request->is_ajax())
265
		{
266
			$sql = 'SELECT cat_links
267
				FROM ' . DIR_CAT_TABLE . '
268
				WHERE cat_id = ' . (int) $cat_id;
269
			$result = $this->db->sql_query($sql);
270
			$data = $this->db->sql_fetchrow($result);
271
272
			$json_response = new \phpbb\json_response;
273
			$json_response->send(array(
274
				'success' => true,
275
276
				'MESSAGE_TITLE'	=> $this->language->lang('INFORMATION'),
277
				'MESSAGE_TEXT'	=> $this->language->lang('DIR_DELETE_OK'),
278
				'LINK_ID'		=> $link_id,
279
				'TOTAL_LINKS'	=> $this->language->lang('DIR_NB_LINKS', (int) $data['cat_links']),
280
			));
281
		}
282
	}
283
284
	/**
285
	* Increments link view counter
286
	*
287
	* @param	int		$link_id	Link's id, for WHERE clause
288
	* @return	null
289
	* @throws	\phpbb\exception\http_exception
290
	*/
291
	public function view($link_id)
292
	{
293
		$sql = 'SELECT link_id, link_url
294
			FROM ' . DIR_LINK_TABLE . '
295
			WHERE link_id = ' . (int) $link_id;
296
		$result = $this->db->sql_query($sql);
297
		$data = $this->db->sql_fetchrow($result);
298
299
		if (empty($data['link_id']))
300
		{
301
			throw new \phpbb\exception\http_exception(404, 'DIR_ERROR_NO_LINKS');
302
		}
303
304
		$sql = 'UPDATE ' . DIR_LINK_TABLE . '
305
			SET link_view = link_view + 1
306
			WHERE link_id = ' . (int) $link_id;
307
		$this->db->sql_query($sql);
308
309
		redirect($data['link_url'], false, true);
310
		return;
311
	}
312
313
	/**
314
	* Verify that an URL exist before add into db
315
	*
316
	* @param	string	$url	The URL to check
317
	* @return	bool			True if url is reachable, else false.
318
	*/
319
	public function checkurl($url)
320
	{
321
		$details = parse_url($url);
322
323
		$default_port = 80;
324
		$hostname = $details['host'];
325
326
		if ($details['scheme'] == 'https')
327
		{
328
			$default_port = 443;
329
			$hostname = 'tls://' . $details['host'];
330
		}
331
332
		if (!isset($details['path']))
333
		{
334
			$details['path'] = '/';
335
		}
336
337
		$port = (isset($details['port']) && !empty($details['port'])) ? (int) $details['port'] : $default_port;
338
339
		if ($sock = @fsockopen($hostname, $port, $errno, $errstr, 1))
340
		{
341
			$requete = 'GET '.$details['path']." HTTP/1.1\r\n";
342
			$requete .= 'Host: '.$details['host']."\r\n\r\n";
343
344
			// Send a HTTP GET header
345
			fputs($sock, $requete);
346
			// answer from server
347
			$str = fgets($sock, 1024);
348
			preg_match("'HTTP/1\.. (.*) (.*)'U", $str, $parts);
349
			fclose($sock);
350
351
			if ($parts[1] == '404')
352
			{
353
				return false;
354
			}
355
356
			return true;
357
		}
358
		return false;
359
	}
360
361
	/**
362
	* Delete the final '/', if no path
363
	*
364
	* @param	string	$url	URL to clean
365
	* @return	string	$url	The correct string.
366
	*/
367
	public function clean_url($url)
368
	{
369
		$details = parse_url($url);
370
371
		if (isset($details['path']) && $details['path'] == '/' && !isset($details['query']))
372
		{
373
			return substr($url, 0, -1);
374
		}
375
		return $url;
376
	}
377
378
	/**
379
	* Display a flag
380
	*
381
	* @param	array	$data	Link's data from db
382
	* @return	string			Flag path.
383
	*/
384
	public function display_flag($data)
385
	{
386
		global $phpbb_extension_manager;
387
388
		$ext_path = $phpbb_extension_manager->get_extension_path('ernadoo/phpbbdirectory', false);
389
		$flag_path = $ext_path.'images/flags/';
390
		$img_flag = 'no_flag.png';
391
392
		if ($this->config['dir_activ_flag'] && !empty($data['link_flag']) && file_exists($flag_path . $data['link_flag']))
393
		{
394
			$img_flag = $data['link_flag'];
395
		}
396
397
		return $this->dir_helper->get_img_path('flags', $img_flag);
398
	}
399
400
	/**
401
	* Calculate the link's note
402
	*
403
	* @param	int		$total_note		Sum of all link's notes
404
	* @param	int		$nb_vote		Number of votes
405
	* @param	bool	$votes_status	Votes are enable in this category?
406
	* @return	string	$note			The calculated note.
407
	*/
408
	public function display_note($total_note, $nb_vote, $votes_status)
409
	{
410
		if (!$votes_status)
411
		{
412
			return;
413
		}
414
415
		$note = ($nb_vote < 1) ? '' : $total_note / $nb_vote;
416
		$note = (strlen($note) > 2) ? number_format($note, 1) : $note;
417
418
		return ($nb_vote) ? $this->language->lang('DIR_FROM_TEN', $note) : $this->language->lang('DIR_NO_NOTE');
419
	}
420
421
	/**
422
	* Display the vote form for auth users
423
	*
424
	* @param	array	$data	Link's data from db
425
	* @return	null|string		Html combo list or nothing if votes are not available.
426
	*/
427
	public function display_vote($data)
428
	{
429
		if ($this->user->data['is_registered'] && $this->auth->acl_get('u_vote_dir') && empty($data['vote_user_id']))
430
		{
431
			$list = '<select name="vote">';
432
			for ($i = 0; $i <= 10; $i++)
433
			{
434
				$list .= '<option value="' . $i . '"' . (($i == 5) ? ' selected="selected"' : '') . '>' . $i . '</option>';
435
			}
436
			$list .= '</select>';
437
438
			return $list;
439
		}
440
	}
441
442
	/**
443
	* Display the RSS icon
444
	*
445
	* @param	array	$data	Link's data from db
446
	* @return	null|string		RSS feed URL or nothing.
447
	*/
448
	public function display_rss($data)
449
	{
450
		if ($this->config['dir_activ_rss'] && !empty($data['link_rss']))
451
		{
452
				return $data['link_rss'];
453
		}
454
	}
455
456
	/**
457
	* Display link's thumb if thumb service enabled.
458
	* if thumb don't exists in db or if a new service was choosen in acp
459
	* thumb is research
460
	*
461
	* @param	array		$data	Link's data from db
462
	* @return	string|null			Thumb or null.
463
	*/
464
	public function display_thumb($data)
465
	{
466
		if ($this->config['dir_activ_thumb'])
467
		{
468
			if (!$data['link_thumb'] || ($this->config['dir_thumb_service_reverse'] && (!strstr($data['link_thumb'], 'ascreen.jpg') && (!strstr($data['link_thumb'], $this->config['dir_thumb_service'])))))
469
			{
470
				$thumb = $this->thumb_process($data['link_url']);
471
472
				$sql = 'UPDATE ' . DIR_LINK_TABLE . '
473
					SET link_thumb = "' . $this->db->sql_escape($thumb) . '"
474
					WHERE link_id = ' . (int) $data['link_id'];
475
				$this->db->sql_query($sql);
476
477
				return $thumb;
478
			}
479
			return $data['link_thumb'];
480
		}
481
	}
482
483
	/**
484
	* Display and calculate PageRank if needed
485
	*
486
	* @param	array	$data	Link's data from db
487
	* @return	string			Pagerank, 'n/a' or false
488
	*/
489
	public function display_pagerank($data)
490
	{
491
		if ($this->config['dir_activ_pagerank'])
492
		{
493
			if ($data['link_pagerank'] == '')
494
			{
495
				$pagerank = $this->pagerank_process($data['link_url']);
496
497
				$sql = 'UPDATE ' . DIR_LINK_TABLE . '
498
					SET link_pagerank = ' . (int) $pagerank . '
499
					WHERE link_id = ' . (int) $data['link_id'];
500
				$this->db->sql_query($sql);
501
			}
502
			else
503
			{
504
				$pagerank = (int) $data['link_pagerank'];
505
			}
506
507
			$prpos=40*$pagerank/10;
508
			$prneg=40-$prpos;
509
			$html='<img src="http://www.google.com/images/pos.gif" width="'.$prpos.'" height="4" alt="'.$pagerank.'" /><img src="http://www.google.com/images/neg.gif" width="'.$prneg.'" height="4" alt="'.$pagerank.'" /> ';
510
511
			$pagerank = $pagerank == '-1' ? $this->language->lang('DIR_PAGERANK_NOT_AVAILABLE') : $this->language->lang('DIR_FROM_TEN', $pagerank);
512
			return $html.$pagerank;
513
		}
514
		return false;
515
	}
516
517
	/**
518
	* Display and resize a banner
519
	*
520
	* @param	array	$data		link's data from db
521
	* @return	string	$s_banner	html code.
522
	*/
523
	public function display_bann($data)
524
	{
525
		if (!empty($data['link_banner']))
526
		{
527
			if (!preg_match('/^(http:\/\/|https:\/\/|ftp:\/\/|ftps:\/\/|www\.).+/si', $data['link_banner']))
528
			{
529
				$img_src = $this->helper->route('ernadoo_phpbbdirectory_banner_controller', array('banner_img' => $data['link_banner']));
530
				$physical_path = $this->dir_helper->get_banner_path($data['link_banner']);
531
			}
532
			else
533
			{
534
				$img_src = $physical_path = $data['link_banner'];
535
			}
536
537
			if (($image_data = $this->imagesize->getImageSize($physical_path)) === false)
538
			{
539
				return '';
540
			}
541
542
			$width = $image_data['width'];
543
			$height = $image_data['height'];
544
545
			if (($width > $this->config['dir_banner_width'] || $height > $this->config['dir_banner_height']) && $this->config['dir_banner_width'] > 0 && $this->config['dir_banner_height'] > 0)
546
			{
547
				$coef_w = $width / $this->config['dir_banner_width'];
548
				$coef_h = $height / $this->config['dir_banner_height'];
549
				$coef_max = max($coef_w, $coef_h);
550
				$width /= $coef_max;
551
				$height /= $coef_max;
552
			}
553
554
			return '<img src="' . $img_src . '" width="' . $width . '" height="' . $height . '" alt="'.$data['link_name'].'" title="'.$data['link_name'].'" />';
555
		}
556
		return '';
557
	}
558
559
	/**
560
	* Add a vote in db, for a specifi link
561
	*
562
	* @param	int		$link_id	Link_id from db
563
	* @return	null
564
	*/
565
	public function add_vote($link_id)
566
	{
567
		$data = array(
568
			'vote_link_id' 		=> (int) $link_id,
569
			'vote_user_id' 		=> $this->user->data['user_id'],
570
			'vote_note'			=> $this->request->variable('vote', 0),
571
		);
572
573
		$this->db->sql_transaction('begin');
574
575
		$sql = 'INSERT INTO ' . DIR_VOTE_TABLE . ' ' . $this->db->sql_build_array('INSERT', $data);
576
		$this->db->sql_query($sql);
577
578
		$sql = 'UPDATE ' . DIR_LINK_TABLE . '
579
			SET link_vote = link_vote + 1,
580
			link_note = link_note + ' . (int) $data['vote_note'] . '
581
		WHERE link_id = ' . (int) $link_id;
582
		$this->db->sql_query($sql);
583
584
		$this->db->sql_transaction('commit');
585
586
		if ($this->request->is_ajax())
587
		{
588
			$sql= 'SELECT link_vote, link_note FROM ' . DIR_LINK_TABLE . ' WHERE link_id = ' . (int) $link_id;
589
			$result = $this->db->sql_query($sql);
590
			$data = $this->db->sql_fetchrow($result);
591
592
			$note = $this->display_note($data['link_note'], $data['link_vote'], true);
593
594
			$json_response = new \phpbb\json_response;
595
			$json_response->send(array(
596
				'success' => true,
597
598
				'MESSAGE_TITLE'	=> $this->language->lang('INFORMATION'),
599
				'MESSAGE_TEXT'	=> $this->language->lang('DIR_VOTE_OK'),
600
				'NOTE'			=> $note,
601
				'NB_VOTE'		=> $this->language->lang('DIR_NB_VOTES', (int) $data['link_vote']),
602
				'LINK_ID'		=> $link_id
603
			));
604
		}
605
	}
606
607
	/**
608
	* Search an appropriate thumb for url
609
	*
610
	* @param	string	$url	Link's url
611
	* @return	string			The thumb url
612
	*/
613
	public function thumb_process($url)
614
	{
615
		if (!$this->config['dir_activ_thumb'])
616
		{
617
			return $this->root_path.'images/directory/nothumb.gif';
618
		}
619
620
		$details = parse_url($url);
621
622
		$root_url		= $details['scheme'].'://'.$details['host'];
623
		$absolute_url	= isset($details['path']) ? $root_url.$details['path'] : $root_url;
624
625
		if ($this->config['dir_activ_thumb_remote'] && $this->_ascreen_exist($details['scheme'], $details['host']))
626
		{
627
			return $root_url.'/ascreen.jpg';
628
		}
629
		return $this->config['dir_thumb_service'].$absolute_url;
630
	}
631
632
	/**
633
	* Check if ascreen thumb exists
634
	*
635
	* @param	string	$protocol	The protocol
636
	* @param	string	$host		The hostname
637
	* @return	bool				True if ascreen file exixts, else false
638
	*/
639
	private function _ascreen_exist($protocol, $host)
640
	{
641
		if (($thumb_info = $this->imagesize->getImageSize($protocol.'://'.$host.'/ascreen.jpg')) !== false)
642
		{
643
			// Obviously this is an image, we did some additional tests
644
			if ($thumb_info['width'] == '120' && $thumb_info['height'] == '90' && $thumb_info['type'] == 2)
645
			{
646
				return true;
647
			}
648
		}
649
		return false;
650
	}
651
652
	/**
653
	* Primary work on banner, can edit, copy or check a banner
654
	*
655
	* @param	string	$banner	The banner's remote url
656
	* @param	array	$error	The array error, passed by reference
657
	* @return	null
658
	*/
659
	public function banner_process(&$banner, &$error)
660
	{
661
		$old_banner = $this->request->variable('old_banner', '');
662
663
		$destination = $this->dir_helper->get_banner_path();
664
665
		// Can we upload?
666
		$can_upload = ($this->config['dir_storage_banner'] && $this->filesystem->exists($this->root_path . $destination) && $this->filesystem->is_writable($this->root_path . $destination) && (@ini_get('file_uploads') || strtolower(@ini_get('file_uploads')) == 'on')) ? true : false;
667
668
		if ($banner && $can_upload)
669
		{
670
			$file = $this->_banner_upload($banner, $error);
671
		}
672
		else if ($banner)
673
		{
674
			$file = $this->_banner_remote($banner, $error);
675
		}
676
		else if ($this->request->is_set_post('delete_banner') && $old_banner)
677
		{
678
			$this->_banner_delete($old_banner);
679
			return;
680
		}
681
682
		if (!sizeof($error))
683
		{
684
			if ($banner && $old_banner && !preg_match('/^(http:\/\/|https:\/\/|ftp:\/\/|ftps:\/\/|www\.).+/si', $old_banner))
685
			{
686
				$this->_banner_delete($old_banner);
687
			}
688
689
			$banner = !empty($file) ? $file : '';
690
		}
691
	}
692
693
	/**
694
	* Copy a remonte banner to server.
695
	* called by banner_process()
696
	*
697
	* @param	string	$banner The banner's remote url
698
	* @param	array	$error	The array error, passed by reference
699
	* @return	false|string	String if no errors, else false
700
	*/
701
	private function _banner_upload($banner, &$error)
702
	{
703
		/** @var \phpbb\files\upload $upload */
704
		$upload = $this->files_factory->get('upload')
705
			->set_error_prefix('DIR_BANNER_')
706
			->set_allowed_extensions(array('jpg', 'jpeg', 'gif', 'png'))
707
			->set_max_filesize($this->config['dir_banner_filesize'])
708
			->set_disallowed_content((isset($this->config['mime_triggers']) ? explode('|', $this->config['mime_triggers']) : false));
709
710
		$file = $upload->handle_upload('files.types.remote', $banner);
711
712
		$prefix = unique_id() . '_';
713
		$file->clean_filename('real', $prefix);
714
715
		if (sizeof($file->error))
716
		{
717
			$file->remove();
718
			$error = array_merge($error, $file->error);
719
			return false;
720
		}
721
722
		$destination = $this->dir_helper->get_banner_path();
723
724
		// Move file and overwrite any existing image
725
		$file->move_file($destination, true);
726
727
		return strtolower($file->get('realname'));
728
	}
729
730
	/**
731
	* Check than remote banner exists
732
	* called by banner_process()
733
	*
734
	* @param	string	$banner	The banner's remote url
735
	* @param	array	$error	The array error, passed by reference
736
	* @return	false|string	String if no errors, else false
737
	*/
738
	private function _banner_remote($banner, &$error)
739
	{
740
		if (!preg_match('#^(http|https|ftp)://#i', $banner))
741
		{
742
			$banner = 'http://' . $banner;
743
		}
744
		if (!preg_match('#^(http|https|ftp)://(?:(.*?\.)*?[a-z0-9\-]+?\.[a-z]{2,4}|(?:\d{1,3}\.){3,5}\d{1,3}):?([0-9]*?).*?\.(gif|jpg|jpeg|png)$#i', $banner))
745
		{
746
			$error[] = $this->language->lang('DIR_BANNER_URL_INVALID');
747
			return false;
748
		}
749
750
		// Get image dimensions
751
		if (($image_data = $this->imagesize->getImageSize($banner)) === false)
752
		{
753
			$error[] = $this->language->lang('DIR_BANNER_UNABLE_GET_IMAGE_SIZE');
754
			return false;
755
		}
756
757
		if (!empty($image_data) && ($image_data['width'] < 2 || $image_data['height'] < 2))
758
		{
759
			$error[] = $this->language->lang('DIR_BANNER_UNABLE_GET_IMAGE_SIZE');
760
			return false;
761
		}
762
763
		$width = $image_data['width'];
764
		$height = $image_data['height'];
765
766
		if ($width <= 0 || $height <= 0)
767
		{
768
			$error[] = $this->language->lang('DIR_BANNER_UNABLE_GET_IMAGE_SIZE');
769
			return false;
770
		}
771
772
		// Check image type
773
		$types		= \phpbb\files\upload::image_types();
774
		$extension	= strtolower(\phpbb\files\filespec::get_extension($banner));
775
776
		// Check if this is actually an image
777
		if ($file_stream = @fopen($banner, 'r'))
778
		{
779
			// Timeout after 1 second
780
			stream_set_timeout($file_stream, 1);
781
			// read some data to ensure headers are present
782
			fread($file_stream, 1024);
783
			$meta = stream_get_meta_data($file_stream);
784
			if (isset($meta['wrapper_data']['headers']) && is_array($meta['wrapper_data']['headers']))
785
			{
786
				$headers = $meta['wrapper_data']['headers'];
787
			}
788
			else if (isset($meta['wrapper_data']) && is_array($meta['wrapper_data']))
789
			{
790
				$headers = $meta['wrapper_data'];
791
			}
792
			else
793
			{
794
				$headers = array();
795
			}
796
797
			foreach ($headers as $header)
798
			{
799
				$header = preg_split('/ /', $header, 2);
800
				if (strtr(strtolower(trim($header[0], ':')), '_', '-') === 'content-type')
801
				{
802
					if (strpos($header[1], 'image/') !== 0)
803
					{
804
						$error[] = 'DIR_BANNER_URL_INVALID';
805
						fclose($file_stream);
806
						return false;
807
					}
808
					else
809
					{
810
						fclose($file_stream);
811
						break;
812
					}
813
				}
814
			}
815
		}
816
		else
817
		{
818
			$error[] = 'DIR_BANNER_URL_INVALID';
819
			return false;
820
		}
821
822
		if (!empty($image_data) && (!isset($types[$image_data['type']]) || !in_array($extension, $types[$image_data['type']])))
823
		{
824
			if (!isset($types[$image_data['type']]))
825
			{
826
				$error[] = $this->language->lang('UNABLE_GET_IMAGE_SIZE');
827
			}
828
			else
829
			{
830
				$error[] = $this->language->lang('DIR_BANNER_IMAGE_FILETYPE_MISMATCH', $types[$image_data['type']][0], $extension);
831
			}
832
			return false;
833
		}
834
835
		if (($this->config['dir_banner_width'] || $this->config['dir_banner_height']) && ($width > $this->config['dir_banner_width'] || $height > $this->config['dir_banner_height']))
836
		{
837
			$error[] = $this->language->lang('DIR_BANNER_WRONG_SIZE', $this->config['dir_banner_width'], $this->config['dir_banner_height'], $width, $height);
838
			return false;
839
		}
840
841
		return $banner;
842
	}
843
844
	/**
845
	* Delete a banner from server
846
	*
847
	* @param	string	$file	The file's name
848
	* @return	bool			True if delete success, else false
849
	*/
850
	private function _banner_delete($file)
851
	{
852
		if (file_exists($this->dir_helper->get_banner_path($file)))
853
		{
854
			@unlink($this->dir_helper->get_banner_path($file));
855
			return true;
856
		}
857
858
		return false;
859
	}
860
861
	/**
862
	* PageRank Lookup (Based on Google Toolbar for Mozilla Firefox)
863
	*
864
	* @copyright 2012 HM2K <[email protected]>
865
	* @link http://pagerank.phurix.net/
866
	* @author James Wade <[email protected]>
867
	* @version $Revision: 2.1 $
868
	* @require PHP 4.3.0 (file_get_contents)
869
	* @updated 06/10/11
870
	*
871
	* @param	string		$q	The website URL
872
	* @return	string			The calculated pagerank, or -1
873
	*/
874
	public function pagerank_process($q)
875
	{
876
		$googleDomains	= array('.com', '.com.tr', '.de', '.fr', '.be', '.ca', '.ro', '.ch');
877
		$seed			= $this->language->lang('SEED');
878
		$result			= 0x01020345;
879
		$len			= strlen($q);
880
881
		for ($i=0; $i<$len; $i++)
882
		{
883
			$result ^= ord($seed{$i%strlen($seed)}) ^ ord($q{$i});
884
			$result = (($result >> 23) & 0x1ff) | $result << 9;
885
		}
886
887
		if (PHP_INT_MAX != 2147483647)
888
		{
889
			$result = -(~($result & 0xFFFFFFFF) + 1);
890
		}
891
892
		$ch		= sprintf('8%x', $result);
893
		$url	= 'http://%s/tbr?client=navclient-auto&ch=%s&features=Rank&q=info:%s';
894
		$host	= 'toolbarqueries.google'.$googleDomains[mt_rand(0,count($googleDomains)-1)];
895
896
		$url	= sprintf($url,$host,$ch,$q);
897
		@$pr	= trim(file_get_contents($url,false));
898
899
		if (is_numeric(substr(strrchr($pr, ':'), 1)))
900
		{
901
			return substr(strrchr($pr, ':'), 1);
902
		}
903
		return '-1';
904
	}
905
906
	/**
907
	* List flags
908
	*
909
	* @param	string	$flag_path	The flag directory path
910
	* @param	string	$value		Selected flag
911
	* @return	string	$list		Html code
912
	*/
913
	public function get_dir_flag_list($flag_path, $value)
914
	{
915
		$list = '';
916
917
		$this->language->add_lang('directory_flags', 'ernadoo/phpbbdirectory');
918
919
		$flags = $this->dir_helper->preg_grep_keys('/^DIR_FLAG_CODE_/i', $this->language->get_lang_array());
920
921
		if (extension_loaded('intl'))
922
		{
923
			$locale = $this->language->lang('USER_LANG');
924
925
			$col = new \Collator($locale);
926
			$col->asort($flags);
927
		}
928
		else
929
		{
930
			asort($flags);
931
		}
932
933
		foreach ($flags as $file => $name)
934
		{
935
			$img_file = strtolower(substr(strrchr($file, '_'), 1)).'.png';
936
937
			if (file_exists($flag_path.$img_file))
938
			{
939
				$list .= '<option value="' . $img_file . '" ' . (($img_file == $value) ? 'selected="selected"' : '') . '>' . $name . '</option>';
940
			}
941
		}
942
943
		return $list;
944
	}
945
946
	/**
947
	* Display recents links added
948
	*
949
	* @return	null
950
	*/
951
	public function recents()
952
	{
953
		if ($this->config['dir_recent_block'])
954
		{
955
			$limit_sql		= $this->config['dir_recent_rows'] * $this->config['dir_recent_columns'];
956
			$exclude_array	= explode(',', str_replace(' ', '', $this->config['dir_recent_exclude']));
957
958
			$sql_array = array(
959
				'SELECT'	=> 'l.link_id, l.link_cat, l.link_url, l.link_user_id, l.link_comment, l. link_description, l.link_vote, l.link_note, l.link_view, l.link_time, l.link_name, l.link_thumb, u.user_id, u.username, u.user_colour, c.cat_name',
960
				'FROM'		=> array(
961
						DIR_LINK_TABLE	=> 'l'),
962
				'LEFT_JOIN'	=> array(
963
						array(
964
							'FROM'	=> array(USERS_TABLE	=> 'u'),
965
							'ON'	=> 'l.link_user_id = u.user_id'
966
						),
967
						array(
968
							'FROM'	=> array(DIR_CAT_TABLE => 'c'),
969
							'ON'	=> 'l.link_cat = c.cat_id'
970
						)
971
				),
972
				'WHERE'		=> $this->db->sql_in_set('l.link_cat', $exclude_array, true).' AND l.link_active = 1',
973
				'ORDER_BY'	=> 'l.link_time DESC, l.link_id DESC');
974
975
			$sql = $this->db->sql_build_query('SELECT', $sql_array);
976
			$result = $this->db->sql_query_limit($sql, $limit_sql, 0);
977
			$num = 0;
978
			$rowset = array();
979
980
			while ($site = $this->db->sql_fetchrow($result))
981
			{
982
				$rowset[$site['link_id']] = $site;
983
			}
984
			$this->db->sql_freeresult($result);
985
986
			if (sizeof($rowset))
987
			{
988
				$this->template->assign_block_vars('block', array(
989
					'S_COL_WIDTH'			=> (100 / $this->config['dir_recent_columns']) . '%',
990
				));
991
992
				foreach ($rowset as $row)
993
				{
994
					if (($num % $this->config['dir_recent_columns']) == 0)
995
					{
996
						$this->template->assign_block_vars('block.row', array());
997
					}
998
999
					$this->template->assign_block_vars('block.row.col', array(
1000
						'UC_THUMBNAIL'            => '<a href="'.$row['link_url'].'" onclick="window.open(\''.$this->helper->route('ernadoo_phpbbdirectory_view_controller', array('link_id' => (int) $row['link_id'])).'\'); return false;"><img src="'.$row['link_thumb'].'" title="'.$row['link_name'].'" alt="'.$row['link_name'].'" /></a>',
1001
						'NAME'                    => $row['link_name'],
1002
						'USER'                    => get_username_string('full', $row['link_user_id'], $row['username'], $row['user_colour']),
1003
						'TIME'                    => ($row['link_time']) ? $this->user->format_date($row['link_time']) : '',
1004
						'CAT'                     => $row['cat_name'],
1005
						'COUNT'					  => $row['link_view'],
1006
						'COMMENT'                 => $row['link_comment'],
1007
1008
						'U_CAT'                   => $this->helper->route('ernadoo_phpbbdirectory_page_controller', array('cat_id' => (int) $row['link_cat'])),
1009
						'U_COMMENT'               => $this->helper->route('ernadoo_phpbbdirectory_comment_view_controller', array('link_id' => (int) $row['link_id'])),
1010
1011
						'L_DIR_SEARCH_NB_CLICKS'	=> $this->language->lang('DIR_SEARCH_NB_CLICKS', (int) $row['link_view']),
1012
						'L_DIR_SEARCH_NB_COMMS'		=> $this->language->lang('DIR_SEARCH_NB_COMMS', (int) $row['link_comment']),
1013
					));
1014
					$num++;
1015
				}
1016
1017
				while (($num % $this->config['dir_recent_columns']) != 0)
1018
				{
1019
					$this->template->assign_block_vars('block.row.col2', array());
1020
					$num++;
1021
				}
1022
			}
1023
		}
1024
	}
1025
1026
	/**
1027
	* Validate back link
1028
	*
1029
	* @param	string		$remote_url	Page URL contains the backlink
1030
	* @param	bool		$optional	Link back is optional in this category?
1031
	* @param	bool		$cron		This methos is called by con process?
1032
	* @return	false|string			Either false if validation succeeded or a string which will be used as the error message (with the variable name appended)
1033
	*/
1034
	public function validate_link_back($remote_url, $optional, $cron = false)
1035
	{
1036
		if (!$cron)
1037
		{
1038
			if (empty($remote_url) && $optional)
1039
			{
1040
				return false;
1041
			}
1042
1043
			if (!preg_match('#^http[s]?://(.*?\.)*?[a-z0-9\-]+\.[a-z]{2,4}#i', $remote_url))
1044
			{
1045
				return 'DIR_ERROR_WRONG_DATA_BACK';
1046
			}
1047
		}
1048
1049
		if (false === ($handle = @fopen($remote_url, 'r')))
1050
		{
1051
			return 'DIR_ERROR_NOT_FOUND_BACK';
1052
		}
1053
1054
		$buff = '';
1055
1056
		// Read by packet, faster than file_get_contents()
1057
		while (!feof($handle))
1058
		{
1059
			$buff .= fgets($handle, 256);
1060
1061
			if (stristr($buff, $this->config['server_name']))
1062
			{
1063
				@fclose($handle);
1064
				return false;
1065
			}
1066
		}
1067
		@fclose($handle);
1068
1069
		return 'DIR_ERROR_NO_LINK_BACK';
1070
	}
1071
1072
	/**
1073
	* Check, for website with backlink specified, if backlink is always here.
1074
	* After $nb_check verification, website is deleted, otherwise, a notification is send to poster
1075
	*
1076
	* @param	int		$cat_id		The categoryID
1077
	* @param	int		$nb_check	Number of check before demete a website
1078
	* @param	int		$next_prune	Date of next auto check
1079
	* @return	null
1080
	*/
1081
	private function _check($cat_id, $nb_check, $next_prune)
1082
	{
1083
		$del_array = $update_array = array();
1084
1085
		$sql_array = array(
1086
			'SELECT'	=> 'link_id, link_cat, link_back, link_guest_email, link_nb_check, link_user_id, link_name, link_url, link_description, u.user_lang, u.user_dateformat',
1087
			'FROM'		=> array(
1088
					DIR_LINK_TABLE	=> 'l'),
1089
			'LEFT_JOIN'	=> array(
1090
					array(
1091
						'FROM'	=> array(USERS_TABLE	=> 'u'),
1092
						'ON'	=> 'l.link_user_id = u.user_id'
1093
					)
1094
			),
1095
			'WHERE'		=> 'l.link_back <> "" AND l.link_active = 1 AND l.link_cat = '  . (int) $cat_id);
1096
1097
		$sql = $this->db->sql_build_query('SELECT', $sql_array);
1098
		$result = $this->db->sql_query($sql);
1099
1100
		while ($row = $this->db->sql_fetchrow($result))
1101
		{
1102
			if ($this->validate_link_back($row['link_back'], false, true) !== false)
1103
			{
1104
				if (!$nb_check || ($row['link_nb_check']+1) >= $nb_check)
1105
				{
1106
					$del_array[] = $row['link_id'];
1107
				}
1108
				else
1109
				{
1110
					// A first table containing links ID to update
1111
					$update_array[$row['link_id']] = $row;
1112
				}
1113
			}
1114
		}
1115
		$this->db->sql_freeresult($result);
1116
1117
		if (sizeof($del_array))
1118
		{
1119
			$this->del($cat_id, $del_array);
1120
		}
1121
		if (sizeof($update_array))
1122
		{
1123
			$this->_update_check($update_array, $next_prune);
1124
		}
1125
	}
1126
1127
	/**
1128
	* Method called by cron task.
1129
	*
1130
	* @param	array	$cat_data	Information about category, from db
1131
	* @return	null
1132
	*/
1133
	public function auto_check($cat_data)
1134
	{
1135
		global $phpbb_log;
1136
1137
		$sql = 'SELECT cat_name
1138
			FROM ' . DIR_CAT_TABLE . '
1139
			WHERE cat_id = ' . (int) $cat_data['cat_id'];
1140
		$result = $this->db->sql_query($sql);
1141
		$row = $this->db->sql_fetchrow($result);
1142
		$this->db->sql_freeresult($result);
1143
1144
		if ($row)
1145
		{
1146
			$next_prune = time() + ($cat_data['cat_cron_freq'] * 86400);
1147
1148
			$this->_check($cat_data['cat_id'], $cat_data['cat_cron_nb_check'], $next_prune);
1149
1150
			$sql = 'UPDATE ' . DIR_CAT_TABLE . "
1151
				SET cat_cron_next = $next_prune
1152
				WHERE cat_id = " . (int) $cat_data['cat_id'];
1153
			$this->db->sql_query($sql);
1154
1155
			$phpbb_log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_DIR_AUTO_PRUNE', time(), array($row['cat_name']));
1156
		}
1157
1158
		return;
1159
	}
1160
1161
	/**
1162
	* Update website verification number after a missing backlink, and send notificaton
1163
	*
1164
	* @param	array	$u_array	Information about website
1165
	* @param	int		$next_prune	Date of next auto check
1166
	* @return	null
1167
	*/
1168
	private function _update_check($u_array, $next_prune)
1169
	{
1170
		if (!class_exists('messenger'))
1171
		{
1172
			include($this->root_path . 'includes/functions_messenger.' . $this->php_ext);
1173
		}
1174
1175
		$messenger = new \messenger(false);
1176
1177
		// cron.php don't call $user->setup(), so $this->timezone is unset.
1178
		// We need to define it, because we use user->format_date below
1179
		$this->user->timezone = new \DateTimeZone($this->config['board_timezone']);
1180
1181
		$sql = 'UPDATE ' . DIR_LINK_TABLE . '
1182
			SET link_nb_check = link_nb_check + 1
1183
			WHERE ' . $this->db->sql_in_set('link_id', array_keys($u_array));
1184
		$this->db->sql_query($sql);
1185
1186
		foreach ($u_array as $data)
1187
		{
1188
			strip_bbcode($data['link_description']);
1189
1190
			$notification_data = array(
1191
					'cat_name'			=> \ernadoo\phpbbdirectory\core\categorie::getname((int) $data['link_cat']),
1192
					'link_id'			=> $data['link_id'],
1193
					'link_user_id'		=> $data['link_user_id'],
1194
					'link_name'			=> $data['link_name'],
1195
					'link_url'			=> $data['link_url'],
1196
					'link_description'	=> $data['link_description'],
1197
					'next_cron' 		=> $this->user->format_date($next_prune, $data['user_dateformat']),
1198
			);
1199
1200
			if ($data['link_nb_check'])
1201
			{
1202
				$this->notification->delete_notifications('ernadoo.phpbbdirectory.notification.type.directory_website_error_cron', $notification_data);
1203
			}
1204
1205
			// New notification system can't send mail to an anonymous user with an email address stored in another table than phpbb_users
1206
			if ($data['link_user_id'] == ANONYMOUS)
1207
			{
1208
				$username = $email = $data['link_guest_email'];
1209
1210
				$messenger->template('@ernadoo_phpbbdirectory/directory_website_error_cron', $data['user_lang']);
1211
				$messenger->to($email, $username);
1212
1213
				$messenger->assign_vars(array(
1214
					'USERNAME'			=> htmlspecialchars_decode($username),
1215
					'LINK_NAME'			=> $data['link_name'],
1216
					'LINK_URL'			=> $data['link_url'],
1217
					'LINK_DESCRIPTION'	=> $data['link_description'],
1218
					'NEXT_CRON' 		=> $this->user->format_date($next_prune, $data['user_dateformat']),
1219
				));
1220
1221
				$messenger->send(NOTIFY_EMAIL);
1222
			}
1223
			else
1224
			{
1225
				$this->notification->add_notifications('ernadoo.phpbbdirectory.notification.type.directory_website_error_cron', $notification_data);
1226
			}
1227
		}
1228
	}
1229
}
1230