Completed
Push — master ( e866d6...19d1cc )
by Erwan
03:14
created

link::checkurl()   C

Complexity

Conditions 7
Paths 48

Size

Total Lines 41
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
c 4
b 0
f 0
dl 0
loc 41
rs 6.7272
cc 7
eloc 21
nc 48
nop 1
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
			if ($parts[1] == '404')
332
			{
333
				return false;
334
			}
335
336
			return true;
337
		}
338
		return false;
339
	}
340
341
	/**
342
	* Delete the final '/', if no path
343
	*
344
	* @param	string	$url	URL to clean
345
	* @return	string	$url	The correct string.
346
	*/
347
	public function clean_url($url)
348
	{
349
		$details = parse_url($url);
350
351
		if (isset($details['path']) && $details['path'] == '/' && !isset($details['query']))
352
		{
353
			return substr($url, 0, -1);
354
		}
355
		return $url;
356
	}
357
358
	/**
359
	* Display a flag
360
	*
361
	* @param	array	$data	Link's data from db
362
	* @return	string			Flag path.
363
	*/
364
	public function display_flag($data)
365
	{
366
		global $phpbb_extension_manager;
367
368
		$ext_path = $phpbb_extension_manager->get_extension_path('ernadoo/phpbbdirectory', false);
369
		$flag_path = $ext_path.'images/flags/';
370
		$img_flag = 'no_flag.png';
371
372
		if ($this->config['dir_activ_flag'] && !empty($data['link_flag']) && file_exists($flag_path . $data['link_flag']))
373
		{
374
			$img_flag = $data['link_flag'];
375
		}
376
377
		return $this->dir_helper->get_img_path('flags', $img_flag);
378
	}
379
380
	/**
381
	* Calculate the link's note
382
	*
383
	* @param	int		$total_note		Sum of all link's notes
384
	* @param	int		$nb_vote		Number of votes
385
	* @param	bool	$votes_status	Votes are enable in this category?
386
	* @return	string	$note			The calculated note.
387
	*/
388
	public function display_note($total_note, $nb_vote, $votes_status)
389
	{
390
		if (!$votes_status)
391
		{
392
			return;
393
		}
394
395
		$note = ($nb_vote < 1) ? '' : $total_note / $nb_vote;
396
		$note = (strlen($note) > 2) ? number_format($note, 1) : $note;
397
398
		return ($nb_vote) ? $this->user->lang('DIR_FROM_TEN', $note) : $this->user->lang['DIR_NO_NOTE'];
399
	}
400
401
	/**
402
	* Display the vote form for auth users
403
	*
404
	* @param	array	$data	Link's data from db
405
	* @return	null|string		Html combo list or nothing if votes are not available.
406
	*/
407
	public function display_vote($data)
408
	{
409
		if ($this->user->data['is_registered'] && $this->auth->acl_get('u_vote_dir') && empty($data['vote_user_id']))
410
		{
411
			$list = '<select name="vote">';
412
			for ($i = 0; $i <= 10; $i++)
413
			{
414
				$list .= '<option value="' . $i . '"' . (($i == 5) ? ' selected="selected"' : '') . '>' . $i . '</option>';
415
			}
416
			$list .= '</select>';
417
418
			return $list;
419
		}
420
	}
421
422
	/**
423
	* Display the RSS icon
424
	*
425
	* @param	array	$data	Link's data from db
426
	* @return	null|string		RSS feed URL or nothing.
427
	*/
428
	public function display_rss($data)
429
	{
430
		if ($this->config['dir_activ_rss'] && !empty($data['link_rss']))
431
		{
432
				return $data['link_rss'];
433
		}
434
	}
435
436
	/**
437
	* Display link's thumb if thumb service enabled.
438
	* if thumb don't exists in db or if a new service was choosen in acp
439
	* thumb is research
440
	*
441
	* @param	array		$data	Link's data from db
442
	* @return	string|null			Thumb or null.
443
	*/
444
	public function display_thumb($data)
445
	{
446
		if ($this->config['dir_activ_thumb'])
447
		{
448
			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'])))))
449
			{
450
				$thumb = $this->thumb_process($data['link_url']);
451
452
				$sql = 'UPDATE ' . DIR_LINK_TABLE . '
453
					SET link_thumb = "' . $this->db->sql_escape($thumb) . '"
454
					WHERE link_id = ' . (int) $data['link_id'];
455
				$this->db->sql_query($sql);
456
457
				return $thumb;
458
			}
459
			return $data['link_thumb'];
460
		}
461
	}
462
463
	/**
464
	* Display and calculate PageRank if needed
465
	*
466
	* @param	array	$data	Link's data from db
467
	* @return	string			Pagerank, 'n/a' or false
468
	*/
469
	public function display_pagerank($data)
470
	{
471
		if ($this->config['dir_activ_pagerank'])
472
		{
473
			if ($data['link_pagerank'] == '')
474
			{
475
				$pagerank = $this->pagerank_process($data['link_url']);
476
477
				$sql = 'UPDATE ' . DIR_LINK_TABLE . '
478
					SET link_pagerank = ' . (int) $pagerank . '
479
					WHERE link_id = ' . (int) $data['link_id'];
480
				$this->db->sql_query($sql);
481
			}
482
			else
483
			{
484
				$pagerank = (int) $data['link_pagerank'];
485
			}
486
487
			$prpos=40*$pagerank/10;
488
			$prneg=40-$prpos;
489
			$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.'" /> ';
490
491
			$pagerank = $pagerank == '-1' ? $this->user->lang['DIR_PAGERANK_NOT_AVAILABLE'] : $this->user->lang('DIR_FROM_TEN', $pagerank);
492
			return $html.$pagerank;
493
		}
494
		return false;
495
	}
496
497
	/**
498
	* Display and resize a banner
499
	*
500
	* @param	array	$data		link's data from db
501
	* @return	string	$s_banner	html code.
502
	*/
503
	public function display_bann($data)
504
	{
505
		$s_banner = '';
506
507
		if (!empty($data['link_banner']))
508
		{
509
			if (!preg_match('/^(http:\/\/|https:\/\/|ftp:\/\/|ftps:\/\/|www\.).+/si', $data['link_banner']))
510
			{
511
				$img_src = $this->helper->route('ernadoo_phpbbdirectory_banner_controller', array('banner_img' => $data['link_banner']));
512
				$physical_path = $this->dir_helper->get_banner_path($data['link_banner']);
513
			}
514
			else
515
			{
516
				$img_src = $physical_path = $data['link_banner'];
517
			}
518
519
			list($width, $height) = @getimagesize($physical_path);
520
			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)
521
			{
522
				$coef_w = $width / $this->config['dir_banner_width'];
523
				$coef_h = $height / $this->config['dir_banner_height'];
524
				$coef_max = max($coef_w, $coef_h);
525
				$width /= $coef_max;
526
				$height /= $coef_max;
527
			}
528
529
			$s_banner = '<img src="' . $img_src . '" width="' . $width . '" height="' . $height . '" alt="'.$data['link_name'].'" title="'.$data['link_name'].'" />';
530
		}
531
532
		return $s_banner;
533
	}
534
535
	/**
536
	* Add a vote in db, for a specifi link
537
	*
538
	* @param	int		$link_id	Link_id from db
539
	* @return	null
540
	*/
541
	public function add_vote($link_id)
542
	{
543
		$data = array(
544
			'vote_link_id' 		=> (int) $link_id,
545
			'vote_user_id' 		=> $this->user->data['user_id'],
546
			'vote_note'			=> $this->request->variable('vote', 0),
547
		);
548
549
		$this->db->sql_transaction('begin');
550
551
		$sql = 'INSERT INTO ' . DIR_VOTE_TABLE . ' ' . $this->db->sql_build_array('INSERT', $data);
552
		$this->db->sql_query($sql);
553
554
		$sql = 'UPDATE ' . DIR_LINK_TABLE . '
555
			SET link_vote = link_vote + 1,
556
			link_note = link_note + ' . (int) $data['vote_note'] . '
557
		WHERE link_id = ' . (int) $link_id;
558
		$this->db->sql_query($sql);
559
560
		$this->db->sql_transaction('commit');
561
562
		if ($this->request->is_ajax())
563
		{
564
			$sql= 'SELECT link_vote, link_note FROM ' . DIR_LINK_TABLE . ' WHERE link_id = ' . (int) $link_id;
565
			$result = $this->db->sql_query($sql);
566
			$data = $this->db->sql_fetchrow($result);
567
568
			$note = $this->display_note($data['link_note'], $data['link_vote'], true);
569
570
			$json_response = new \phpbb\json_response;
571
			$json_response->send(array(
572
				'success' => true,
573
574
				'MESSAGE_TITLE'	=> $this->user->lang['INFORMATION'],
575
				'MESSAGE_TEXT'	=> $this->user->lang['DIR_VOTE_OK'],
576
				'NOTE'			=> $note,
577
				'NB_VOTE'		=> $this->user->lang('DIR_NB_VOTES', (int) $data['link_vote']),
578
				'LINK_ID'		=> $link_id
579
			));
580
		}
581
	}
582
583
	/**
584
	* Search an appropriate thumb for url
585
	*
586
	* @param	string	$url	Link's url
587
	* @return	string			The thumb url
588
	*/
589
	public function thumb_process($url)
590
	{
591
		if (!$this->config['dir_activ_thumb'])
592
		{
593
			return $this->root_path.'images/directory/nothumb.gif';
594
		}
595
596
		$details = parse_url($url);
597
598
		$root_url		= $details['scheme'].'://'.$details['host'];
599
		$absolute_url	= isset($details['path']) ? $root_url.$details['path'] : $root_url;
600
601
		if ($this->config['dir_activ_thumb_remote'] && $this->_ascreen_exist($details['scheme'], $details['host']))
602
		{
603
			return $root_url.'/ascreen.jpg';
604
		}
605
		return $this->config['dir_thumb_service'].$absolute_url;
606
	}
607
608
	/**
609
	* Check if ascreen thumb exists
610
	*
611
	* @param	string	$protocol	The protocol
612
	* @param	string	$host		The hostname
613
	* @return	bool				True if ascreen file exixts, else false
614
	*/
615
	private function _ascreen_exist($protocol, $host)
616
	{
617
		if ($thumb_info = @getimagesize($protocol.'://'.$host.'/ascreen.jpg'))
618
		{
619
			// Obviously this is an image, we did some additional tests
620
			if ($thumb_info[0] == '120' && $thumb_info[1] == '90' && $thumb_info['mime'] == 'image/jpeg')
621
			{
622
				return true;
623
			}
624
		}
625
		return false;
626
	}
627
628
	/**
629
	* Primary work on banner, can edit, copy or check a banner
630
	*
631
	* @param	string	$banner	The banner's remote url
632
	* @param	array	$error	The array error, passed by reference
633
	* @return	null
634
	*/
635
	public function banner_process(&$banner, &$error)
636
	{
637
		$old_banner = $this->request->variable('old_banner', '');
638
639
		$destination = $this->dir_helper->get_banner_path();
640
641
		// Can we upload?
642
		$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;
643
644
		if ($banner && $can_upload)
645
		{
646
			$file = $this->_banner_upload($banner, $error);
647
		}
648
		else if ($banner)
649
		{
650
			$file = $this->_banner_remote($banner, $error);
651
		}
652
		else if ($this->request->is_set_post('delete_banner') && $old_banner)
653
		{
654
			$this->_banner_delete($old_banner);
655
			return;
656
		}
657
658
		if (!sizeof($error))
659
		{
660
			if ($banner && $old_banner && !preg_match('/^(http:\/\/|https:\/\/|ftp:\/\/|ftps:\/\/|www\.).+/si', $old_banner))
661
			{
662
				$this->_banner_delete($old_banner);
663
			}
664
665
			$banner = !empty($file) ? $file : '';
666
		}
667
	}
668
669
	/**
670
	* Copy a remonte banner to server.
671
	* called by banner_process()
672
	*
673
	* @param	string	$banner The anner's remote url
674
	* @param	array	$error	The array error, passed by reference
675
	* @return	false|string	String if no errors, else false
676
	*/
677
	private function _banner_upload($banner, &$error)
678
	{
679
		// Init upload class
680
		if (!class_exists('fileupload'))
681
		{
682
			include($this->root_path . 'includes/functions_upload.' . $this->php_ext);
683
		}
684
		$upload = new \fileupload('DIR_BANNER_', array('jpg', 'jpeg', 'gif', 'png'), $this->config['dir_banner_filesize']);
685
686
		$file = $upload->remote_upload($banner);
687
688
		$prefix = unique_id() . '_';
689
		$file->clean_filename('real', $prefix);
690
691
		$destination = $this->dir_helper->get_banner_path();
692
693
		// Move file and overwrite any existing image
694
		$file->move_file($destination, true);
695
696
		if (sizeof($file->error))
697
		{
698
			$file->remove();
699
			$error = array_merge($error, $file->error);
700
			return false;
701
		}
702
703
		return $prefix .strtolower($file->uploadname);
704
	}
705
706
	/**
707
	* Check than remote banner exists
708
	* called by banner_process()
709
	*
710
	* @param	string	$banner	The banner's remote url
711
	* @param	array	$error	The array error, passed by reference
712
	* @return	false|string	String if no errors, else false
713
	*/
714
	private function _banner_remote($banner, &$error)
715
	{
716
		if (!preg_match('#^(http|https|ftp)://#i', $banner))
717
		{
718
			$banner = 'http://' . $banner;
719
		}
720
		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))
721
		{
722
			$error[] = $this->user->lang['DIR_BANNER_URL_INVALID'];
723
			return false;
724
		}
725
726
		// Make sure getimagesize works...
727
		if (($image_data = @getimagesize($banner)) === false)
728
		{
729
			$error[] = $this->user->lang['DIR_BANNER_UNABLE_GET_IMAGE_SIZE'];
730
			return false;
731
		}
732
733
		if (!empty($image_data) && ($image_data[0] < 2 || $image_data[1] < 2))
734
		{
735
			$error[] = $this->user->lang['DIR_BANNER_UNABLE_GET_IMAGE_SIZE'];
736
			return false;
737
		}
738
739
		$width = $image_data[0];
740
		$height = $image_data[1];
741
742
		// Check image type
743
		if (!class_exists('fileupload'))
744
		{
745
			include($this->root_path . 'includes/functions_upload.' . $this->php_ext);
746
		}
747
748
		$types		= \fileupload::image_types();
749
		$extension	= strtolower(\filespec::get_extension($banner));
750
751
		// Check if this is actually an image
752
		if ($file_stream = @fopen($banner, 'r'))
753
		{
754
			// Timeout after 1 second
755
			stream_set_timeout($file_stream, 1);
756
			// read some data to ensure headers are present
757
			fread($file_stream, 1024);
758
			$meta = stream_get_meta_data($file_stream);
759
			if (isset($meta['wrapper_data']['headers']) && is_array($meta['wrapper_data']['headers']))
760
			{
761
				$headers = $meta['wrapper_data']['headers'];
762
			}
763
			else if (isset($meta['wrapper_data']) && is_array($meta['wrapper_data']))
764
			{
765
				$headers = $meta['wrapper_data'];
766
			}
767
			else
768
			{
769
				$headers = array();
770
			}
771
772
			foreach ($headers as $header)
773
			{
774
				$header = preg_split('/ /', $header, 2);
775
				if (strtr(strtolower(trim($header[0], ':')), '_', '-') === 'content-type')
776
				{
777
					if (strpos($header[1], 'image/') !== 0)
778
					{
779
						$error[] = 'DIR_BANNER_URL_INVALID';
780
						fclose($file_stream);
781
						return false;
782
					}
783
					else
784
					{
785
						fclose($file_stream);
786
						break;
787
					}
788
				}
789
			}
790
		}
791
		else
792
		{
793
			$error[] = 'DIR_BANNER_URL_INVALID';
794
			return false;
795
		}
796
797
		if (!empty($image_data) && (!isset($types[$image_data[2]]) || !in_array($extension, $types[$image_data[2]])))
798
		{
799
			if (!isset($types[$image_data[2]]))
800
			{
801
				$error[] = $this->user->lang['UNABLE_GET_IMAGE_SIZE'];
802
			}
803
			else
804
			{
805
				$error[] = $this->user->lang('DIR_BANNER_IMAGE_FILETYPE_MISMATCH', $types[$image_data[2]][0], $extension);
806
			}
807
			return false;
808
		}
809
810
		if (($this->config['dir_banner_width'] || $this->config['dir_banner_height']) && ($width > $this->config['dir_banner_width'] || $height > $this->config['dir_banner_height']))
811
		{
812
			$error[] = $this->user->lang('DIR_BANNER_WRONG_SIZE', $this->config['dir_banner_width'], $this->config['dir_banner_height'], $width, $height);
813
			return false;
814
		}
815
816
		return $banner;
817
	}
818
819
	/**
820
	* Delete a banner from server
821
	*
822
	* @param	string	$file	The file's name
823
	* @return	bool			True if delete success, else false
824
	*/
825
	private function _banner_delete($file)
826
	{
827
		if (file_exists($this->dir_helper->get_banner_path($file)))
828
		{
829
			@unlink($this->dir_helper->get_banner_path($file));
830
			return true;
831
		}
832
833
		return false;
834
	}
835
836
	/**
837
	* PageRank Lookup (Based on Google Toolbar for Mozilla Firefox)
838
	*
839
	* @copyright 2012 HM2K <[email protected]>
840
	* @link http://pagerank.phurix.net/
841
	* @author James Wade <[email protected]>
842
	* @version $Revision: 2.1 $
843
	* @require PHP 4.3.0 (file_get_contents)
844
	* @updated 06/10/11
845
	*
846
	* @param	string		$q	The website URL
847
	* @return	string			The calculated pagerank, or -1
848
	*/
849
	public function pagerank_process($q)
850
	{
851
		$googleDomains	= array('.com', '.com.tr', '.de', '.fr', '.be', '.ca', '.ro', '.ch');
852
		$seed			= $this->user->lang['SEED'];
853
		$result			= 0x01020345;
854
		$len			= strlen($q);
855
856
		for ($i=0; $i<$len; $i++)
857
		{
858
			$result ^= ord($seed{$i%strlen($seed)}) ^ ord($q{$i});
859
			$result = (($result >> 23) & 0x1ff) | $result << 9;
860
		}
861
862
		if (PHP_INT_MAX != 2147483647)
863
		{
864
			$result = -(~($result & 0xFFFFFFFF) + 1);
865
		}
866
867
		$ch		= sprintf('8%x', $result);
868
		$url	= 'http://%s/tbr?client=navclient-auto&ch=%s&features=Rank&q=info:%s';
869
		$host	= 'toolbarqueries.google'.$googleDomains[mt_rand(0,count($googleDomains)-1)];
870
871
		$url	= sprintf($url,$host,$ch,$q);
872
		@$pr	= trim(file_get_contents($url,false));
873
874
		if (is_numeric(substr(strrchr($pr, ':'), 1)))
875
		{
876
			return substr(strrchr($pr, ':'), 1);
877
		}
878
		return '-1';
879
	}
880
881
	/**
882
	* List flags
883
	*
884
	* @param	string	$flag_path	The flag directory path
885
	* @param	string	$value		Selected flag
886
	* @return	string	$list		Html code
887
	*/
888
	public function get_dir_flag_list($flag_path, $value)
889
	{
890
		$list = '';
891
892
		$this->user->add_lang_ext('ernadoo/phpbbdirectory', 'directory_flags');
893
894
		$flags = $this->dir_helper->preg_grep_keys('/^DIR_FLAG_CODE_/i', $this->user->lang);
895
896
		if (extension_loaded('intl'))
897
		{
898
			$locale = $this->user->lang['USER_LANG'];
899
900
			$col = new \Collator($locale);
901
			$col->asort($flags);
902
		}
903
		else
904
		{
905
			asort($flags);
906
		}
907
908
		foreach ($flags as $file => $name)
909
		{
910
			$img_file = strtolower(substr(strrchr($file, '_'), 1)).'.png';
911
912
			if (file_exists($flag_path.$img_file))
913
			{
914
				$list .= '<option value="' . $img_file . '" ' . (($img_file == $value) ? 'selected="selected"' : '') . '>' . $name . '</option>';
915
			}
916
		}
917
918
		return $list;
919
	}
920
921
	/**
922
	* Display recents links added
923
	*
924
	* @return	null
925
	*/
926
	public function recents()
927
	{
928
		if ($this->config['dir_recent_block'])
929
		{
930
			$limit_sql		= $this->config['dir_recent_rows'] * $this->config['dir_recent_columns'];
931
			$exclude_array	= explode(',', str_replace(' ', '', $this->config['dir_recent_exclude']));
932
933
			$sql_array = array(
934
				'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',
935
				'FROM'		=> array(
936
						DIR_LINK_TABLE	=> 'l'),
937
				'LEFT_JOIN'	=> array(
938
						array(
939
							'FROM'	=> array(USERS_TABLE	=> 'u'),
940
							'ON'	=> 'l.link_user_id = u.user_id'
941
						),
942
						array(
943
							'FROM'	=> array(DIR_CAT_TABLE => 'c'),
944
							'ON'	=> 'l.link_cat = c.cat_id'
945
						)
946
				),
947
				'WHERE'		=> $this->db->sql_in_set('l.link_cat', $exclude_array, true).' AND l.link_active = 1',
948
				'ORDER_BY'	=> 'l.link_time DESC, l.link_id DESC');
949
950
			$sql = $this->db->sql_build_query('SELECT', $sql_array);
951
			$result = $this->db->sql_query_limit($sql, $limit_sql, 0);
952
			$num = 0;
953
			$rowset = array();
954
955
			while ($site = $this->db->sql_fetchrow($result))
956
			{
957
				$rowset[$site['link_id']] = $site;
958
			}
959
			$this->db->sql_freeresult($result);
960
961
			if (sizeof($rowset))
962
			{
963
				$this->template->assign_block_vars('block', array(
964
					'S_COL_WIDTH'			=> (100 / $this->config['dir_recent_columns']) . '%',
965
				));
966
967
				foreach ($rowset as $row)
968
				{
969
					if (($num % $this->config['dir_recent_columns']) == 0)
970
					{
971
						$this->template->assign_block_vars('block.row', array());
972
					}
973
974
					$this->template->assign_block_vars('block.row.col', array(
975
						'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>',
976
						'NAME'                    => $row['link_name'],
977
						'USER'                    => get_username_string('full', $row['link_user_id'], $row['username'], $row['user_colour']),
978
						'TIME'                    => ($row['link_time']) ? $this->user->format_date($row['link_time']) : '',
979
						'CAT'                     => $row['cat_name'],
980
						'COUNT'					  => $row['link_view'],
981
						'COMMENT'                 => $row['link_comment'],
982
983
						'U_CAT'                   => $this->helper->route('ernadoo_phpbbdirectory_page_controller', array('cat_id' => (int) $row['link_cat'])),
984
						'U_COMMENT'               => $this->helper->route('ernadoo_phpbbdirectory_comment_view_controller', array('link_id' => (int) $row['link_id'])),
985
986
						'L_DIR_SEARCH_NB_CLICKS'	=> $this->user->lang('DIR_SEARCH_NB_CLICKS', (int) $row['link_view']),
987
						'L_DIR_SEARCH_NB_COMMS'		=> $this->user->lang('DIR_SEARCH_NB_COMMS', (int) $row['link_comment']),
988
					));
989
					$num++;
990
				}
991
992
				while (($num % $this->config['dir_recent_columns']) != 0)
993
				{
994
					$this->template->assign_block_vars('block.row.col2', array());
995
					$num++;
996
				}
997
			}
998
		}
999
	}
1000
1001
	/**
1002
	* Validate back link
1003
	*
1004
	* @param	string		$remote_url	Page URL contains the backlink
1005
	* @param	bool		$optional	Link back is optional in this category?
1006
	* @param	bool		$cron		This methos is called by con process?
1007
	* @return	false|string			Either false if validation succeeded or a string which will be used as the error message (with the variable name appended)
1008
	*/
1009
	public function validate_link_back($remote_url, $optional, $cron = false)
1010
	{
1011
		if (!$cron)
1012
		{
1013
			if (empty($remote_url) && $optional)
1014
			{
1015
				return false;
1016
			}
1017
1018
			if (!preg_match('#^http[s]?://(.*?\.)*?[a-z0-9\-]+\.[a-z]{2,4}#i', $remote_url))
1019
			{
1020
				return 'DIR_ERROR_WRONG_DATA_BACK';
1021
			}
1022
		}
1023
1024
		if (false === ($handle = @fopen($remote_url, 'r')))
1025
		{
1026
			return 'DIR_ERROR_NOT_FOUND_BACK';
1027
		}
1028
1029
		$buff = '';
1030
1031
		// Read by packet, faster than file_get_contents()
1032
		while (!feof($handle))
1033
		{
1034
			$buff .= fgets($handle, 256);
1035
1036
			if (stristr($buff, $this->config['server_name']))
1037
			{
1038
				@fclose($handle);
1039
				return false;
1040
			}
1041
		}
1042
		@fclose($handle);
1043
1044
		return 'DIR_ERROR_NO_LINK_BACK';
1045
	}
1046
1047
	/**
1048
	* Check, for website with backlink specified, if backlink is always here.
1049
	* After $nb_check verification, website is deleted, otherwise, a notification is send to poster
1050
	*
1051
	* @param	int		$cat_id		The categoryID
1052
	* @param	int		$nb_check	Number of check before demete a website
1053
	* @param	int		$next_prune	Date of next auto check
1054
	* @return	null
1055
	*/
1056
	private function _check($cat_id, $nb_check, $next_prune)
1057
	{
1058
		$del_array = $update_array = array();
1059
1060
		$sql_array = array(
1061
			'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',
1062
			'FROM'		=> array(
1063
					DIR_LINK_TABLE	=> 'l'),
1064
			'LEFT_JOIN'	=> array(
1065
					array(
1066
						'FROM'	=> array(USERS_TABLE	=> 'u'),
1067
						'ON'	=> 'l.link_user_id = u.user_id'
1068
					)
1069
			),
1070
			'WHERE'		=> 'l.link_back <> "" AND l.link_active = 1 AND l.link_cat = '  . (int) $cat_id);
1071
1072
		$sql = $this->db->sql_build_query('SELECT', $sql_array);
1073
		$result = $this->db->sql_query($sql);
1074
1075
		while ($row = $this->db->sql_fetchrow($result))
1076
		{
1077
			if ($this->validate_link_back($row['link_back'], false, true) !== false)
1078
			{
1079
				if (!$nb_check || ($row['link_nb_check']+1) >= $nb_check)
1080
				{
1081
					$del_array[] = $row['link_id'];
1082
				}
1083
				else
1084
				{
1085
					// A first table containing links ID to update
1086
					$update_array[$row['link_id']] = $row;
1087
				}
1088
			}
1089
		}
1090
		$this->db->sql_freeresult($result);
1091
1092
		if (sizeof($del_array))
1093
		{
1094
			$this->del($cat_id, $del_array);
1095
		}
1096
		if (sizeof($update_array))
1097
		{
1098
			$this->_update_check($update_array, $next_prune);
1099
		}
1100
	}
1101
1102
	/**
1103
	* Method called by cron task.
1104
	*
1105
	* @param	array	$cat_data	Information about category, from db
1106
	* @return	null
1107
	*/
1108
	public function auto_check($cat_data)
1109
	{
1110
		global $phpbb_log;
1111
1112
		$sql = 'SELECT cat_name
1113
			FROM ' . DIR_CAT_TABLE . '
1114
			WHERE cat_id = ' . (int) $cat_data['cat_id'];
1115
		$result = $this->db->sql_query($sql);
1116
		$row = $this->db->sql_fetchrow($result);
1117
		$this->db->sql_freeresult($result);
1118
1119
		if ($row)
1120
		{
1121
			$next_prune = time() + ($cat_data['cat_cron_freq'] * 86400);
1122
1123
			$this->_check($cat_data['cat_id'], $cat_data['cat_cron_nb_check'], $next_prune);
1124
1125
			$sql = 'UPDATE ' . DIR_CAT_TABLE . "
1126
				SET cat_cron_next = $next_prune
1127
				WHERE cat_id = " . (int) $cat_data['cat_id'];
1128
			$this->db->sql_query($sql);
1129
1130
			$phpbb_log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_DIR_AUTO_PRUNE', time(), array($row['cat_name']));
1131
		}
1132
1133
		return;
1134
	}
1135
1136
	/**
1137
	* Update website verification number after a missing backlink, and send notificaton
1138
	*
1139
	* @param	array	$u_array	Information about website
1140
	* @param	int		$next_prune	Date of next auto check
1141
	* @return	null
1142
	*/
1143
	private function _update_check($u_array, $next_prune)
1144
	{
1145
		if (!class_exists('messenger'))
1146
		{
1147
			include($this->root_path . 'includes/functions_messenger.' . $this->php_ext);
1148
		}
1149
1150
		$messenger = new \messenger(false);
1151
1152
		// cron.php don't call $user->setup(), so $this->timezone is unset.
1153
		// We need to define it, because we use user->format_date below
1154
		$this->user->timezone = new \DateTimeZone($this->config['board_timezone']);
1155
1156
		$sql = 'UPDATE ' . DIR_LINK_TABLE . '
1157
			SET link_nb_check = link_nb_check + 1
1158
			WHERE ' . $this->db->sql_in_set('link_id', array_keys($u_array));
1159
		$this->db->sql_query($sql);
1160
1161
		foreach ($u_array as $data)
1162
		{
1163
			strip_bbcode($data['link_description']);
1164
1165
			$notification_data = array(
1166
					'cat_name'			=> \ernadoo\phpbbdirectory\core\categorie::getname((int) $data['link_cat']),
1167
					'link_id'			=> $data['link_id'],
1168
					'link_name'			=> $data['link_name'],
1169
					'link_url'			=> $data['link_url'],
1170
					'link_description'	=> $data['link_description'],
1171
					'next_cron' 		=> $this->user->format_date($next_prune, $data['user_dateformat']),
1172
			);
1173
1174
			if ($data['link_nb_check'])
1175
			{
1176
				$this->notification->delete_notifications('ernadoo.phpbbdirectory.notification.type.directory_website_error_cron', $notification_data);
1177
			}
1178
1179
			// New notification system can't send mail to an anonymous user with an email address stored in another table than phpbb_users
1180
			if ($data['link_user_id'] == ANONYMOUS)
1181
			{
1182
				$username = $email = $data['link_guest_email'];
1183
1184
				$messenger->template('@ernadoo_phpbbdirectory/directory_website_error_cron', $data['user_lang']);
1185
				$messenger->to($email, $username);
1186
1187
				$messenger->assign_vars(array(
1188
					'USERNAME'			=> htmlspecialchars_decode($username),
1189
					'LINK_NAME'			=> $data['link_name'],
1190
					'LINK_URL'			=> $data['link_url'],
1191
					'LINK_DESCRIPTION'	=> $data['link_description'],
1192
					'NEXT_CRON' 		=> $this->user->format_date($next_prune, $data['user_dateformat']),
1193
				));
1194
1195
				$messenger->send(NOTIFY_EMAIL);
1196
			}
1197
			else
1198
			{
1199
				$this->notification->add_notifications('ernadoo.phpbbdirectory.notification.type.directory_website_error_cron', $notification_data);
1200
			}
1201
		}
1202
	}
1203
}
1204