Completed
Push — develop ( ba497a...2389fa )
by Matt
01:19
created

helper::query_images()   B

Complexity

Conditions 7
Paths 16

Size

Total Lines 42

Duplication

Lines 0
Ratio 0 %

Importance

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