Issues (1697)

sources/ElkArte/Controller/About.php (2 issues)

1
<?php
2
3
/**
4
 * Handle credits, license, privacy policy?, cookie policy?, registration agreement?, contact
5
 * staff, COPPA contact
6
 *
7
 * @package   ElkArte Forum
8
 * @copyright ElkArte Forum contributors
9
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file)
10
 *
11
 * @version 2.0 Beta 1
12
 *
13
 */
14
15
namespace ElkArte\Controller;
16
17
use ArrayObject;
18
use ElkArte\AbstractController;
19
use ElkArte\Action;
20
use ElkArte\Exceptions\Exception;
21
use ElkArte\Helper\DataValidator;
22
use ElkArte\Http\Headers;
23
use ElkArte\Languages\Txt;
24
25
/**
26
 * About Controller
27
 */
28
class About extends AbstractController
29
{
30
	private const STATUS_AWAITING_COPPA = 5;
31
32
	/**
33
	 * Default action of this class.
34
	 * Accessed with ?action=about
35
	 */
36
	public function action_index() :void
37
	{
38
		// Add an subaction array to act accordingly
39
		$subActions = [
40
			'credits' => [$this, 'action_credits'],
41
			'contact' => [$this, 'action_contact'],
42
			'coppa' => [$this, 'action_coppa'],
43
		];
44
45
		// Setup the action handler
46
		$action = new Action();
47
		$subAction = $action->initialize($subActions, 'credits');
48
49
		// Call the action
50
		$action->dispatch($subAction);
51
	}
52
53
	/**
54
	 * Shows the contact form for the user to fill out
55
	 *
56
	 * - Functionality needs to be enabled in the ACP for this to be used
57
	 * - Triggers the verify_contact event
58
	 */
59
	public function action_contact(): void
60
	{
61
		global $context, $txt, $modSettings;
62
63
		// Users have no need to use this, just send a PM
64
		// Disabled, you cannot enter.
65
		if ($this->user->is_guest === false || empty($modSettings['enable_contactform']) || $modSettings['enable_contactform'] === 'disabled')
0 ignored issues
show
Bug Best Practice introduced by
The property is_guest does not exist on ElkArte\Helper\ValuesContainer. Since you implemented __get, consider adding a @property annotation.
Loading history...
66
		{
67
			redirectexit();
68
		}
69
70
		Txt::load('Login');
71
		theme()->getTemplates()->load('Register');
72
73
		// Submitted the contact form?
74
		if (isset($this->_req->post->send))
75
		{
76
			checkSession();
77
			validateToken('contact');
78
79
			// Can't send a lot of these in a row, no sir!
80
			spamProtection('contact');
81
82
			// No errors, yet.
83
			$context['errors'] = [];
84
			Txt::load('Errors');
85
86
			// Could they get the right send topic verification code?
87
			require_once(SUBSDIR . '/Members.subs.php');
88
89
			// Form validation
90
			$validator = new DataValidator();
91
			$validator->sanitation_rules([
92
				'emailaddress' => 'trim',
93
				'contactmessage' => 'trim'
94
			]);
95
			$validator->validation_rules([
96
				'emailaddress' => 'required|valid_email',
97
				'contactmessage' => 'required'
98
			]);
99
			$validator->text_replacements([
100
				'emailaddress' => $txt['error_email'],
101
				'contactmessage' => $txt['error_message']
102
			]);
103
104
			// Any form errors
105
			if (!$validator->validate($this->_req->post))
106
			{
107
				$context['errors'] = $validator->validation_errors();
108
			}
109
110
			// Get the clean data
111
			$this->_req->post = new ArrayObject($validator->validation_data(), ArrayObject::ARRAY_AS_PROPS);
112
113
			// Trigger the verify contact event for captcha checks
114
			$this->_events->trigger('verify_contact', []);
115
116
			// No errors, then send the PM to the admins
117
			if (empty($context['errors']))
118
			{
119
				$admins = admins();
120
				if (!empty($admins))
121
				{
122
					require_once(SUBSDIR . '/PersonalMessage.subs.php');
123
					sendpm(['to' => array_keys($admins), 'bcc' => []], $txt['contact_subject'], $this->_req->post->contactmessage, false, ['id' => 0, 'name' => $this->_req->post->emailaddress, 'username' => $this->_req->post->emailaddress]);
124
				}
125
126
				// Send the PM
127
				redirectexit('action=about;sa=contact;done');
128
			}
129
			else
130
			{
131
				$context['emailaddress'] = $this->_req->post->emailaddress;
132
				$context['contactmessage'] = $this->_req->post->contactmessage;
133
			}
134
		}
135
136
		// Show the contact done form or the form itself
137
		if (isset($this->_req->query->done))
138
		{
139
			$context['sub_template'] = 'contact_form_done';
140
		}
141
		else
142
		{
143
			loadJavascriptFile('ext/mailcheck.min.js');
144
			$context['sub_template'] = 'contact_form';
145
			$context['page_title'] = $txt['admin_contact_form'];
146
147
			// Setup any contract form events, like validation
148
			$this->_events->trigger('setup_contact', []);
149
		}
150
151
		createToken('contact');
152
	}
153
154
	/**
155
	 * This function will display the contact information for the forum, as well a form to fill in.
156
	 *
157
	 * - Accessed by action=about;sa=coppa
158
	 */
159
	public function action_coppa(): void
160
	{
161
		Txt::load('Login');
162
		theme()->getTemplates()->load('About');
163
164
		// No User ID??
165
		if (!isset($this->_req->query->member))
166
		{
167
			throw new Exception('no_access', false);
168
		}
169
170
		// Get the user details...
171
		require_once(SUBSDIR . '/Members.subs.php');
172
		$member = getBasicMemberData((int) $this->_req->query->member, ['authentication' => true]);
173
174
		// If doesn't exist or not pending coppa
175
		if (empty($member) || (int) $member['is_activated'] !== self::STATUS_AWAITING_COPPA)
176
		{
177
			throw new Exception('no_access', false);
178
		}
179
180
		if (isset($this->_req->query->form))
181
		{
182
			$this->handleContactForm($member);
183
		}
184
		else
185
		{
186
			$this->handleCoppa();
187
		}
188
	}
189
190
	/**
191
	 * Handle the contact form for member registration.
192
	 *
193
	 * This method sets the necessary variables in the global $context for displaying the contact form.
194
	 * If the query parameter `dl` is set, the method outputs a file for download, otherwise it shows the contact form template.
195
	 *
196
	 * @param array $member The member data from getBasicMemberData())
197
	 */
198
	private function handleContactForm($member): void
199
	{
200
		global $context, $modSettings, $txt;
201
202
		// Some simple contact stuff for the forum.
203
		$context['forum_contacts'] = (empty($modSettings['coppaPost']) ? '' : $modSettings['coppaPost'] . '<br /><br />') . (empty($modSettings['coppaFax']) ? '' : $modSettings['coppaFax'] . '<br />');
204
		$context['forum_contacts'] = empty($context['forum_contacts']) ? '' : $context['forum_name_html_safe'] . '<br />' . $context['forum_contacts'];
205
206
		// Showing template?
207
		if (!isset($this->_req->query->dl))
208
		{
209
			// Shortcut for producing underlines.
210
			$context['ul'] = '<span class="underline">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>';
211
			theme()->getLayers()->removeAll();
212
			$context['sub_template'] = 'coppa_form';
213
			$context['page_title'] = replaceBasicActionUrl($txt['coppa_form_title']);
214
			$context['coppa_body'] = str_replace(['{PARENT_NAME}', '{CHILD_NAME}', '{USER_NAME}'], [$context['ul'], $context['ul'], $member['member_name']], replaceBasicActionUrl($txt['coppa_form_body']));
215
		}
216
		// Downloading.
217
		else
218
		{
219
			// Set up to output a file to the users browser
220
			while (ob_get_level() > 0)
221
			{
222
				@ob_end_clean();
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for ob_end_clean(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

222
				/** @scrutinizer ignore-unhandled */ @ob_end_clean();

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
223
			}
224
225
			// The data.
226
			$ul = '                ';
227
			$crlf = "\r\n";
228
			$data = $context['forum_contacts'] . $crlf . $txt['coppa_form_address'] . ':' . $crlf . $txt['coppa_form_date'] . ':' . $crlf . $crlf . $crlf . replaceBasicActionUrl($txt['coppa_form_body']);
229
			$data = str_replace(['{PARENT_NAME}', '{CHILD_NAME}', '{USER_NAME}', '<br />', '<br />'], [$ul, $ul, $member['member_name'], $crlf, $crlf], $data);
230
231
			// Send the headers.
232
			Headers::instance()
233
				->removeHeader('all')
234
				->header('Content-Encoding', 'none')
235
				->header('Pragma', 'no-cache')
236
				->header('Cache-Control', 'no-cache')
237
				->header('Connection', 'close')
238
				->header('Content-Disposition', 'attachment; filename="approval.txt"')
239
				->contentType('application/octet-stream', '')
240
				->sendHeaders();
241
242
			echo $data;
243
244
			obExit(false, false);
245
		}
246
	}
247
248
	/**
249
	 * Handle the Children's Online Privacy Protection Act (COPPA) for member registration.
250
	 *
251
	 * This method sets the necessary variables in the global $context for displaying the COPPA page.
252
	 *
253
	 * @return void
254
	 */
255
	private function handleCoppa(): void
256
	{
257
		global $context, $modSettings, $txt;
258
259
		$context += [
260
			'page_title' => $txt['coppa_title'],
261
			'sub_template' => 'coppa',
262
		];
263
264
		$context['coppa'] = [
265
			'body' => str_replace('{MINIMUM_AGE}', $modSettings['coppaAge'], replaceBasicActionUrl($txt['coppa_after_registration'])),
266
			'many_options' => !empty($modSettings['coppaPost']) && !empty($modSettings['coppaFax']),
267
			'post' => empty($modSettings['coppaPost']) ? '' : $modSettings['coppaPost'],
268
			'fax' => empty($modSettings['coppaFax']) ? '' : $modSettings['coppaFax'],
269
			'phone' => empty($modSettings['coppaPhone']) ? '' : str_replace('{PHONE_NUMBER}', $modSettings['coppaPhone'], $txt['coppa_send_by_phone']),
270
			'id' => $this->_req->query->member,
271
		];
272
	}
273
274
	/**
275
	 * It prepares credit and copyright information for the credits page or the admin page.
276
	 *
277
	 * - Accessed by ?action=who;sa=credits
278
	 *
279
	 * @uses Who language file
280
	 * @uses template_credits() sub template in Who.template,
281
	 */
282
	public function action_credits(): void
283
	{
284
		global $context, $txt;
285
286
		require_once(SUBSDIR . '/About.subs.php');
287
		Txt::load('About');
288
289
		$context += prepareCreditsData();
290
291
		theme()->getTemplates()->load('About');
292
		$context['sub_template'] = 'credits';
293
		$context['robot_no_index'] = true;
294
		$context['page_title'] = $txt['credits'];
295
	}
296
}
297