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 dev |
||||
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() |
||||
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() |
||||
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
![]() |
|||||
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() |
||||
160 | { |
||||
161 | global $context, $modSettings, $txt; |
||||
162 | |||||
163 | Txt::load('Login'); |
||||
164 | theme()->getTemplates()->load('About'); |
||||
165 | |||||
166 | // No User ID?? |
||||
167 | if (!isset($this->_req->query->member)) |
||||
168 | { |
||||
169 | throw new Exception('no_access', false); |
||||
170 | } |
||||
171 | |||||
172 | // Get the user details... |
||||
173 | require_once(SUBSDIR . '/Members.subs.php'); |
||||
174 | $member = getBasicMemberData((int) $this->_req->query->member, ['authentication' => true]); |
||||
175 | |||||
176 | // If doesn't exist or not pending coppa |
||||
177 | if (empty($member) || (int) $member['is_activated'] !== self::STATUS_AWAITING_COPPA) |
||||
178 | { |
||||
179 | throw new Exception('no_access', false); |
||||
180 | } |
||||
181 | |||||
182 | if (isset($this->_req->query->form)) |
||||
183 | { |
||||
184 | $this->handleContactForm($member); |
||||
185 | } |
||||
186 | else |
||||
187 | { |
||||
188 | $this->handleCoppa(); |
||||
189 | } |
||||
190 | } |
||||
191 | |||||
192 | /** |
||||
193 | * Handle the contact form for member registration. |
||||
194 | * |
||||
195 | * This method sets the necessary variables in the global $context for displaying the contact form. |
||||
196 | * If the query parameter `dl` is set, the method outputs a file for download, otherwise it shows the contact form template. |
||||
197 | * |
||||
198 | * @param array $member The member data from getBasicMemberData()) |
||||
199 | */ |
||||
200 | private function handleContactForm($member) |
||||
201 | { |
||||
202 | global $context, $modSettings, $txt; |
||||
203 | |||||
204 | // Some simple contact stuff for the forum. |
||||
205 | $context['forum_contacts'] = (empty($modSettings['coppaPost']) ? '' : $modSettings['coppaPost'] . '<br /><br />') . (empty($modSettings['coppaFax']) ? '' : $modSettings['coppaFax'] . '<br />'); |
||||
206 | $context['forum_contacts'] = empty($context['forum_contacts']) ? '' : $context['forum_name_html_safe'] . '<br />' . $context['forum_contacts']; |
||||
207 | |||||
208 | // Showing template? |
||||
209 | if (!isset($this->_req->query->dl)) |
||||
210 | { |
||||
211 | // Shortcut for producing underlines. |
||||
212 | $context['ul'] = '<span class="underline"> </span>'; |
||||
213 | theme()->getLayers()->removeAll(); |
||||
214 | $context['sub_template'] = 'coppa_form'; |
||||
215 | $context['page_title'] = replaceBasicActionUrl($txt['coppa_form_title']); |
||||
216 | $context['coppa_body'] = str_replace(['{PARENT_NAME}', '{CHILD_NAME}', '{USER_NAME}'], [$context['ul'], $context['ul'], $member['member_name']], replaceBasicActionUrl($txt['coppa_form_body'])); |
||||
217 | } |
||||
218 | // Downloading. |
||||
219 | else |
||||
220 | { |
||||
221 | // Set up to output a file to the users browser |
||||
222 | while (ob_get_level() > 0) |
||||
223 | { |
||||
224 | @ob_end_clean(); |
||||
0 ignored issues
–
show
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
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.');
}
![]() |
|||||
225 | } |
||||
226 | |||||
227 | // The data. |
||||
228 | $ul = ' '; |
||||
229 | $crlf = "\r\n"; |
||||
230 | $data = $context['forum_contacts'] . $crlf . $txt['coppa_form_address'] . ':' . $crlf . $txt['coppa_form_date'] . ':' . $crlf . $crlf . $crlf . replaceBasicActionUrl($txt['coppa_form_body']); |
||||
231 | $data = str_replace(['{PARENT_NAME}', '{CHILD_NAME}', '{USER_NAME}', '<br />', '<br />'], [$ul, $ul, $member['member_name'], $crlf, $crlf], $data); |
||||
232 | |||||
233 | // Send the headers. |
||||
234 | Headers::instance() |
||||
235 | ->removeHeader('all') |
||||
236 | ->header('Content-Encoding', 'none') |
||||
237 | ->header('Pragma', 'no-cache') |
||||
238 | ->header('Cache-Control', 'no-cache') |
||||
239 | ->header('Connection', 'close') |
||||
240 | ->header('Content-Disposition', 'attachment; filename="approval.txt"') |
||||
241 | ->contentType('application/octet-stream', '') |
||||
242 | ->sendHeaders(); |
||||
243 | |||||
244 | echo $data; |
||||
245 | |||||
246 | obExit(false, false); |
||||
247 | } |
||||
248 | } |
||||
249 | |||||
250 | /** |
||||
251 | * Handle the Children's Online Privacy Protection Act (COPPA) for member registration. |
||||
252 | * |
||||
253 | * This method sets the necessary variables in the global $context for displaying the COPPA page. |
||||
254 | * |
||||
255 | * @return void |
||||
256 | */ |
||||
257 | private function handleCoppa() |
||||
258 | { |
||||
259 | global $context, $modSettings, $txt; |
||||
260 | |||||
261 | $context += [ |
||||
262 | 'page_title' => $txt['coppa_title'], |
||||
263 | 'sub_template' => 'coppa', |
||||
264 | ]; |
||||
265 | |||||
266 | $context['coppa'] = [ |
||||
267 | 'body' => str_replace('{MINIMUM_AGE}', $modSettings['coppaAge'], replaceBasicActionUrl($txt['coppa_after_registration'])), |
||||
268 | 'many_options' => !empty($modSettings['coppaPost']) && !empty($modSettings['coppaFax']), |
||||
269 | 'post' => empty($modSettings['coppaPost']) ? '' : $modSettings['coppaPost'], |
||||
270 | 'fax' => empty($modSettings['coppaFax']) ? '' : $modSettings['coppaFax'], |
||||
271 | 'phone' => empty($modSettings['coppaPhone']) ? '' : str_replace('{PHONE_NUMBER}', $modSettings['coppaPhone'], $txt['coppa_send_by_phone']), |
||||
272 | 'id' => $this->_req->query->member, |
||||
273 | ]; |
||||
274 | } |
||||
275 | |||||
276 | /** |
||||
277 | * It prepares credit and copyright information for the credits page or the admin page. |
||||
278 | * |
||||
279 | * - Accessed by ?action=who;sa=credits |
||||
280 | * |
||||
281 | * @uses Who language file |
||||
282 | * @uses template_credits() sub template in Who.template, |
||||
283 | */ |
||||
284 | public function action_credits() |
||||
285 | { |
||||
286 | global $context, $txt; |
||||
287 | |||||
288 | require_once(SUBSDIR . '/About.subs.php'); |
||||
289 | Txt::load('About'); |
||||
290 | |||||
291 | $context += prepareCreditsData(); |
||||
292 | |||||
293 | theme()->getTemplates()->load('About'); |
||||
294 | $context['sub_template'] = 'credits'; |
||||
295 | $context['robot_no_index'] = true; |
||||
296 | $context['page_title'] = $txt['credits']; |
||||
297 | } |
||||
298 | } |