Completed
Branch feature/permissions (20ff90)
by Matt
01:18
created

preview::forum_allowed()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
/**
3
 *
4
 * Topic Image Preview. An extension for the phpBB Forum Software package.
5
 *
6
 * @copyright (c) 2017, Matt Friedman
7
 * @license GNU General Public License, version 2 (GPL-2.0)
8
 *
9
 */
10
11
namespace vse\topicimagepreview\event;
12
13
use phpbb\auth\auth;
14
use phpbb\config\config;
15
use phpbb\db\driver\driver_interface;
16
use phpbb\user;
17
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
18
19
/**
20
 * Topic Image Preview Event listener.
21
 */
22
class preview implements EventSubscriberInterface
23
{
24
	/** @var auth */
25
	protected $auth;
26
27
	/** @var config */
28
	protected $config;
29
30
	/** @var driver_interface */
31
	protected $db;
32
33
	/** @var user */
34
	protected $user;
35
36
	/**
37
	 * {@inheritdoc}
38
	 */
39
	public static function getSubscribedEvents()
40
	{
41
		return [
42
			'core.permissions'						=> 'add_permission',
43
			// Viewforum events
44
			'core.viewforum_modify_topics_data'		=> 'update_row_data',
45
			'core.viewforum_modify_topicrow'		=> 'update_tpl_data',
46
			// Search events
47
			'core.search_modify_rowset'				=> 'update_row_data',
48
			'core.search_modify_tpl_ary'			=> 'update_tpl_data',
49
			// Precise Similar Topics events
50
			'vse.similartopics.modify_rowset'		=> 'update_row_data',
51
			'vse.similartopics.modify_topicrow'		=> 'update_tpl_data',
52
		];
53
	}
54
55
	/**
56
	 * Constructor
57
	 *
58
	 * @param auth             $auth
59
	 * @param config           $config
60
	 * @param driver_interface $db
61
	 * @param user             $user
62
	 */
63
	public function __construct(auth $auth, config $config, driver_interface $db, user $user)
64
	{
65
		$this->auth = $auth;
66
		$this->config = $config;
67
		$this->db = $db;
68
		$this->user = $user;
69
	}
70
71
	/**
72
	 * Add administrative permissions to manage forums
73
	 *
74
	 * @param \phpbb\event\data $event The event object
75
	 * @return void
76
	 */
77
	public function add_permission($event)
78
	{
79
		$event->update_subarray('permissions', 'f_vse_tip', [
80
			'lang' => 'ACL_F_VSE_TIP',
81
			'cat'  => 'actions',
82
		]);
83
	}
84
85
	/**
86
	 * Add post text containing images to topic row data.
87
	 *
88
	 * @param \phpbb\event\data $event The event object
89
	 *
90
	 * @return void
91
	 */
92
	public function update_row_data($event)
93
	{
94
		if (!$this->user_allowed())
95
		{
96
			return;
97
		}
98
99
		// Use topic_list from event, otherwise create one based on the rowset
100
		$topic_list = $event->offsetExists('topic_list') ? $event['topic_list'] : array_keys($event['rowset']);
101
102
		if (count($topic_list))
103
		{
104
			$event['rowset'] = $this->query_images($topic_list, $event['rowset']);
105
		}
106
	}
107
108
	/**
109
	 * Add image previews to the template data.
110
	 *
111
	 * @param \phpbb\event\data $event The event object
112
	 *
113
	 * @return void
114
	 */
115
	public function update_tpl_data($event)
116
	{
117
		if (!$this->user_allowed() || !$this->forum_allowed($event['row']['forum_id']) || !$this->has_images($event))
118
		{
119
			return;
120
		}
121
122
		// Send the image string to the template
123
		$block = $event->offsetExists('topic_row') ? 'topic_row' : 'tpl_ary';
124
		$event[$block] = array_merge($event[$block], ['TOPIC_IMAGES' => $this->extract_images($event['row']['post_text'])]);
125
	}
126
127
	/**
128
	 * Run an SQL query on a group of topics, and find the newest (or oldest)
129
	 * post with [IMG] images. Then update the topic's row set array to include
130
	 * the post's text in the cases where images were found.
131
	 *
132
	 * @param array $topic_list An array of topic ids
133
	 * @param array $rowset     The row set of topic data
134
	 *
135
	 * @return array The updated row set of topic data which now includes
136
	 *               the post_text of a post containing images.
137
	 */
138
	protected function query_images(array $topic_list, array $rowset)
139
	{
140
		$sql_array = [];
141
		foreach ($topic_list as $topic_id)
142
		{
143
			if (!$this->forum_allowed($rowset[$topic_id]['forum_id']))
144
			{
145
				continue;
146
			}
147
148
			$stmt = '(SELECT topic_id, post_text
149
				FROM ' . POSTS_TABLE . '
150
				WHERE topic_id = ' . (int) $topic_id . '
151
					AND post_visibility = ' . ITEM_APPROVED . '
152
					AND post_text ' . $this->db->sql_like_expression('<r>' . $this->db->get_any_char() . '<IMG ' . $this->db->get_any_char()) . '
153
				ORDER BY post_time ' . ($this->config->offsetGet('vse_tip_new') ? 'DESC' : 'ASC') . '
154
				LIMIT 1)';
155
156
			// SQLite3 doesn't like ORDER BY with UNION ALL, so treat $stmt as derived table
157
			if ($this->db->get_sql_layer() === 'sqlite3')
158
			{
159
				$stmt = "SELECT * FROM $stmt AS d";
160
			}
161
162
			$sql_array[] = $stmt;
163
		}
164
165
		if ($sql_array)
0 ignored issues
show
Bug Best Practice introduced by
The expression $sql_array of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
166
		{
167
			$sql = implode(' UNION ALL ', $sql_array);
168
			$result = $this->db->sql_query($sql);
169
			while ($row = $this->db->sql_fetchrow($result))
170
			{
171
				$rowset[$row['topic_id']]['post_text'] = $row['post_text'];
172
			}
173
			$this->db->sql_freeresult($result);
174
		}
175
176
		return $rowset;
177
	}
178
179
	/**
180
	 * Extract images from a post and return them as HTML image tags.
181
	 *
182
	 * @param string $post Post text from the database.
183
	 *
184
	 * @return string An string of HTML IMG tags.
185
	 */
186
	protected function extract_images($post)
187
	{
188
		// Extract the images
189
		$images = [];
190
		$dom = new \DOMDocument;
191
		$dom->loadXML($post);
192
		$xpath = new \DOMXPath($dom);
193
		foreach ($xpath->query('//IMG[not(ancestor::IMG)]/@src') as $image)
194
		{
195
			$images[] = $image->textContent;
196
		}
197
198
		// Create a string of images
199
		return implode(' ', array_map(function ($image) {
200
			return "<img src='{$image}' alt='' style='max-width:{$this->config['vse_tip_dim']}px; max-height:{$this->config['vse_tip_dim']}px;' />";
201
		}, array_slice($images, 0, (int) $this->config['vse_tip_num'], true)));
202
	}
203
204
	/**
205
	 * Is the forum allowed to show topic image previews
206
	 *
207
	 * @param int $forum_id Forum identifier
208
	 * @return bool True if allowed, false if not
209
	 */
210
	protected function forum_allowed($forum_id)
211
	{
212
		return (bool) $this->auth->acl_get('f_vse_tip', $forum_id);
213
	}
214
215
	/**
216
	 * Does the user allow topic image previews?
217
	 *
218
	 * @return bool True if allowed, false if not
219
	 */
220
	protected function user_allowed()
221
	{
222
		return (bool) $this->user->data['user_vse_tip'];
223
	}
224
225
	/**
226
	 * Check if we have post with images
227
	 *
228
	 * @param \phpbb\event\data $event The event object
229
	 * @return bool True if images found in post text, false if not
230
	 */
231
	protected function has_images($event)
232
	{
233
		return !empty($event['row']['post_text']) && preg_match('/^<[r][ >]/', $event['row']['post_text']) && strpos($event['row']['post_text'], '<IMG ') !== false;
234
	}
235
}
236