[TASK] updated contact-form-layout
This commit is contained in:
parent
571576756e
commit
8675176bb6
@ -1,17 +1,16 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* p01-contact - A simple contact forms manager
|
* p01-contact - A simple contact forms manager.
|
||||||
|
*
|
||||||
|
* @see https://github.com/nliautaud/p01contact
|
||||||
*
|
*
|
||||||
* @link https://github.com/nliautaud/p01contact
|
|
||||||
* @author Nicolas Liautaud
|
* @author Nicolas Liautaud
|
||||||
* @package p01contact
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace P01C;
|
namespace P01C;
|
||||||
|
|
||||||
class P01contactField
|
class P01contactField
|
||||||
{
|
{
|
||||||
private $form;
|
|
||||||
|
|
||||||
public $id;
|
public $id;
|
||||||
public $type;
|
public $type;
|
||||||
public $title;
|
public $title;
|
||||||
@ -22,10 +21,11 @@ class P01contactField
|
|||||||
public $required;
|
public $required;
|
||||||
public $locked;
|
public $locked;
|
||||||
public $error;
|
public $error;
|
||||||
|
private $form;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Form $form the container form
|
* @param Form $form the container form
|
||||||
* @param int $id the field id
|
* @param int $id the field id
|
||||||
* @param string $type the field type
|
* @param string $type the field type
|
||||||
*/
|
*/
|
||||||
public function __construct($form, $id, $type)
|
public function __construct($form, $id, $type)
|
||||||
@ -36,7 +36,7 @@ class P01contactField
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the field value or selected value
|
* Set the field value or selected value.
|
||||||
*
|
*
|
||||||
* @param mixed $new_value the value, or an array of selected values ids
|
* @param mixed $new_value the value, or an array of selected values ids
|
||||||
*/
|
*/
|
||||||
@ -45,11 +45,12 @@ class P01contactField
|
|||||||
// simple value
|
// simple value
|
||||||
if (!is_array($this->value)) {
|
if (!is_array($this->value)) {
|
||||||
$this->value = htmlentities($new_value, ENT_COMPAT, 'UTF-8', false);
|
$this->value = htmlentities($new_value, ENT_COMPAT, 'UTF-8', false);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// multiples-values (checkbox, radio, select)
|
// multiples-values (checkbox, radio, select)
|
||||||
if (!is_array($new_value)) {
|
if (!is_array($new_value)) {
|
||||||
$new_value = array($new_value);
|
$new_value = [$new_value];
|
||||||
}
|
}
|
||||||
foreach ($new_value as $i) {
|
foreach ($new_value as $i) {
|
||||||
$this->selected_values[intval($i)] = true;
|
$this->selected_values[intval($i)] = true;
|
||||||
@ -57,11 +58,11 @@ class P01contactField
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset the selected values by finding ones who starts or end with ":"
|
* Reset the selected values by finding ones who starts or end with ":".
|
||||||
*/
|
*/
|
||||||
public function resetSelectedValues()
|
public function resetSelectedValues()
|
||||||
{
|
{
|
||||||
$this->selected_values = array();
|
$this->selected_values = [];
|
||||||
foreach ($this->value as $i => $val) {
|
foreach ($this->value as $i => $val) {
|
||||||
$value = preg_replace('`(^\s*:|:\s*$)`', '', $val, -1, $count);
|
$value = preg_replace('`(^\s*:|:\s*$)`', '', $val, -1, $count);
|
||||||
if ($count) {
|
if ($count) {
|
||||||
@ -73,32 +74,38 @@ class P01contactField
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Check field value.
|
* Check field value.
|
||||||
* @return boolean
|
*
|
||||||
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function validate()
|
public function validate()
|
||||||
{
|
{
|
||||||
// empty and required
|
// empty and required
|
||||||
if (empty($this->value) && $this->required) {
|
if (empty($this->value) && $this->required) {
|
||||||
$this->error = 'field_required';
|
$this->error = 'field_required';
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// value blacklisted or not in whitelist
|
// value blacklisted or not in whitelist
|
||||||
if ($reason = $this->isBlacklisted()) {
|
if ($reason = $this->isBlacklisted()) {
|
||||||
$this->error = 'field_' . $reason;
|
$this->error = 'field_'.$reason;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// not empty but not valid
|
// not empty but not valid
|
||||||
if (!empty($this->value) && !$this->isValid()) {
|
if (!empty($this->value) && !$this->isValid()) {
|
||||||
$this->error = 'field_' . $this->type;
|
$this->error = 'field_'.$this->type;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if field value is valid
|
* Check if field value is valid
|
||||||
* Mean different things depending on field type
|
* Mean different things depending on field type.
|
||||||
* @return boolean
|
*
|
||||||
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function isValid()
|
public function isValid()
|
||||||
{
|
{
|
||||||
@ -107,6 +114,7 @@ class P01contactField
|
|||||||
return filter_var($this->value, FILTER_VALIDATE_EMAIL);
|
return filter_var($this->value, FILTER_VALIDATE_EMAIL);
|
||||||
case 'tel':
|
case 'tel':
|
||||||
$pattern = '`^\+?[-0-9(). ]{6,}$$`i';
|
$pattern = '`^\+?[-0-9(). ]{6,}$$`i';
|
||||||
|
|
||||||
return preg_match($pattern, $this->value);
|
return preg_match($pattern, $this->value);
|
||||||
case 'url':
|
case 'url':
|
||||||
return filter_var($this->value, FILTER_VALIDATE_URL);
|
return filter_var($this->value, FILTER_VALIDATE_URL);
|
||||||
@ -122,8 +130,11 @@ class P01contactField
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if reCaptcha is valid
|
* Check if reCaptcha is valid.
|
||||||
* @return boolean
|
*
|
||||||
|
* @param mixed $answer
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function reCaptchaValidity($answer)
|
public function reCaptchaValidity($answer)
|
||||||
{
|
{
|
||||||
@ -131,10 +142,10 @@ class P01contactField
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$params = [
|
$params = [
|
||||||
'secret' => $this->form->config('recaptcha_secret_key'),
|
'secret' => $this->form->config('recaptcha_secret_key'),
|
||||||
'response' => $answer
|
'response' => $answer,
|
||||||
];
|
];
|
||||||
$url = "https://www.google.com/recaptcha/api/siteverify?" . http_build_query($params);
|
$url = 'https://www.google.com/recaptcha/api/siteverify?'.http_build_query($params);
|
||||||
if (function_exists('curl_version')) {
|
if (function_exists('curl_version')) {
|
||||||
$curl = curl_init($url);
|
$curl = curl_init($url);
|
||||||
curl_setopt($curl, CURLOPT_HEADER, false);
|
curl_setopt($curl, CURLOPT_HEADER, false);
|
||||||
@ -154,12 +165,12 @@ class P01contactField
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if field value is blacklisted
|
* Check if field value is blacklisted.
|
||||||
*
|
*
|
||||||
* Search for every comma-separated entry of every checklist
|
* Search for every comma-separated entry of every checklist
|
||||||
* in value, and define if it should or should not be there.
|
* in value, and define if it should or should not be there.
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function isBlacklisted()
|
public function isBlacklisted()
|
||||||
{
|
{
|
||||||
@ -173,14 +184,15 @@ class P01contactField
|
|||||||
}
|
}
|
||||||
$content = array_filter(explode(',', $cl->content));
|
$content = array_filter(explode(',', $cl->content));
|
||||||
foreach ($content as $avoid) {
|
foreach ($content as $avoid) {
|
||||||
$found = preg_match("`$avoid`", $this->value);
|
$found = preg_match("`{$avoid}`", $this->value);
|
||||||
$foundBlacklisted = $found && $cl->type == 'blacklist';
|
$foundBlacklisted = $found && 'blacklist' == $cl->type;
|
||||||
$notFoundWhitelisted = !$found && $cl->type == 'whitelist';
|
$notFoundWhitelisted = !$found && 'whitelist' == $cl->type;
|
||||||
if ($foundBlacklisted || $notFoundWhitelisted) {
|
if ($foundBlacklisted || $notFoundWhitelisted) {
|
||||||
return $cl->type;
|
return $cl->type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,8 +204,8 @@ class P01contactField
|
|||||||
*/
|
*/
|
||||||
public function html()
|
public function html()
|
||||||
{
|
{
|
||||||
$id = 'p01-contact' . $this->form->getId() . '_field' . $this->id;
|
$id = 'p01-contact'.$this->form->getId().'_field'.$this->id;
|
||||||
$name = 'p01-contact_fields[' . $this->id . ']';
|
$name = 'p01-contact_fields['.$this->id.']';
|
||||||
$type = $this->getGeneralType();
|
$type = $this->getGeneralType();
|
||||||
$orig = $type != $this->type ? $this->type : '';
|
$orig = $type != $this->type ? $this->type : '';
|
||||||
$value = $this->value;
|
$value = $this->value;
|
||||||
@ -201,71 +213,80 @@ class P01contactField
|
|||||||
$required = $this->required ? ' required ' : '';
|
$required = $this->required ? ' required ' : '';
|
||||||
$placeholder = $this->placeholder ? ' placeholder="'.$this->placeholder.'"' : '';
|
$placeholder = $this->placeholder ? ' placeholder="'.$this->placeholder.'"' : '';
|
||||||
|
|
||||||
$is_single_option = is_array($this->value) && count($this->value) == 1;
|
$is_single_option = is_array($this->value) && 1 == count($this->value) ? 'inline' : '';
|
||||||
if ($is_single_option) {
|
$html = "<div class=\"row field {$is_single_option} {$type} {$orig} {$required}\">";
|
||||||
$html = "<div class=\"field inline $type $orig $required\">";
|
|
||||||
} else {
|
$html .= '<div class="col-sm-12 col-md-3">';
|
||||||
$html = "<div class=\"field $type $orig $required\">";
|
if ('' === $is_single_option) {
|
||||||
$html .= $this->htmlLabel($id);
|
$html .= $this->htmlLabel($id);
|
||||||
}
|
}
|
||||||
|
$html .= '</div>';
|
||||||
|
|
||||||
|
$html .= '<div class="col-sm-12 col-md">';
|
||||||
switch ($type) {
|
switch ($type) {
|
||||||
case 'textarea':
|
case 'textarea':
|
||||||
$html .= '<textarea id="' . $id . '" rows="10" ';
|
$html .= '<textarea id="'.$id.'" rows="10" ';
|
||||||
$html .= 'name="' . $name . '"' . $disabled.$required.$placeholder;
|
$html .= 'name="'.$name.'"'.$disabled.$required.$placeholder;
|
||||||
$html .= '>' . $value . '</textarea>';
|
$html .= '>'.$value.'</textarea>';
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 'captcha':
|
case 'captcha':
|
||||||
$key = $this->form->config('recaptcha_public_key');
|
$key = $this->form->config('recaptcha_public_key');
|
||||||
if (!$key) {
|
if (!$key) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if ($this->form->getId() == 1) {
|
if (1 == $this->form->getId()) {
|
||||||
$html .= '<script src="https://www.google.com/recaptcha/api.js"></script>';
|
$html .= '<script src="https://www.google.com/recaptcha/api.js"></script>';
|
||||||
}
|
}
|
||||||
$html .='<div class="g-recaptcha" id="'.$id.'" data-sitekey="'.$key.'"></div>';
|
$html .= '<div class="g-recaptcha" id="'.$id.'" data-sitekey="'.$key.'"></div>';
|
||||||
$html .="<input type=\"hidden\" id=\"$id\" name=\"$name\" value=\"trigger\">";
|
$html .= "<input type=\"hidden\" id=\"{$id}\" name=\"{$name}\" value=\"trigger\">";
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 'checkbox':
|
case 'checkbox':
|
||||||
case 'radio':
|
case 'radio':
|
||||||
$html .= '<div class="options">';
|
$html .= '<div class="options row">';
|
||||||
foreach ($this->value as $i => $v) {
|
foreach ($this->value as $i => $v) {
|
||||||
$selected = $this->isSelected($i) ? ' checked' : '';
|
$selected = $this->isSelected($i) ? ' checked' : '';
|
||||||
$v = !empty($v) ? $v : 'Default';
|
$v = !empty($v) ? $v : 'Default';
|
||||||
$html .= '<label class="option">';
|
$html .= '<label class="option col-sm-12">';
|
||||||
$html .= "<input id=\"{$id}_option{$i}\"";
|
$html .= "<input id=\"{$id}_option{$i}\"";
|
||||||
$html .= " type=\"$type\" class=\"$type\" name=\"{$name}\"";
|
$html .= " type=\"{$type}\" class=\"{$type}\" name=\"{$name}\"";
|
||||||
$html .= " value=\"$i\"$disabled$required$selected />$v";
|
$html .= " value=\"{$i}\"{$disabled}{$required}{$selected} />{$v}";
|
||||||
$html .= '</label>';
|
$html .= '</label>';
|
||||||
}
|
}
|
||||||
$html .= '</div>';
|
$html .= '</div>';
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 'select':
|
case 'select':
|
||||||
$html .= "<select id=\"$id\" name=\"$name\"$disabled$required>";
|
$html .= "<select id=\"{$id}\" name=\"{$name}\"{$disabled}{$required}>";
|
||||||
foreach ($this->value as $i => $v) {
|
foreach ($this->value as $i => $v) {
|
||||||
$value = !empty($v) ? $v : 'Default';
|
$value = !empty($v) ? $v : 'Default';
|
||||||
$selected = $this->isSelected($i) ? ' selected="selected"' : '';
|
$selected = $this->isSelected($i) ? ' selected="selected"' : '';
|
||||||
$html .= "<option id=\"{$id}_option{$i}\" value=\"$i\"$selected>";
|
$html .= "<option id=\"{$id}_option{$i}\" value=\"{$i}\"{$selected}>";
|
||||||
$html .= $value . '</option>';
|
$html .= $value.'</option>';
|
||||||
}
|
}
|
||||||
$html.= '</select>';
|
$html .= '</select>';
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
$html .= '<input id="' . $id . '" ';
|
$html .= '<input id="'.$id.'" ';
|
||||||
$html .= 'name="' . $name . '" type="'.$type.'" ';
|
$html .= 'name="'.$name.'" type="'.$type.'" ';
|
||||||
$html .= 'value="' . $value . '"' . $disabled.$required.$placeholder . ' />';
|
$html .= 'value="'.$value.'"'.$disabled.$required.$placeholder.' />';
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
$html .= '</div>';
|
$html .= '</div>';
|
||||||
|
$html .= '</div>';
|
||||||
|
|
||||||
return $html;
|
return $html;
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
* Return a html presentation of the field value.
|
// Return a html presentation of the field value.
|
||||||
*/
|
|
||||||
public function htmlMail()
|
public function htmlMail()
|
||||||
{
|
{
|
||||||
$gen_type = $this->getGeneralType();
|
$gen_type = $this->getGeneralType();
|
||||||
$properties = array();
|
$properties = [];
|
||||||
|
|
||||||
$html = '<table style="width: 100%; margin: 1em 0; border-collapse: collapse;">';
|
$html = '<table style="width: 100%; margin: 1em 0; border-collapse: collapse;">';
|
||||||
|
|
||||||
@ -281,7 +302,7 @@ class P01contactField
|
|||||||
// properties
|
// properties
|
||||||
$html .= '<td style="padding:.5em 1em; text-transform:lowercase; text-align:right; font-size:.875em; color:#888888; vertical-align: middle"><em>';
|
$html .= '<td style="padding:.5em 1em; text-transform:lowercase; text-align:right; font-size:.875em; color:#888888; vertical-align: middle"><em>';
|
||||||
if (!$this->value) {
|
if (!$this->value) {
|
||||||
$html .= $this->form->lang('empty') . ' ';
|
$html .= $this->form->lang('empty').' ';
|
||||||
}
|
}
|
||||||
if ($this->title) {
|
if ($this->title) {
|
||||||
$properties[] = $this->type;
|
$properties[] = $this->type;
|
||||||
@ -289,21 +310,21 @@ class P01contactField
|
|||||||
if ($gen_type != $this->type) {
|
if ($gen_type != $this->type) {
|
||||||
$properties[] = $gen_type;
|
$properties[] = $gen_type;
|
||||||
}
|
}
|
||||||
foreach (array('locked', 'required') as $property) {
|
foreach (['locked', 'required'] as $property) {
|
||||||
if ($this->$property) {
|
if ($this->{$property}) {
|
||||||
$properties[] = $this->form->lang($property);
|
$properties[] = $this->form->lang($property);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (count($properties)) {
|
if (count($properties)) {
|
||||||
$html .= '(' . implode(', ', $properties) . ') ';
|
$html .= '('.implode(', ', $properties).') ';
|
||||||
}
|
}
|
||||||
$html .= '#' . $this->id;
|
$html .= '#'.$this->id;
|
||||||
$html .= '</em></td></tr>';
|
$html .= '</em></td></tr>';
|
||||||
$html .= "\n\n";
|
$html .= "\n\n";
|
||||||
|
|
||||||
// value
|
// value
|
||||||
if (!$this->value) {
|
if (!$this->value) {
|
||||||
return $html . '</table>';
|
return $html.'</table>';
|
||||||
}
|
}
|
||||||
$html .= '<tr><td colspan=2 style="padding:0">';
|
$html .= '<tr><td colspan=2 style="padding:0">';
|
||||||
$html .= '<div style="padding:.5em 1.5em;border:1px solid #ccc">';
|
$html .= '<div style="padding:.5em 1.5em;border:1px solid #ccc">';
|
||||||
@ -323,15 +344,18 @@ class P01contactField
|
|||||||
$html .= empty($v) ? 'Default' : $v;
|
$html .= empty($v) ? 'Default' : $v;
|
||||||
$html .= "</div>\n";
|
$html .= "</div>\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
$address = '~[[:alpha:]]+://[^<>[:space:]]+[[:alnum:]/]~';
|
$address = '~[[:alpha:]]+://[^<>[:space:]]+[[:alnum:]/]~';
|
||||||
$val = nl2br(preg_replace($address, '<a href="\\0">\\0</a>', $this->value));
|
$val = nl2br(preg_replace($address, '<a href="\\0">\\0</a>', $this->value));
|
||||||
$html .= "<p style=\"margin:0\">$val</p>";
|
$html .= "<p style=\"margin:0\">{$val}</p>";
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
$html .= '</div></td></tr></table>';
|
$html .= '</div></td></tr></table>';
|
||||||
|
|
||||||
return $html;
|
return $html;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -347,19 +371,20 @@ class P01contactField
|
|||||||
*/
|
*/
|
||||||
private function htmlLabel($for)
|
private function htmlLabel($for)
|
||||||
{
|
{
|
||||||
$html = '<label for="' . $for . '">';
|
$html .= '<label for="'.$for.'" class="doc">';
|
||||||
if ($this->title) {
|
if ($this->title) {
|
||||||
$html .= $this->title;
|
$html .= $this->title;
|
||||||
} else {
|
} else {
|
||||||
$html .= ucfirst($this->form->lang($this->type));
|
$html .= ucfirst($this->form->lang($this->type));
|
||||||
}
|
}
|
||||||
if ($this->description) {
|
if ($this->description) {
|
||||||
$html .= ' <em class="description">' . $this->description . '</em>';
|
$html .= ' <em class="description">'.$this->description.'</em>';
|
||||||
}
|
}
|
||||||
if ($this->error) {
|
if ($this->error) {
|
||||||
$html .= ' <span class="error-msg">' . $this->form->lang($this->error) . '</span>';
|
$html .= ' <span class="error-msg">'.$this->form->lang($this->error).'</span>';
|
||||||
}
|
}
|
||||||
$html .= '</label>';
|
$html .= '</label>';
|
||||||
|
|
||||||
return $html;
|
return $html;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -368,22 +393,23 @@ class P01contactField
|
|||||||
*/
|
*/
|
||||||
private function getGeneralType()
|
private function getGeneralType()
|
||||||
{
|
{
|
||||||
$types = array(
|
$types = [
|
||||||
'name' => 'text',
|
'name' => 'text',
|
||||||
'subject' => 'text',
|
'subject' => 'text',
|
||||||
'message' => 'textarea',
|
'message' => 'textarea',
|
||||||
'askcopy' => 'checkbox'
|
'askcopy' => 'checkbox',
|
||||||
);
|
];
|
||||||
if (isset($types[$this->type])) {
|
if (isset($types[$this->type])) {
|
||||||
return $types[$this->type];
|
return $types[$this->type];
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->type;
|
return $this->type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function preint($arr, $return = false)
|
function preint($arr, $return = false)
|
||||||
{
|
{
|
||||||
$out = '<pre class="test" style="white-space:pre-wrap;">' . print_r(@$arr, true) . '</pre>';
|
$out = '<pre class="test" style="white-space:pre-wrap;">'.print_r(@$arr, true).'</pre>';
|
||||||
if ($return) {
|
if ($return) {
|
||||||
return $out;
|
return $out;
|
||||||
}
|
}
|
||||||
@ -402,5 +428,6 @@ function unset_r($a, $i)
|
|||||||
unset($a[$k][$i]);
|
unset($a[$k][$i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $a;
|
return $a;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,41 +1,42 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* p01-contact - A simple contact forms manager
|
* p01-contact - A simple contact forms manager.
|
||||||
|
*
|
||||||
|
* @see https://github.com/nliautaud/p01contact
|
||||||
*
|
*
|
||||||
* @link https://github.com/nliautaud/p01contact
|
|
||||||
* @author Nicolas Liautaud
|
* @author Nicolas Liautaud
|
||||||
* @package p01contact
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace P01C;
|
namespace P01C;
|
||||||
|
|
||||||
require 'P01contact_Field.php';
|
require 'P01contact_Field.php';
|
||||||
|
|
||||||
class P01contactForm
|
class P01contactForm
|
||||||
{
|
{
|
||||||
|
public $lang;
|
||||||
|
public $sent;
|
||||||
private $manager;
|
private $manager;
|
||||||
|
|
||||||
private $id;
|
private $id;
|
||||||
private $status;
|
private $status;
|
||||||
private $targets;
|
private $targets;
|
||||||
private $fields;
|
private $fields;
|
||||||
public $lang;
|
|
||||||
public $sent;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param P01contact $P01contact
|
* @param P01contact $P01contact
|
||||||
* @param int $id the form id
|
* @param int $id the form id
|
||||||
*/
|
*/
|
||||||
public function __construct($P01contact)
|
public function __construct($P01contact)
|
||||||
{
|
{
|
||||||
static $id;
|
static $id;
|
||||||
$id++;
|
++$id;
|
||||||
|
|
||||||
$this->manager = $P01contact;
|
$this->manager = $P01contact;
|
||||||
|
|
||||||
$this->id = $id;
|
$this->id = $id;
|
||||||
$this->status = '';
|
$this->status = '';
|
||||||
$this->targets = array();
|
$this->targets = [];
|
||||||
$this->fields = array();
|
$this->fields = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -77,67 +78,9 @@ class P01contactForm
|
|||||||
$this->addTarget($email);
|
$this->addTarget($email);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Create a field by parsing a tag parameter
|
|
||||||
*
|
|
||||||
* Find emails and parameters, create and setup form object.
|
|
||||||
* @param int $id the field id
|
|
||||||
* @param string $param the param to parse
|
|
||||||
*/
|
|
||||||
private function parseParam($id, $param)
|
|
||||||
{
|
|
||||||
$param_pattern = '`\s*([^ ,"=!]+)'; // type
|
|
||||||
$param_pattern.= '\s*(!)?'; // required!
|
|
||||||
$param_pattern.= '\s*(?:"([^"]*)")?'; // "title"
|
|
||||||
$param_pattern.= '\s*(?:\(([^"]*)\))?'; // (description)
|
|
||||||
$param_pattern.= '\s*(?:(=[><]?)?'; // =value, =>locked, =<placeholder
|
|
||||||
$param_pattern.= '\s*(.*))?\s*`'; // value
|
|
||||||
|
|
||||||
preg_match($param_pattern, $param, $param);
|
|
||||||
list(, $type, $required, $title, $desc, $assign, $values) = $param;
|
|
||||||
|
|
||||||
$field = new P01contactField($this, $id, $type);
|
|
||||||
|
|
||||||
// values
|
|
||||||
switch ($type) {
|
|
||||||
case 'select':
|
|
||||||
case 'radio':
|
|
||||||
case 'checkbox':
|
|
||||||
$field->value = explode('|', $values);
|
|
||||||
$field->resetSelectedValues();
|
|
||||||
break;
|
|
||||||
case 'askcopy':
|
|
||||||
// checkbox-like structure
|
|
||||||
$field->value = array($this->lang('askcopy'));
|
|
||||||
break;
|
|
||||||
case 'password':
|
|
||||||
// password value is required value
|
|
||||||
$field->required = $values;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if ($assign == '=<') {
|
|
||||||
$field->placeholder = $values;
|
|
||||||
} else {
|
|
||||||
// simple value
|
|
||||||
$field->value = $values;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// required
|
|
||||||
if ($type != 'password') {
|
|
||||||
$field->required = $required == '!';
|
|
||||||
}
|
|
||||||
if ($type == 'captcha') {
|
|
||||||
$field->required = true;
|
|
||||||
}
|
|
||||||
$field->title = $title;
|
|
||||||
$field->description = $desc;
|
|
||||||
$field->locked = $assign == '=>';
|
|
||||||
|
|
||||||
$this->addField($field);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update POSTed form and try to send mail
|
* Update POSTed form and try to send mail.
|
||||||
*
|
*
|
||||||
* Check posted data, update form data,
|
* Check posted data, update form data,
|
||||||
* define fields errors and form status.
|
* define fields errors and form status.
|
||||||
@ -146,7 +89,7 @@ class P01contactForm
|
|||||||
public function post()
|
public function post()
|
||||||
{
|
{
|
||||||
if (empty($_POST['p01-contact_form'])
|
if (empty($_POST['p01-contact_form'])
|
||||||
|| $_POST['p01-contact_form']['id'] != $this->id ) {
|
|| $_POST['p01-contact_form']['id'] != $this->id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,11 +98,12 @@ class P01contactForm
|
|||||||
$this->setStatus('sent_already');
|
$this->setStatus('sent_already');
|
||||||
$this->setToken();
|
$this->setToken();
|
||||||
$this->reset();
|
$this->reset();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$posted = $_POST['p01-contact_fields'];
|
$posted = $_POST['p01-contact_fields'];
|
||||||
|
|
||||||
// populate fields values and check errors
|
// populate fields values and check errors
|
||||||
$hasFieldsErrors = false;
|
$hasFieldsErrors = false;
|
||||||
$fields = $this->getFields();
|
$fields = $this->getFields();
|
||||||
@ -175,13 +119,15 @@ class P01contactForm
|
|||||||
// check errors and set status
|
// check errors and set status
|
||||||
if ($this->config('disable')) {
|
if ($this->config('disable')) {
|
||||||
$this->setStatus('disable');
|
$this->setStatus('disable');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (count($this->targets) == 0) {
|
if (0 == count($this->targets)) {
|
||||||
$this->setStatus('error_notarget');
|
$this->setStatus('error_notarget');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($hasFieldsErrors || $this->checkSpam($posted) !== true) {
|
if ($hasFieldsErrors || true !== $this->checkSpam($posted)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,58 +136,9 @@ class P01contactForm
|
|||||||
$this->reset();
|
$this->reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* SECURITY
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the honeypot field is untouched and if the time between this post,
|
* Get the token in Session (create it if not exists).
|
||||||
* the page load and previous posts and the hourly post count are valid
|
|
||||||
* according to the settings, and set the form status accordingly.
|
|
||||||
*
|
*
|
||||||
* @param P01contact_form $form The submitted form
|
|
||||||
* @param array $post Sanitized p01-contact data of $_POST
|
|
||||||
* @return bool the result status
|
|
||||||
*/
|
|
||||||
private function checkSpam($post)
|
|
||||||
{
|
|
||||||
if (isset($post['totally_legit'])) {
|
|
||||||
$this->setStatus('error_honeypot');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$loads = Session::get('pageloads');
|
|
||||||
if (count($loads) > 1 && $loads[1] - $loads[0] < $this->config('min_sec_after_load')) {
|
|
||||||
$this->setStatus('error_pageload');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$lastpost = Session::get('lastpost', false);
|
|
||||||
if ($lastpost && time() - $lastpost < $this->config('min_sec_between_posts')) {
|
|
||||||
$this->setStatus('error_lastpost');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$postcount = Session::get('postcount', 0);
|
|
||||||
if (!$this->config('debug') && $postcount > $this->config('max_posts_by_hour')) {
|
|
||||||
$this->setStatus('error_postcount');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Session::set('lastpost', time());
|
|
||||||
Session::set('postcount', $postcount + 1);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an unique hash in Session
|
|
||||||
*/
|
|
||||||
private static function setToken()
|
|
||||||
{
|
|
||||||
Session::set('token', uniqid(md5(microtime()), true));
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Get the token in Session (create it if not exists)
|
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getToken()
|
public function getToken()
|
||||||
@ -249,31 +146,22 @@ class P01contactForm
|
|||||||
if (!Session::get('token', false)) {
|
if (!Session::get('token', false)) {
|
||||||
$this->setToken();
|
$this->setToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Session::get('token');
|
return Session::get('token');
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Compare the POSTed token to the Session one
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
private function checkToken()
|
|
||||||
{
|
|
||||||
return $this->getToken() === $_POST['p01-contact_form']['token'];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* RENDER
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// RENDER
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the html display of the form
|
* Return the html display of the form.
|
||||||
|
*
|
||||||
* @return string the <form>
|
* @return string the <form>
|
||||||
*/
|
*/
|
||||||
public function html()
|
public function html()
|
||||||
{
|
{
|
||||||
$html = '<form action="'.PAGEURL.'#p01-contact'.$this->id.'" autocomplete="off" ';
|
$html = '<div class="section">';
|
||||||
$html .= 'id="p01-contact' . $this->id . '" class="p01-contact" method="post">';
|
$html .= '<form action="'.PAGEURL.'#p01-contact'.$this->id.'" autocomplete="off" ';
|
||||||
|
$html .= 'id="p01-contact'.$this->id.'" class="p01-contact" method="post">';
|
||||||
|
|
||||||
if ($this->status) {
|
if ($this->status) {
|
||||||
$html .= $this->htmlStatus();
|
$html .= $this->htmlStatus();
|
||||||
@ -285,30 +173,25 @@ class P01contactForm
|
|||||||
if ($this->config('use_honeypot')) {
|
if ($this->config('use_honeypot')) {
|
||||||
$html .= '<input type="checkbox" name="p01-contact_fields[totally_legit]" value="1" style="display:none !important" tabindex="-1" autocomplete="false">';
|
$html .= '<input type="checkbox" name="p01-contact_fields[totally_legit]" value="1" style="display:none !important" tabindex="-1" autocomplete="false">';
|
||||||
}
|
}
|
||||||
$html .= '<div><input name="p01-contact_form[id]" type="hidden" value="' . $this->id . '" />';
|
$html .= '<div><input name="p01-contact_form[id]" type="hidden" value="'.$this->id.'" />';
|
||||||
$html .= '<input name="p01-contact_form[token]" type="hidden" value="' . $this->getToken() . '" />';
|
$html .= '<input name="p01-contact_form[token]" type="hidden" value="'.$this->getToken().'" />';
|
||||||
$html .= '<input class="submit" type="submit" value="' . $this->lang('send') . '" /></div>';
|
$html .= '<input class="submit" type="submit" value="'.$this->lang('send').'" /></div>';
|
||||||
}
|
}
|
||||||
$html .= '</form>';
|
$html .= '</form>';
|
||||||
|
$html .= '</div>';
|
||||||
|
|
||||||
if ($this->config('debug')) {
|
if ($this->config('debug')) {
|
||||||
$html .= $this->debug(false);
|
$html .= $this->debug(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $html;
|
return $html;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return an html display of the form status
|
|
||||||
* @return string the <div>
|
|
||||||
*/
|
|
||||||
private function htmlStatus()
|
|
||||||
{
|
|
||||||
$statusclass = $this->sent ? 'alert success' : 'alert failed';
|
|
||||||
return '<div class="' . $statusclass . '">' . $this->lang($this->status) . '</div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return P01contact_form infos.
|
* Return P01contact_form infos.
|
||||||
|
*
|
||||||
|
* @param mixed $set_infos
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function debug($set_infos)
|
public function debug($set_infos)
|
||||||
@ -317,31 +200,30 @@ class P01contactForm
|
|||||||
static $post;
|
static $post;
|
||||||
if ($set_infos) {
|
if ($set_infos) {
|
||||||
$post = $set_infos;
|
$post = $set_infos;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($post) {
|
if ($post) {
|
||||||
list($headers, $targets, $subject, $text_content, $html_content) = $post;
|
list($headers, $targets, $subject, $text_content, $html_content) = $post;
|
||||||
$out.= '<h3>Virtually sent mail :</h3>';
|
$out .= '<h3>Virtually sent mail :</h3>';
|
||||||
$out.= '<pre>'.htmlspecialchars($headers).'</pre>';
|
$out .= '<pre>'.htmlspecialchars($headers).'</pre>';
|
||||||
$out.= "<pre>Targets: $targets\nSubject: $subject</pre>";
|
$out .= "<pre>Targets: {$targets}\nSubject: {$subject}</pre>";
|
||||||
$out.= "Text content : <pre>$text_content</pre>";
|
$out .= "Text content : <pre>{$text_content}</pre>";
|
||||||
$out.= "HTML content : <div style=\"border:1px solid #ccc;\">$html_content</div>";
|
$out .= "HTML content : <div style=\"border:1px solid #ccc;\">{$html_content}</div>";
|
||||||
}
|
}
|
||||||
$infos = $this;
|
$infos = $this;
|
||||||
unset($infos->manager);
|
unset($infos->manager);
|
||||||
$out .= "<h3>p01contact form $this->id :</h3>";
|
$out .= "<h3>p01contact form {$this->id} :</h3>";
|
||||||
$out .= preint($infos, true);
|
$out .= preint($infos, true);
|
||||||
$out .= '</div>';
|
$out .= '</div>';
|
||||||
|
|
||||||
return $out;
|
return $out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// MAIL
|
||||||
* MAIL
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a mail based on form
|
* Send a mail based on form.
|
||||||
*
|
*
|
||||||
* Create the mail content and headers along to settings, form
|
* Create the mail content and headers along to settings, form
|
||||||
* and fields datas; and update the form status (sent|error).
|
* and fields datas; and update the form status (sent|error).
|
||||||
@ -351,7 +233,7 @@ class P01contactForm
|
|||||||
$email = $name = $subject = $askcopy = null;
|
$email = $name = $subject = $askcopy = null;
|
||||||
$tpl_data = (object) null;
|
$tpl_data = (object) null;
|
||||||
$tpl_data->date = date('r');
|
$tpl_data->date = date('r');
|
||||||
$tpl_data->ip = $_SERVER["REMOTE_ADDR"];
|
$tpl_data->ip = $_SERVER['REMOTE_ADDR'];
|
||||||
$tpl_data->contact = $this->targets[0];
|
$tpl_data->contact = $this->targets[0];
|
||||||
// fields
|
// fields
|
||||||
$tpl_data->fields = '';
|
$tpl_data->fields = '';
|
||||||
@ -360,15 +242,19 @@ class P01contactForm
|
|||||||
switch ($field->type) {
|
switch ($field->type) {
|
||||||
case 'name':
|
case 'name':
|
||||||
$name = $field->value;
|
$name = $field->value;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 'email':
|
case 'email':
|
||||||
$email = $field->value;
|
$email = $field->value;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 'subject':
|
case 'subject':
|
||||||
$subject = $field->value;
|
$subject = $field->value;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 'askcopy':
|
case 'askcopy':
|
||||||
$askcopy = true;
|
$askcopy = true;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -391,12 +277,12 @@ class P01contactForm
|
|||||||
|
|
||||||
$content = $this->mailContent($text, 'plain', $mime_boundary);
|
$content = $this->mailContent($text, 'plain', $mime_boundary);
|
||||||
$content .= $this->mailContent($html, 'html', $mime_boundary);
|
$content .= $this->mailContent($html, 'html', $mime_boundary);
|
||||||
$content .= "--$mime_boundary--\n\n";
|
$content .= "--{$mime_boundary}--\n\n";
|
||||||
|
|
||||||
|
|
||||||
// debug
|
// debug
|
||||||
if ($this->config('debug')) {
|
if ($this->config('debug')) {
|
||||||
$this->debug(array($headers, $targets, $subject, $text, $html));
|
$this->debug([$headers, $targets, $subject, $text, $html]);
|
||||||
|
|
||||||
return $this->setStatus('sent_debug');
|
return $this->setStatus('sent_debug');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -404,9 +290,9 @@ class P01contactForm
|
|||||||
$success = mail($targets, $encoded_subject, $content, $headers);
|
$success = mail($targets, $encoded_subject, $content, $headers);
|
||||||
|
|
||||||
// log
|
// log
|
||||||
$this->manager->log(array(
|
$this->manager->log([
|
||||||
date('d/m/Y H:i:s'), $targets, $subject, $name, $success ? 'success':'error'
|
date('d/m/Y H:i:s'), $targets, $subject, $name, $success ? 'success' : 'error',
|
||||||
));
|
]);
|
||||||
|
|
||||||
if (!$success) {
|
if (!$success) {
|
||||||
return $this->setStatus('error');
|
return $this->setStatus('error');
|
||||||
@ -421,56 +307,10 @@ class P01contactForm
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the mail headers
|
* Return array of valid emails from a comma separated string.
|
||||||
* @param string $name
|
*
|
||||||
* @param string $email
|
|
||||||
* @param string $mime_boundary
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
private function mailHeaders($name, $email, $mime_boundary)
|
|
||||||
{
|
|
||||||
$encoded_name = $this->encodeHeader($name);
|
|
||||||
$headers = "From: $encoded_name <no-reply@" . SERVERNAME . ">\n";
|
|
||||||
if ($email) {
|
|
||||||
$headers .= "Reply-To: $encoded_name <$email>\n";
|
|
||||||
$headers .= "Return-Path: $encoded_name <$email>";
|
|
||||||
}
|
|
||||||
$headers .= "\n";
|
|
||||||
$headers .= "MIME-Version: 1.0\n";
|
|
||||||
$headers .= "Content-type: multipart/alternative; boundary=\"$mime_boundary\"\n";
|
|
||||||
$headers .= "X-Mailer: PHP/" . phpversion() . "\n";
|
|
||||||
return $headers;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a multipart/alternative content part.
|
|
||||||
* @param string $content
|
|
||||||
* @param string $type the content type (plain, html)
|
|
||||||
* @param string $mime_boundary
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
private function mailContent($content, $type, $mime_boundary)
|
|
||||||
{
|
|
||||||
$head = "--$mime_boundary\n";
|
|
||||||
$head .= "Content-Type: text/$type; charset=UTF-8\n";
|
|
||||||
$head .= "Content-Transfer-Encoding: 7bit\n\n";
|
|
||||||
return $head.$content."\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Format a string for UTF-8 email headers.
|
|
||||||
* @param string $string
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
private function encodeHeader($string)
|
|
||||||
{
|
|
||||||
$string = base64_encode(html_entity_decode($string, ENT_COMPAT, 'UTF-8'));
|
|
||||||
return "=?UTF-8?B?$string?=";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return array of valid emails from a comma separated string
|
|
||||||
* @param string $emails
|
* @param string $emails
|
||||||
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public static function getValidEmails($emails)
|
public static function getValidEmails($emails)
|
||||||
@ -481,12 +321,10 @@ class P01contactForm
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GETTERS / SETTERS
|
* GETTERS / SETTERS.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
// Reset all fields values and errors
|
||||||
* Reset all fields values and errors
|
|
||||||
*/
|
|
||||||
public function reset()
|
public function reset()
|
||||||
{
|
{
|
||||||
foreach ($this->fields as $field) {
|
foreach ($this->fields as $field) {
|
||||||
@ -494,52 +332,256 @@ class P01contactForm
|
|||||||
$field->error = '';
|
$field->error = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTargets()
|
public function getTargets()
|
||||||
{
|
{
|
||||||
return $this->targets;
|
return $this->targets;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addTarget($tget)
|
public function addTarget($tget)
|
||||||
{
|
{
|
||||||
if (in_array($tget, $this->targets) === false) {
|
if (false === in_array($tget, $this->targets)) {
|
||||||
$this->targets[] = $tget;
|
$this->targets[] = $tget;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getField($id)
|
public function getField($id)
|
||||||
{
|
{
|
||||||
return $this->fields[$id];
|
return $this->fields[$id];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFields()
|
public function getFields()
|
||||||
{
|
{
|
||||||
return $this->fields;
|
return $this->fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addField($field)
|
public function addField($field)
|
||||||
{
|
{
|
||||||
$this->fields[] = $field;
|
$this->fields[] = $field;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getStatus()
|
public function getStatus()
|
||||||
{
|
{
|
||||||
return $this->status;
|
return $this->status;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setStatus($status)
|
public function setStatus($status)
|
||||||
{
|
{
|
||||||
if (!is_string($status)) {
|
if (!is_string($status)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$this->status = $status;
|
$this->status = $status;
|
||||||
if (substr($status, 0, 4) == 'sent') {
|
if ('sent' == substr($status, 0, 4)) {
|
||||||
$this->sent = true;
|
$this->sent = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getId()
|
public function getId()
|
||||||
{
|
{
|
||||||
return $this->id;
|
return $this->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function config($key)
|
public function config($key)
|
||||||
{
|
{
|
||||||
return $this->manager->config($key);
|
return $this->manager->config($key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function lang($key)
|
public function lang($key)
|
||||||
{
|
{
|
||||||
return $this->manager->lang($key, $this->lang);
|
return $this->manager->lang($key, $this->lang);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a field by parsing a tag parameter.
|
||||||
|
*
|
||||||
|
* Find emails and parameters, create and setup form object.
|
||||||
|
*
|
||||||
|
* @param int $id the field id
|
||||||
|
* @param string $param the param to parse
|
||||||
|
*/
|
||||||
|
private function parseParam($id, $param)
|
||||||
|
{
|
||||||
|
$param_pattern = '`\s*([^ ,"=!]+)'; // type
|
||||||
|
$param_pattern .= '\s*(!)?'; // required!
|
||||||
|
$param_pattern .= '\s*(?:"([^"]*)")?'; // "title"
|
||||||
|
$param_pattern .= '\s*(?:\(([^"]*)\))?'; // (description)
|
||||||
|
$param_pattern .= '\s*(?:(=[><]?)?'; // =value, =>locked, =<placeholder
|
||||||
|
$param_pattern .= '\s*(.*))?\s*`'; // value
|
||||||
|
|
||||||
|
preg_match($param_pattern, $param, $param);
|
||||||
|
list(, $type, $required, $title, $desc, $assign, $values) = $param;
|
||||||
|
|
||||||
|
$field = new P01contactField($this, $id, $type);
|
||||||
|
|
||||||
|
// values
|
||||||
|
switch ($type) {
|
||||||
|
case 'select':
|
||||||
|
case 'radio':
|
||||||
|
case 'checkbox':
|
||||||
|
$field->value = explode('|', $values);
|
||||||
|
$field->resetSelectedValues();
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 'askcopy':
|
||||||
|
// checkbox-like structure
|
||||||
|
$field->value = [$this->lang('askcopy')];
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 'password':
|
||||||
|
// password value is required value
|
||||||
|
$field->required = $values;
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if ('=<' == $assign) {
|
||||||
|
$field->placeholder = $values;
|
||||||
|
} else {
|
||||||
|
// simple value
|
||||||
|
$field->value = $values;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// required
|
||||||
|
if ('password' != $type) {
|
||||||
|
$field->required = '!' == $required;
|
||||||
|
}
|
||||||
|
if ('captcha' == $type) {
|
||||||
|
$field->required = true;
|
||||||
|
}
|
||||||
|
$field->title = $title;
|
||||||
|
$field->description = $desc;
|
||||||
|
$field->locked = '=>' == $assign;
|
||||||
|
|
||||||
|
$this->addField($field);
|
||||||
|
}
|
||||||
|
|
||||||
|
// SECURITY
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the honeypot field is untouched and if the time between this post,
|
||||||
|
* the page load and previous posts and the hourly post count are valid
|
||||||
|
* according to the settings, and set the form status accordingly.
|
||||||
|
*
|
||||||
|
* @param P01contact_form $form The submitted form
|
||||||
|
* @param array $post Sanitized p01-contact data of $_POST
|
||||||
|
*
|
||||||
|
* @return bool the result status
|
||||||
|
*/
|
||||||
|
private function checkSpam($post)
|
||||||
|
{
|
||||||
|
if (isset($post['totally_legit'])) {
|
||||||
|
$this->setStatus('error_honeypot');
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$loads = Session::get('pageloads');
|
||||||
|
if (count($loads) > 1 && $loads[1] - $loads[0] < $this->config('min_sec_after_load')) {
|
||||||
|
$this->setStatus('error_pageload');
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$lastpost = Session::get('lastpost', false);
|
||||||
|
if ($lastpost && time() - $lastpost < $this->config('min_sec_between_posts')) {
|
||||||
|
$this->setStatus('error_lastpost');
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$postcount = Session::get('postcount', 0);
|
||||||
|
if (!$this->config('debug') && $postcount > $this->config('max_posts_by_hour')) {
|
||||||
|
$this->setStatus('error_postcount');
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Session::set('lastpost', time());
|
||||||
|
Session::set('postcount', $postcount + 1);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an unique hash in Session.
|
||||||
|
*/
|
||||||
|
private static function setToken()
|
||||||
|
{
|
||||||
|
Session::set('token', uniqid(md5(microtime()), true));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare the POSTed token to the Session one.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function checkToken()
|
||||||
|
{
|
||||||
|
return $this->getToken() === $_POST['p01-contact_form']['token'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an html display of the form status.
|
||||||
|
*
|
||||||
|
* @return string the <div>
|
||||||
|
*/
|
||||||
|
private function htmlStatus()
|
||||||
|
{
|
||||||
|
$statusclass = $this->sent ? 'alert success' : 'alert failed';
|
||||||
|
|
||||||
|
return '<div class="'.$statusclass.'">'.$this->lang($this->status).'</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the mail headers.
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @param string $email
|
||||||
|
* @param string $mime_boundary
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function mailHeaders($name, $email, $mime_boundary)
|
||||||
|
{
|
||||||
|
$encoded_name = $this->encodeHeader($name);
|
||||||
|
$headers = "From: {$encoded_name} <no-reply@".SERVERNAME.">\n";
|
||||||
|
if ($email) {
|
||||||
|
$headers .= "Reply-To: {$encoded_name} <{$email}>\n";
|
||||||
|
$headers .= "Return-Path: {$encoded_name} <{$email}>";
|
||||||
|
}
|
||||||
|
$headers .= "\n";
|
||||||
|
$headers .= "MIME-Version: 1.0\n";
|
||||||
|
$headers .= "Content-type: multipart/alternative; boundary=\"{$mime_boundary}\"\n";
|
||||||
|
$headers .= 'X-Mailer: PHP/'.phpversion()."\n";
|
||||||
|
|
||||||
|
return $headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a multipart/alternative content part.
|
||||||
|
*
|
||||||
|
* @param string $content
|
||||||
|
* @param string $type the content type (plain, html)
|
||||||
|
* @param string $mime_boundary
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function mailContent($content, $type, $mime_boundary)
|
||||||
|
{
|
||||||
|
$head = "--{$mime_boundary}\n";
|
||||||
|
$head .= "Content-Type: text/{$type}; charset=UTF-8\n";
|
||||||
|
$head .= "Content-Transfer-Encoding: 7bit\n\n";
|
||||||
|
|
||||||
|
return $head.$content."\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format a string for UTF-8 email headers.
|
||||||
|
*
|
||||||
|
* @param string $string
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function encodeHeader($string)
|
||||||
|
{
|
||||||
|
$string = base64_encode(html_entity_decode($string, ENT_COMPAT, 'UTF-8'));
|
||||||
|
|
||||||
|
return "=?UTF-8?B?{$string}?=";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user