Completed
Push — master ( 7709dc...4595f6 )
by Matt
04:24 queued 03:16
created

helper::is_preview()   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 0
1
<?php
2
/**
3
 *
4
 * Topic Image Preview. An extension for the phpBB Forum Software package.
5
 *
6
 * @copyright (c) 2017, 2020, 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
18
/**
19
 * Topic Image Preview Factory.
20
 */
21
class helper
22
{
23
	/** @var auth */
24
	protected $auth;
25
26
	/** @var config */
27
	protected $config;
28
29
	/** @var driver_interface */
30
	protected $db;
31
32
	/** @var user */
33
	protected $user;
34
35
	/** @var bool */
36
	protected $preview = false;
37
38
	/**
39
	 * Constructor
40
	 *
41
	 * @param auth             $auth
42
	 * @param config           $config
43
	 * @param driver_interface $db
44
	 * @param user             $user
45
	 */
46
	public function __construct(auth $auth, config $config, driver_interface $db, user $user)
47
	{
48
		$this->auth = $auth;
49
		$this->config = $config;
50
		$this->db = $db;
51
		$this->user = $user;
52
	}
53
54
	/**
55
	 * Get the value of the in_preview
56
	 *
57
	 * @return bool True if topic image previews are generated.
58
	 */
59
	public function is_preview()
60
	{
61
		return $this->preview;
62
	}
63
64
	/**
65
	 * Add post text containing images to topic row data.
66
	 *
67
	 * @param \phpbb\event\data $event The event object
68
	 *
69
	 * @return void
70
	 */
71
	public function update_row_data($event)
72
	{
73
		if (!$this->user_allowed())
74
		{
75
			return;
76
		}
77
78
		// Use topic_list from event, otherwise create one based on the rowset
79
		$topic_list = $event->offsetExists('topic_list') ? $event['topic_list'] : array_keys($event['rowset']);
80
81
		if (count($topic_list))
82
		{
83
			$event['rowset'] = $this->query_images($topic_list, $event['rowset']);
84
		}
85
	}
86
87
	/**
88
	 * Add image previews to the template data.
89
	 *
90
	 * @param \phpbb\event\data $event The event object
91
	 *
92
	 * @return void
93
	 */
94
	public function update_tpl_data($event)
95
	{
96
		if (empty($event['row']['post_text']) || !$this->user_allowed() || !$this->forum_allowed($event['row']['forum_id']))
97
		{
98
			return;
99
		}
100
101
		// Send the image string to the template
102
		$block = $event->offsetExists('topic_row') ? 'topic_row' : 'tpl_ary';
103
		$event[$block] = array_merge($event[$block], ['TOPIC_IMAGES' => $this->extract_images($event['row']['post_text'])]);
104
105
		$this->preview = true;
106
	}
107
108
	/**
109
	 * Run an SQL query on a group of topics, and find the newest (or oldest)
110
	 * post with [IMG] images. Then update the topic's row set array to include
111
	 * the post's text in the cases where images were found.
112
	 *
113
	 * @param array $topic_list An array of topic ids
114
	 * @param array $rowset     The row set of topic data
115
	 *
116
	 * @return array The updated row set of topic data which now includes
117
	 *               the post_text of a post containing images.
118
	 */
119
	protected function query_images(array $topic_list, array $rowset)
120
	{
121
		$sql_array = [];
122
		$direction = $this->config->offsetGet('vse_tip_new') ? 'DESC' : 'ASC';
123
		$like_expression = $this->db->sql_like_expression('<r>' . $this->db->get_any_char() . '<IMG ' . $this->db->get_any_char());
124
		$is_sqlite3 = $this->db->get_sql_layer() === 'sqlite3';
125
		$is_mssql = strpos($this->db->get_sql_layer(), 'mssql') === 0;
126
		foreach ($topic_list as $topic_id)
127
		{
128
			if (!$this->forum_allowed($rowset[$topic_id]['forum_id']))
129
			{
130
				continue;
131
			}
132
133
			$stmt = '(SELECT ' . ($is_mssql ? 'TOP 1 ' : '') . 'topic_id, post_text
134
				FROM ' . POSTS_TABLE . '
135
				WHERE topic_id = ' . (int) $topic_id . '
136
					AND post_visibility = ' . ITEM_APPROVED . '
137
					AND post_text ' . $like_expression . '
138
				ORDER BY post_time ' . $direction . ($is_mssql ? '' : ' LIMIT 1') . ')';
139
140
			// SQLite3 and mssql don't like ORDER BY with UNION ALL, so treat $stmt as derived table
141
			if ($is_sqlite3 || $is_mssql)
142
			{
143
				$stmt = "SELECT * FROM $stmt AS d";
144
			}
145
146
			$sql_array[] = $stmt;
147
		}
148
149
		if (count($sql_array))
150
		{
151
			$sql = implode(' UNION ALL ', $sql_array);
152
			$result = $this->db->sql_query($sql);
153
			while ($row = $this->db->sql_fetchrow($result))
154
			{
155
				$rowset[$row['topic_id']]['post_text'] = $row['post_text'];
156
			}
157
			$this->db->sql_freeresult($result);
158
		}
159
160
		return $rowset;
161
	}
162
163
	/**
164
	 * Extract images from a post and return them as an array of images.
165
	 *
166
	 * @param string $post Post text from the database.
167
	 *
168
	 * @return array An array of images.
169
	 */
170
	protected function extract_images($post)
171
	{
172
		// Extract the images
173
		$images = [];
174
		$dom = new \DOMDocument;
175
		$dom->loadXML($post);
176
		$xpath = new \DOMXPath($dom);
177
		foreach ($xpath->query('//IMG[not(ancestor::IMG)]/@src') as $image)
178
		{
179
			$images[] = $image->textContent;
180
		}
181
182
		return array_slice($images, 0, (int) $this->config['vse_tip_num'], true);
183
	}
184
185
	/**
186
	 * Is the forum allowed to show topic image previews
187
	 *
188
	 * @param int $forum_id Forum identifier
189
	 * @return bool True if allowed, false if not
190
	 */
191
	protected function forum_allowed($forum_id)
192
	{
193
		return (bool) $this->auth->acl_get('f_vse_tip', $forum_id);
194
	}
195
196
	/**
197
	 * Does the user allow topic image previews?
198
	 *
199
	 * @return bool True if allowed, false if not
200
	 */
201
	protected function user_allowed()
202
	{
203
		return (bool) $this->user->data['user_vse_tip'];
204
	}
205
}
206