<?php namespace HashOver;

// Copyright (C) 2015-2021 Jacob Barkdull
// This file is part of HashOver.
//
// HashOver is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// HashOver is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with HashOver. If not, see <http://www.gnu.org/licenses/>.


class FormData
{
protected $setup;
protected $locale;
protected $spamCheck;
protected $cookies;

protected $referer;

public $data = array ();
public $remoteAccess = false;
public $file;
public $replyTo;
public $viaAJAX = false;

// Fake inputs used as spam trap fields
protected $trapFields = array (
'summary',
'age',
'lastname',
'address',
'zip'
);

public function __construct (Setup $setup, Cookies $cookies)
{
// Store parameters as properties
$this->setup = $setup;

// Instantiate various classes
$this->locale = new Locale ($setup);
$this->spamCheck = new SpamCheck ($setup);
$this->cookies = $cookies;

// Use POST or GET based on whether request is for JSONP
$request = isset ($_GET['jsonp']) ? $_GET : $_POST;

// Get regular expression escaped admin path
$admin_path = preg_quote ($this->setup->getHttpPath ('admin'), '/');

// Attempt to get referer
$referer = Misc::getArrayItem ($_SERVER, 'HTTP_REFERER');

// Set status
if (isset ($request['status'])) {
$this->data['status'] = $this->forceUTF8 ($request['status']);
}

// Set name
if (isset ($request['name'])) {
$this->data['name'] = $this->forceUTF8 ($request['name']);
}

// Set password
if (isset ($request['password'])) {
$this->data['password'] = $this->forceUTF8 ($request['password']);
}

// Set e-mail address
if (isset ($request['email'])) {
$this->data['email'] = $this->forceUTF8 ($request['email']);
}

// Set website URL
if (isset ($request['website'])) {
$this->data['website'] = $this->forceUTF8 ($request['website']);
}

// Set comment
if (isset ($request['comment'])) {
$this->data['comment'] = $this->forceUTF8 ($request['comment']);
}

// Set indicator of remote access
if (isset ($request['remote-access'])) {
$this->remoteAccess = true;
}

// Get comment file
if (isset ($request['file'])) {
$this->file = $request['file'];
}

// Get reply comment file
if (isset ($request['reply-to'])) {
$this->replyTo = $request['reply-to'];
}

// Set indicator of AJAX requests
if (isset ($request['ajax'])) {
$this->viaAJAX = true;
}

// Check if we're coming from an admin page
if (preg_match ('/' . $admin_path . '/i', $referer)) {
// If so, use it as the kickback URL
$this->referer = $_SERVER['HTTP_REFERER'];
} else {
// If not, check if posting from remote domain
if ($this->remoteAccess === true) {
// If so, use absolute path
$this->referer = $setup->pageURL;
} else {
// If not, use relative path
$this->referer = $setup->filePath;
}

// Add URL queries to kickback URL
if (!empty ($setup->urlQueries)) {
$this->referer .= '?' . $setup->urlQueries;
}
}
}

// Force a string to UTF-8 encoding and acceptable character range
protected function forceUTF8 ($string)
{
$string = mb_convert_encoding ($string, 'UTF-16', 'UTF-8');
$string = mb_convert_encoding ($string, 'UTF-8', 'UTF-16');
$string = preg_replace ('/[^\x{0009}\x{000A}\x{000D}\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]/u', '?', $string);

return trim ($string, " \r\n\t");
}

// Sets header to redirect user back to the previous page
public function kickback ($anchor = 'comments')
{
header ('Location: ' . $this->referer . '#' . $anchor);
}

// Displays message to visitor, via AJAX or redirect
public function displayMessage ($locale, $error = false)
{
// Message type as string
$message_type = ($error === true) ? 'error' : 'message';

// Get message text from locales if it exists
if (!empty ($this->locale->text[$locale])) {
$locale = $this->locale->text[$locale];
}

// Check if request is not over an AJAX request
if ($this->viaAJAX !== true) {
// If so, set cookie to specified message
$this->cookies->set ($message_type, $locale);

// And redirect user to previous page
return $this->kickback ('hashover-form-section');
}

// Otherwise, display JSON for JavaScript frontend
echo Misc::jsonData (array (
'message' => $locale,
'type' => $message_type
));
}

// Checks user IP against spam databases
public function checkForSpam ($mode = 'javascript')
{
// Treat JSON mode as JavaScript mode
if ($mode === 'json') {
$mode = 'javascript';
}

// Block user if they fill any trap fields
foreach ($this->trapFields as $name) {
if ($this->setup->getRequest ($name)) {
throw new \Exception ('You are blocked!');
}
}

// Check user's IP address against local blocklist
if ($this->spamCheck->checkList () === true) {
throw new \Exception ('You are blocked!');
}

// Whether to check for spam in current mode
if ($this->setup->spamCheckModes === $mode
or $this->setup->spamCheckModes === 'both')
{
// Check user's IP address against local or remote database
if ($this->spamCheck->{$this->setup->spamDatabase}() === true) {
throw new \Exception ('You are blocked!');
}

// Throw any error message as exception
if (!empty ($this->spamCheck->error)) {
throw new \Exception ($this->spamCheck->error);
}
}
}
}