Completed
Push — master ( b05d49...46e7ff )
by Erwan
02:47
created

link   D

Complexity

Total Complexity 163

Size/Duplication

Total Lines 1186
Duplicated Lines 2.28 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

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

28 Methods

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