d2tools/vendor/formr/formr/class.formr.php

5218 lines
177 KiB
PHP

<?php
namespace Formr;
/**
* Formr (1.4.4)
*
* a php micro-framework to help you quickly build and validate web forms
*
* https://formr.github.io
*
* copyright(c) 2013-2022 Tim Gavin
* https://github.com/timgavin
*
* requires php >= 5.6 and gd2 (for uploads)
*
**/
# load the default classes
require_once 'lib/class.formr.dropdowns.php';
require_once 'lib/class.formr.forms.php';
require_once 'lib/class.formr.wrappers.php';
# load the 'plugin' classes
if (file_exists(dirname(__FILE__) . '/my_classes/my.wrappers.php')) {
require_once 'my_classes/my.wrappers.php';
}
if (file_exists(dirname(__FILE__) . '/my_classes/my.dropdowns.php')) {
require_once 'my_classes/my.dropdowns.php';
}
if (file_exists(dirname(__FILE__) . '/my_classes/my.forms.php')) {
require_once 'my_classes/my.forms.php';
}
class Formr
{
# each of these public properties acts as a 'preference' for Formr
# and can be defined after instantiation. see documentation for more info.
# default form action (useful with fastform())
public $action;
# default character set
public $charset = 'utf-8';
# comment each form field for easier debugging
public $comments = false;
# suppress Formr's validation error messages and only display your own
public $custom_validation_messages = false;
# default string delimiters
# $delimiter[0] is for separating field values in fastform()
# $delimiter[1] is for parsing values within fastform() strings and the post() validation rules
# example : input_text('Name $delimiter[0] Label $delimiter[0] Value[Value1 $delimiter[1] Value2 $delimiter[1] Value3 ]');
# example : form->post('email','Email','valid_email $delimiter[1] min[3] $delimiter[1] max[60]')
# property was made public so you can modify it as you see fit
public $delimiter = array(',', '|');
# default doctype
public $doctype = 'html';
# default error message headers
public $error_heading_plural = 'Please Correct the Following Errors';
public $error_heading_singular = 'Please Correct the Following Error';
# add an error message to messages()
public $error_message;
# create an empty errors array for form validation
public $errors = array();
# format dates for validation rules
public $format_rule_dates = 'M d, Y';
# add a honeypot field
public $honeypot;
# sanitize input with HTMLPurifier
public $html_purifier;
# form's ID
public $id;
# add an info message to messages()
public $info_message;
# inline validation is off by default
public $inline_errors = false;
# inline validation CSS class: displays error icon next to form fields
public $inline_errors_class = 'error_inline';
# link from error messages to related fields by setting anchor tags
public $link_errors = false;
# default form method (useful with fastform())
public $method = 'post';
# removes all line breaks and minifies code
public $minify = false;
# form's name
public $name;
# Google ReCaptcha v3
# get keys here: https://www.google.com/recaptcha/admin/create
public $recaptcha_action_name;
public $recaptcha_score = 0.5;
public $recaptcha_secret_key;
public $recaptcha_site_key;
public $recaptcha_use_curl = false;
# form fields are not required by default
public $required = false;
# visually lets the user know a field is required inside the field's label tag
public $required_indicator = '';
# use a salt when hashing
public $salt;
# sanitize html $_POST values with FILTER_SANITIZE_SPECIAL_CHARS
public $sanitize_html = false;
# define a session
public $session;
# use session values in form fields on page load
public $session_values;
# show valid status (green outline) on fields if using a framework
public $show_valid = false;
# default submit button value
public $submit = 'Submit';
# add a success message to messages()
public $success_message;
# accepted file types/mime types for uploading files
public $upload_accepted_mimes;
public $upload_accepted_types;
# the full path to the directory in which we're uploading files
public $upload_dir;
# max file size for uploaded files (2MB)
public $upload_max_filesize = 2097152;
# rename a file after upload
public $upload_rename;
# resize images after upload
public $upload_resize;
# init the $uploads property
public $uploads = true;
# add a warning message to messages()
public $warning_message;
# put default class names into an array
private $controls = array();
# default wrapper types which Formr supports
private $default_wrapper_types = array('div', 'p', 'ul', 'ol', 'dl', 'li');
# we can turn off automatic echoing of elements in the constructor
private $echo;
# exclude these input types from certain operations, namely classes and wrappers
protected $excluded_types = array('submit', 'button', 'reset', 'checkbox', 'radio');
# we don't want to create form attributes from these keywords if they're in the $data array
private $no_keys = array('string', 'checked', 'selected', 'required', 'inline', 'label', 'fastform', 'options', 'group', 'multiple');
# use Formr's default <div> wrapper for elements
protected $use_default_wrapper = true;
# toggle wrapping <div> for elements
protected $use_element_wrapper_div;
function __construct($wrapper = '', $switch = '')
{
# determine our field wrapper and CSS classes
if (file_exists(dirname(__FILE__) . '/my_classes/my.wrappers.php')) {
$this->use_default_wrapper = false;
}
if (!$wrapper) {
# no wrapper specified, use Formr's default
$this->wrapper = '';
} else {
# user-defined wrapper
$this->wrapper = strtolower($wrapper);
$wrapper_css = $this->wrapper . '_css';
}
if (!$this->wrapper || in_array($this->wrapper, $this->default_wrapper_types)) {
# use default wrapper css
$this->controls = \Wrapper::default_css();
} else {
# custom wrapper/control types
try {
# check the Controls class for the supplied method
if (!$this->use_default_wrapper) {
$method = new \ReflectionMethod('mywrappers::' . $wrapper_css);
if ($method->isStatic()) {
$this->controls = \MyWrappers::$wrapper_css();
}
} else {
$method = new \ReflectionMethod('wrapper::' . $wrapper_css);
if ($method->isStatic()) {
$this->controls = \Wrapper::$wrapper_css();
}
}
} catch (\ReflectionException $e) {
# method does not exist, spit out error and set default controls
$this->_error_message('<h4>' . $e->getMessage() . '</h4>If you are using Custom Wrappers, please make sure the Custom Wrapper file is located at "<strong>my_classes/my.wrappers.php</strong>", and that you spelled your Wrapper name correctly.</p><p>If you are NOT using Custom Wrappers, please make sure a file does not exist at <strong>"my_classes/my.wrappers.php"</strong>'); die;
$this->controls = \Wrapper::default_css();
}
}
# create the Formr session
if (!isset($_SESSION['formr'])) {
$_SESSION['formr'] = [];
}
# for checkbox array values
$this->checkbox_values = [];
# determine if we're switching things on/off
$switches = array_map('trim', explode(',', $switch));
# determines if echoing elements & messages should be suppressed
$this->echo = (in_array('hush', $switches) ? 'hush' : null);
# determines if we should *not* wrap our form elements in a <div>
$this->use_element_wrapper_div = in_array('nowrap', $switches) ? false : true;
}
# HELPERS & UTILITY
public function printr($data)
{
# aids in debugging by not making you have to type all of
# this nonsense out each time you want to print_r() something
if ($data === 'POST') {
echo '<tt><pre>';
print_r($_POST);
echo '</pre></tt>';
} elseif ($data === 'GET') {
echo '<tt><pre>';
print_r($_GET);
echo '</pre></tt>';
} else {
echo '<tt><pre>';
print_r($data);
echo '</pre></tt>';
}
}
public function dd($data)
{
# same as printr() but kills the script
$this->printr($data);
die;
}
public function dump($data)
{
# alias of printr()
return $this->printr($data);
}
protected function _echo($data)
{
# echo everything unless 'hush' was passed during init
if($this->echo === 'hush') {
return $data;
} else {
echo $data;
}
}
public function form_info()
{
# prints the current form settings
# set some defaults
$info = array(
'Form ID' => '',
'Form name' => '',
'Form method' => '',
'Charset' => 'utf-8',
'All Fields Required' => 'FALSE',
'Link to Error' => 'FALSE',
'Inline Validation' => 'FALSE',
'Required Indicator' => '',
'FastForm Wrapper'=> '',
'HTML Purifier' => 'FALSE',
);
$return = '';
if (!empty($this->id)) {
$info['Form ID'] = $this->id;
}
if (!empty($this->name)) {
$info['Form name'] = $this->name;
}
$info['Form method'] = strtoupper($this->method);
$info['Charset'] = $this->charset;
if ($this->required === '*') {
$info['All Fields Required'] = 'TRUE';
}
if ($this->link_errors == true) {
$info['Link to Error'] = 'TRUE';
}
if ($this->inline_errors == true) {
$info['Inline Validation'] = 'TRUE';
}
$info['Required Indicator'] = htmlspecialchars($this->required_indicator);
$info['FastForm Wrapper'] = htmlspecialchars($this->wrapper);
if (isset($this->html_purifier)) {
if (!file_exists($this->html_purifier)) {
$info['HTML Purifier'] = 'Can\'t find class at the specified path';
} else {
$info['HTML Purifier'] = 'TRUE';
}
}
$return .= '<table class="table table-sm">';
foreach ($info as $key => $value) {
$return .= '<tr><td><strong>' . $key . '</strong></td><td>' . $value . '</td></tr>';
}
$return .= '</table>';
$return = str_replace('TRUE', '<span style="color:green">TRUE</span>', $return);
$return = str_replace('FALSE', '<span style="color:red">FALSE</span>', $return);
return $this->_echo('<h3>Form Settings</h3><tt>' . $return . '</tt><br><br><br>');
}
public function info()
{
# alias of form_info()
return $this->form_info();
}
public function honeypot($name)
{
if ($this->honeypot) {
$this->_error_message("Sorry! You can only have one Honeypot per form.<br>Please consider removing <code>\$form->honeypot=\"" . $this->honeypot . "\"</code> from your code.");
}
$this->honeypot = $name;
return $this->_echo('<input type="text" name="' . $name . '" value="" style="display:none">');
}
public function submit($form_id = null)
{
$this->_check_for_honeypot();
# checks if submit button was clicked
if ($_SERVER['REQUEST_METHOD'] == 'POST')
{
$this->_check_for_csrf();
$this->_handle_session_checkbox_arrays();
# checks for a form id to see which form was submitted
if($form_id) {
foreach($_POST as $key => $value) {
if($key == 'FormrID' && $value == $form_id) {
return true;
}
}
} else {
return true;
}
}
return false;
}
public function submitted($form_id = null)
{
# alias of submit()
return $this->submit($form_id);
}
public function in_errors($key)
{
# checks the errors array for the supplied key
$key = trim($key, '[]');
if (in_array($key, $this->errors) || array_key_exists($key, $this->errors)) {
return true;
}
# check if a custom message was added via add_to_errors()
foreach($this->errors as $string) {
# get the key, which comes before the pipe delimeter
if(strstr($string, '|', true) == $key) {
return true;
}
}
return false;
}
public function in_errors_if($key, $string)
{
# if the key is in the errors array, return a user-defined string
if ($this->in_errors($key)) {
return $this->_echo($string);
}
}
public function in_errors_else($key, $error_string, $default_string)
{
# return a different user-defined string depending on if the field is in the errors array
if (!$this->in_errors($key)) {
return $this->_echo($default_string);
} else {
return $this->_echo($error_string);
}
}
public function errors()
{
# checks the errors array and returns the errors
if (!empty($this->errors)) {
return $this->errors;
} else {
return false;
}
}
public function add_to_errors($str)
{
# add a string to the errors array
array_push($this->errors, $str);
}
public function value($name, $value = '')
{
# return SESSION value
if ($this->session) {
$_SESSION[$this->session][$name] = $this->_clean_value($_POST[$name]);
return true;
}
# return POSTed field value
if (isset($_POST[$name])) {
return $this->_echo($this->_clean_value($_POST[$name]));
} elseif ($value) {
return $this->_echo($value);
}
return false;
}
public function slug($str)
{
# create a twitter-style username...
# allow only letters, numbers and underscores
$return = str_replace('-', '_', $str);
$return = str_replace(' ', '_', $return);
$return = preg_replace('/[^A-Za-z0-9_]/', '', $return);
return $return;
}
protected function _generate_hash($length = 32)
{
# don't add vowels and we won't get dirty words...
$chars = 'BCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz1234567890';
# length of character list
$chars_length = (strlen($chars) - 1);
# create our string
$string = $chars[rand(0, $chars_length)];
# generate random string
for ($i = 1; $i < $length; $i = strlen($string)) {
# grab a random character
$r = $chars[rand(0, $chars_length)];
# make sure the same characters don't appear next to each other
if ($r != $string[$i - 1]) $string .= $r;
}
return $string;
}
protected function _wrapper_type()
{
# determines what our field element wrapper will be
if (is_array($this->wrapper)) {
# the user entered a custom wrapper
$return['type'] = 'array';
$return['open'] = $this->wrapper[0];
$return['close'] = $this->wrapper[1];
return $return;
} else {
# use a pre-defined wrapper
if(! in_array($this->wrapper, ['ul', 'ol', 'dl', 'p', 'div'])) {
# set the wrapper's name
$return['type'] = $this->wrapper;
$return['open'] = $return['close'] = null;
return $return;
}
# if tags were entered, strip the brackets
$str = strtolower(trim($this->wrapper, '<>'));
# wrapper is a list
if ($str == 'ul') {
$return['type'] = 'ul';
$return['open'] = '<ul class="' . $this->controls['list-ul'] . '">';
$return['close'] = '</ul>';
return $return;
}
if ($str == 'ol') {
$return['type'] = 'ol';
$return['open'] = '<ol class="' . $this->controls['list-ol'] . '">';
$return['close'] = '</ol>';
return $return;
}
if ($str == 'dl') {
$return['type'] = 'dl';
$return['open'] = '<dl class="' . $this->controls['list-dl'] . '">';
$return['close'] = '</dl>';
return $return;
}
# wrapper is a <p>
if ($str == 'p') {
$return['type'] = 'p';
$return['open'] = '<p>';
$return['close'] = '</p>';
return $return;
}
# wrapper is a <div>
if ($str == 'div') {
$return['type'] = 'div';
$return['open'] = '<div>';
$return['close'] = '</div>';
return $return;
}
}
}
protected function _wrapper($element, $data)
{
# wraps and formats field elements
# $element is the field element in HTML
# $data is the $data array containing the element's attributes
# get the wrapper type
$wrapper_context = $this->_wrapper_type();
if (!$this->use_default_wrapper) {
$wrapper = new \MyWrappers($this);
} else {
$wrapper = new \Wrapper($this);
}
# enclose the element in a custom field wrapper (such as bootstrap) from the Wrapper class
if (!empty($this->wrapper) && !in_array($this->wrapper, $this->default_wrapper_types)){
# dynamically build the method's name...
# $method = the method's name in the Wrapper class
$method = $wrapper_context['type'];
return $this->_echo($wrapper->$method($element, $data));
} else {
# enclose the element in the default wrapper
return $this->_echo($wrapper->default_wrapper($wrapper_context, $element, $data));
}
}
protected function _open_list_wrapper()
{
$wrapper = $this->_wrapper_type();
if ($wrapper['type'] == 'ul' || $wrapper['type'] == 'ol' || $wrapper['type'] == 'dl') {
return $wrapper['open'];
}
}
protected function _close_list_wrapper()
{
$wrapper = $this->_wrapper_type();
if ($wrapper['type'] == 'ul' || $wrapper['type'] == 'ol' || $wrapper['type'] == 'dl') {
return $wrapper['close'];
}
}
protected function _input_types($type)
{
# defines input types for use in other methods
if ($type == 'button') {
return array('submit', 'reset', 'button');
}
if ($type == 'checkbox') {
return array('checkbox', 'radio');
}
if ($type == 'text') {
return array('text', 'textarea', 'password', 'color', 'email', 'date', 'datetime', 'datetime_local', 'month', 'number', 'range', 'search', 'tel', 'time', 'url', 'week');
}
}
protected function _attributes($data)
{
// TODO: thinking this method is no longer needed after _fix_classes was updated in 1.4. keeping it for a while just in case...
# adds additional attributes and classes to form fields
$string = $classes = null;
# remove autocorrect, etc from certain field types
# TODO figure out a better way of doing this? Or just omit it?
// if ($data['type'] == 'email' || $data['type'] == 'password' || $data['type'] == 'search' || $data['type'] == 'url') {
// $string .= ' autocorrect="off" autocapitalize="off" ';
// }
# add the button class
if (in_array($data['type'], $this->_input_types('button'))) {
# don't add the class if it's empty
if ($this->controls['button'] && !$data['string']) {
$string .= 'class="' . $this->controls['button'] . ' ';
}
}
# check if field is required
if ($this->_check_required($data['name'], $data)) {
# add the errors class
if ($this->in_errors($data['name']) && !$this->_wrapper_is('framework')) {
$classes .= $this->controls['text-error'] . ' ';
}
# classes exist. build the string
if ($classes != null) {
$string = 'class="' . $classes;
}
}
# working with the 'string' argument
if (!empty($data['string'])) {
# see if there are existing classes...
if (stristr($data['string'], 'class="') && $string != null) {
# add new classes to existing classes
return ' ' . str_replace('class="', $string, $data['string']);
}
if ($string != null) {
# classes do not exist, however this field is required, so add them
return rtrim($string, ' ') . '" ' . $data['string'];
}
# just return the string
return ' ' . $data['string'];
}
return false;
}
protected function _fix_classes($element, $data)
{
# automatically add Formr (and framework) CSS classes to elements
$return = $classes = null;
// get the css classes (if any)
if (preg_match('/class="(.*?)"/', $data['string'], $match) == 1) {
$classes = $match[1];
}
# strip the classes - and class element - and get the rest of the string parameter
$class_string = 'class="'.$classes.'"';
$string = str_replace($class_string, '', $data['string']);
# add default classes
if (!empty($this->controls['input']) && !in_array($data['type'], $this->excluded_types)) {
if($data['type'] == 'file') {
$classes .= ' ' . $this->controls['file'];
} else {
$classes .= ' ' . $this->controls['input'];
}
}
# bootstrap inline checkboxes & radios
if ($this->_wrapper_is('bootstrap') && $this->type_is_checkbox($data)) {
if (isset($data['checkbox-inline'])) {
$classes .= ' ' . $this->controls['checkbox-inline'];
} else {
$classes .= ' ' . $this->controls['form-check-input'];
}
}
if ($this->in_errors($data['name'])) {
# add 'error' class on element
if ($this->_wrapper_is('framework')) {
foreach($_POST as $key => $value) {
if($key == $data['name']) {
$classes .= ' ' . $this->controls['is-invalid'];
}
}
} else {
$classes .= ' ' . $this->controls['text-error'];
}
}
elseif ($this->submitted() && $this->show_valid) {
# add 'success' class on element
if ($this->_wrapper_is('framework')) {
foreach($_POST as $key => $value) {
if($key == $data['name']) {
$classes .= ' ' . $this->controls['is-valid'];
}
}
}
}
if (empty($class_string)) {
if ($data['type'] == 'submit' || $data['type'] == 'button') {
$classes = $this->controls['button'];
if($this->_wrapper_is('bootstrap')) {
$classes = $this->controls['button-primary'];
}
}
}
return ' class="' . $classes . '" ' . $string;
}
protected function _set_array_values($data, $label = '', $value = '', $id = '', $string = '', $inline = '', $selected = '', $options = '')
{
# puts the entered strings into an array
if (!is_array($data)) {
$data = array(
'name' => $data,
'label' => $label,
'value' => $value,
'id' => $id,
'string' => $string,
'inline' => $inline,
'selected' => $selected,
'options' => $options
);
}
return $data;
}
protected function _clean_value($str = '', $allow_html = false)
{
# makes entered values a little safer.
# this function was left somewhat sparse because i didn't want to assume i knew what kind of data you were going to allow,
# so i just put in some basic sanitizing functions. if you want more control, just tweak this to your heart's desire! :)
# Formr can also use HTMLPurifier
# just download the HTMLPurifier class and drop it in at the top of this script. Formr will do the rest.
# http://htmlpurifier.org
# return an empty value
if ($str == '') {
return '';
}
if ($this->html_purifier && file_exists($this->html_purifier)) {
# we're using HTML Purifier
if ($this->charset == strtolower('utf-8')) {
# include the HTML Purifier class
require_once($this->html_purifier);
# set it up using default settings (feel free to alter these if needed)
$p_config = \HTMLPurifier_Config::createDefault();
$purifier = new \HTMLPurifier($p_config);
return $purifier->purify($str);
} else {
$config = \HTMLPurifier_Config::createDefault();
$config->set('Core', 'Encoding', $this->charset);
$config->set('HTML', 'Doctype', $this->doctype);
$purifier = new \HTMLPurifier($config);
}
} else {
if (is_string($str)) {
# trim...
$str = trim($str);
# perform basic sanitization...
if ($allow_html == false) {
# strip html tags and prevent against xss
$str = strip_tags($str);
} else {
# allow html
if($this->sanitize_html) {
$str = filter_var($str,FILTER_SANITIZE_SPECIAL_CHARS);
} else {
$str = $str;
}
}
return $str;
} else {
# clean and return the array
foreach ($str as $value) {
if ($allow_html == false) {
# strip html tags and prevent against xss
$value = strip_tags($value);
} else {
# allow html
if ($this->sanitize_html) {
$value = filter_var($value,FILTER_SANITIZE_SPECIAL_CHARS);
} else {
$value = $value;
}
}
}
return $value;
}
}
}
protected function _build_input_groups($data)
{
# we're building a checkbox or radio group based on multiple field names inside $data['value']
# check if $data['value'] starts with a left bracket
# if so, we know we have multiple values
if ($this->is_in_brackets($data['value'])) {
$return = null;
# the values are comma-delimited, trim the brackets and break the value apart
$additional_fields = explode($this->delimiter[1], trim($data['value'], '[]'));
# output the label text for the group
if ($this->wrapper == 'bootstrap') {
# bootstrap control-label
$return .= '<label class="'.$this->controls['label'].'">'.$data['label'].'</label>'.$this->_nl(1);
} else {
# 'regular' label
$return .= '<label>'.$data['label'].'</label>'.$this->_nl(1);
}
# make sure we're dealing with an array, just to be safe
if (is_array($additional_fields)) {
# output the label text for the group
//$return .= $this->_t(1).$this->label($data);
# loop through each new field name and print it out - wrapped in a label
foreach ($additional_fields as $key => $value) {
# make the element's label the same as the value
$data['label'] = ucwords($value);
# add the element's value
$data['value'] = $value;
# make the ID the element's name so that the label is clickable
$data['id'] = $value;
$data['group'] = true;
# if using bootstrap, wrap the elements in a bootstrap class
if ($this->_wrapper_is('bootstrap')) {
$return .= $this->_t(1) . '<div class="' . $this->controls[$data['type']] . '">';
}
# return the element wrapped in a label
$return .= '<label for="'.$this->make_id($data).'">';
$return .= $this->_create_input($data);
$return .= $data['label'].'</label>';
# close the bootstrap class
if ($this->_wrapper_is('bootstrap')) {
$return .= $this->_nl(1) . $this->_t(1) . '</div>' . $this->_nl(1);
}
}
}
return $return;
} else {
return false;
}
}
protected function _comment($string)
{
# creates an HTML comment
if ($this->minify || !$this->comments) {
return false;
} else {
return '<!-- ' . $string . ' -->';
}
}
protected function _print_field_comment($data)
{
# returns the HTML field comment for display in the wrapper
if (in_array($data['type'], $this->_input_types('checkbox'))) {
return $this->_comment($data['id']);
} else {
return $this->_comment($data['name']);
}
}
protected function _check_filesize($handle)
{
$kb = 1024;
$mb = $kb * 1024;
if ($handle['size'] > $this->upload_max_filesize) {
# convert bytes to megabytes because it's more human readable
$size = round($this->upload_max_filesize / $mb, 2) . ' MB';
$this->errors['file-size'] = 'File size exceeded. The file can not be larger than ' . $size;
return true;
} else {
return false;
}
}
protected function _get_file_extension($handle)
{
# get's a file's extension
return strtolower(ltrim(strrchr($handle['name'], '.'), '.'));
}
protected function _check_upload_accepted_types($handle)
{
# get the accepted file types
# we can check either the extension or the mime type, depending on what the user entered
if (!$this->_upload_accepted_types() && !$this->_upload_accepted_mimes()) {
$this->errors['accepted-types'] = 'Oops! You must specify the allowed file types using either $upload_accepted_types or $upload_accepted_mimes.';
return false;
}
# see if it's in the accepted upload types
if ($this->upload_accepted_types && !in_array($handle['ext'], $this->_upload_accepted_types())) {
$this->errors['accepted-types'] = 'Oops! The file was not uploaded because it is in an unsupported file type.';
return false;
}
$parts = @getimagesize($handle['tmp_name']);
# see if it's in the accepted mime types
if ($this->upload_accepted_mimes && !in_array($parts['mime'], $this->_upload_accepted_mimes())) {
$this->errors['accepted-types'] = 'Oops! The file was not uploaded because it is an unsupported mime type.';
return false;
}
return true;
}
protected function _slug_filename($filename)
{
# slug the filename to make it safer
return strtolower(preg_replace('/[^A-Z0-9._-]/i', '_', $filename));
}
protected function _rename_file($handle)
{
$new_filename = null;
# if the file extension is .jpeg, rename to .jpg
if ($handle['ext'] == 'jpeg') {
$handle['ext'] = 'jpg';
}
# rename the uploaded file with a unique hash
if (mb_substr($this->upload_rename, 0, 4) == 'hash') {
# user wants to specify the length of the hash
if (mb_substr($this->upload_rename, 0, 5) == 'hash[') {
# get the length of the hash
$length = trim($this->upload_rename, 'hash[]');
# rename the file
$new_filename = $this->_generate_hash($length) . '.' . $handle['ext'];
} else {
# rename with the default hash length
$new_filename = $this->_generate_hash() . '.' . $handle['ext'];
}
}
# rename the uploaded file with a custom string
if (mb_substr($this->upload_rename, 0, 6) == 'string')
{
# strip everything which surrounds our new filename
$string = trim($this->upload_rename, 'string[]');
# append the uploaded file's extension to our new filename
$new_filename = $string . '.' . $handle['ext'];
# generate a random filename if there is already a file with the same name
if(file_exists($this->upload_dir.'/'. $new_filename)) {
$new_filename = $string . '-' . mt_rand(1000,9999) . '.' . $handle['ext'];
}
}
# rename the uploaded file with a timestamp
if ($this->upload_rename == 'timestamp') {
$new_filename = time() . '.' . $handle['ext'];
}
# rename the uploaded file with a prepended string
if (substr($this->upload_rename, 0, 7) == 'prepend') {
# strip the brackets from our prepend string
$prepend = trim($this->upload_rename, 'prepend[]');
# get the file extension
$ext = '.' . $handle['ext'];
# remove the extension from the file name
$name = str_replace($ext, '', $handle['name']);
$new_filename = $prepend . $name . '.' . $handle['ext'];
}
return $new_filename;
}
protected function _upload_accepted_types()
{
if ($this->upload_accepted_types) {
# we're allowing jpg, gif and png
if ($this->upload_accepted_types == 'images') {
return array('jpg', 'jpeg', 'gif', 'png');
}
# explode the accepted file types into an array
$types = explode(',', str_replace('.', '', $this->upload_accepted_types));
return $types;
} else {
return false;
}
}
protected function _upload_accepted_mimes()
{
if ($this->upload_accepted_mimes) {
# we're allowing jpg, gif and png
if ($this->upload_accepted_mimes == 'images') {
return array('image/jpg', 'image/jpeg', 'image/gif', 'image/png');
}
# explode the accepted file types into an array
$types = explode(',', $this->upload_accepted_mimes);
return $types;
} else {
return false;
}
}
protected function _upload_files($name)
{
# don't upload if there are form errors
if (!empty($this->errors)) {
return false;
}
$files = array();
if (!empty($_FILES[$name]['tmp_name']) && !empty($_FILES[$name]['tmp_name'][0])) {
if (is_array($_FILES[$name]['tmp_name']) && count($_FILES[$name]['tmp_name']) > 1) {
# we're dealing with multiple uploads
for ($i = 0; $i < count($_FILES[$name]['tmp_name']); $i++) {
if (!empty($_FILES[$name]['tmp_name']) && is_uploaded_file($_FILES[$name]['tmp_name'][$i])) {
# make for a prettier array and reassign the key/values
$handle['key'] = $name;
$handle['name'] = $_FILES[$name]['name'][$i];
$handle['size'] = $_FILES[$name]['size'][$i];
$handle['type'] = $_FILES[$name]['type'][$i];
$handle['tmp_name'] = $_FILES[$name]['tmp_name'][$i];
# put each array into the $files array
array_push($files, $this->_process_image($handle));
}
}
return $files;
} else {
# we're dealing with a single upload
if (!empty($_FILES[$name]['tmp_name'][0]) && is_uploaded_file($_FILES[$name]['tmp_name'][0])) {
# we're using the input_upload_multiple() method, so we have to compensate for the array
# make for a prettier array and reassign the key/values
$handle['key'] = $name;
$handle['name'] = $_FILES[$name]['name'][0];
$handle['size'] = $_FILES[$name]['size'][0];
$handle['type'] = $_FILES[$name]['type'][0];
$handle['tmp_name'] = $_FILES[$name]['tmp_name'][0];
}
elseif (!empty($_FILES[$name]['tmp_name']) && is_uploaded_file($_FILES[$name]['tmp_name'])) {
# make for a prettier array and reassign the key/values
$handle['key'] = $name;
$handle['name'] = $_FILES[$name]['name'];
$handle['size'] = $_FILES[$name]['size'];
$handle['type'] = $_FILES[$name]['type'];
$handle['tmp_name'] = $_FILES[$name]['tmp_name'];
}
return $this->_process_image($handle);
}
}
return false;
}
protected function _process_image($handle)
{
# get the file's extension
$handle['ext'] = $this->_get_file_extension($handle);
# see if user wants to rename the file
if ($this->upload_rename) {
$handle['name'] = $this->_rename_file($handle);
} else {
# if the file extension is .jpeg, rename to .jpg
if ($handle['ext'] == 'jpeg') {
$handle['name'] = rtrim($handle['filename'], 'jpeg') . 'jpg';
$handle['ext'] = 'jpg';
}
}
# make sure file is in the accepted types / accepted mimes array
if (!$this->_check_upload_accepted_types($handle)) {
return false;
}
# make sure file is not over the max_filesize
if ($this->_check_filesize($handle)) {
return false;
}
# add a trailing slash if $upload_dir doesn't have one
if (substr($this->upload_dir, -1) != '/') {
$this->upload_dir = $this->upload_dir . '/';
}
# define the upload path and new file name
$upload_directory = $this->upload_dir . $handle['name'];
# move the file to its final destination
if (@move_uploaded_file($handle['tmp_name'], $upload_directory)) {
# see if we're resizing the image
if ($this->upload_resize) {
# loop through the resize array and process each key
foreach ($this->upload_resize as $resize_key => $resize_values) {
$handle[$resize_key] = $this->_resize_image($handle, $resize_key, $resize_values);
}
}
# return the array
return $handle;
} else {
$this->errors['upload-error-move'] = 'There was an error uploading a file: it could not be moved to the final destination. Please check the directory permissions on ' . $this->upload_dir . ' and try again.';
# we want to display the correct error messages, so we'll return true because the file was uploaded
return true;
}
}
protected function _resize_image($handle, $resize_key, $resize_values)
{
# don't upload if there are form errors
if (!empty($this->errors)) {
return false;
}
# $upload_resize hasn't been set, so don't resize!
if (!$this->upload_resize) {
return false;
}
$prepend = '';
# put the resize values into an array
$parts = explode(',', $resize_values);
# get the thumb width
if (isset($parts[0])) {
$thumb_width = $parts[0];
$handle[$resize_key]['width'] = $parts[0];
} else {
$this->errors[$handle['key']] = $handle['key'] . ': image not resized. You must specify a numeric width for this resized image.';
return false;
}
# get the thumb height
if (isset($parts[1])) {
$thumb_height = $parts[1];
$handle[$resize_key]['height'] = $parts[1];
} else {
$this->errors[$handle['key']] = $handle['key'] . ': image not resized. You must specify a numeric height for this resized image.';
return false;
}
# check if we're prepending something onto the file name
if (isset($parts[2])) {
$prepend = $parts[2];
$handle[$resize_key]['prepend'] = $parts[2];
}
# if the user hasn't specified a resize (tn) directory, put resized image in the same directory
if (isset($parts[3])) {
$thumb_dir = $parts[3];
$handle[$resize_key]['dir'] = $parts[3];
} else {
$thumb_dir = $this->upload_dir;
}
# add a trailing slash if necessary
if (substr($thumb_dir, 0, -1) != '/') {
$thumb_dir = $thumb_dir . '/';
}
# get the resized image's quality, or default to 80% (JPG only)
if (isset($parts[4])) {
$quality = $parts[4];
} else {
$quality = 80;
}
# load original image and get size and type
if ($handle['type'] == 'image/jpeg') {
$original_file = imagecreatefromjpeg($this->upload_dir . $handle['name']);
}
if ($handle['type'] == 'image/png') {
$original_file = imagecreatefrompng($this->upload_dir . $handle['name']);
}
if ($handle['type'] == 'image/gif') {
$original_file = imagecreatefromgif($this->upload_dir . $handle['name']);
}
$original_file_width = imagesx($original_file);
$original_file_height = imagesy($original_file);
# calculate resized image's size
$new_width = $thumb_width;
$new_height = floor($original_file_height * ($new_width / $original_file_width));
# if upload's width or height is larger than specified width or heigh, perform resize
if ($original_file_width > $new_width || $original_file_height > $new_height) {
# create a new temporary image
$tmp_image = imagecreatetruecolor($new_width, $new_height);
# copy and resize old image into new image
imagecopyresized($tmp_image, $original_file, 0, 0, 0, 0, $new_width, $new_height, $original_file_width, $original_file_height);
# save resized image
if ($handle['type'] == 'image/jpeg') {
imagejpeg($tmp_image, $thumb_dir . $prepend . $handle['name'], $quality);
}
if ($handle['type'] == 'image/png') {
imagepng($tmp_image, $thumb_dir . $prepend . $handle['name']);
}
if ($handle['type'] == 'image/gif') {
imagegif($tmp_image, $thumb_dir . $prepend . $handle['name']);
}
$handle[$resize_key]['name'] = $prepend . $handle['name'];
# return the file name
return $handle[$resize_key];
} else {
return false;
}
}
protected function _check_required($name)
{
# checks the field name to see if that field is required
$this->required_fields = array();
// $this->typested_fields = array();
# all fields are required
if ($this->required === '*') {
return true;
}
# required fields are set. determine which individual fields are required
if ($this->required == true) {
# get any required fields
$required_fields = explode($this->delimiter[0], rtrim($this->required, '[]'));
# get any omitted fields inside round brackets ()
if (preg_match_all('#\((([^()]+|(?R))*)\)#', rtrim($this->required, '[]'), $matches)) {
$fields = implode(',', $matches[1]);
$omitted_fields = explode($this->delimiter[0], $fields);
}
# if the omitted_fields array in not empty...
if (!empty($omitted_fields)) {
if (in_array($name, $omitted_fields)) {
# field name is not required
return false;
} else {
# everything *but* this field is required
return true;
}
}
# field name is required
if (in_array($name, $required_fields)) {
return true;
}
} else {
return false;
}
}
protected function _nl($count = 1)
{
# adds as many new lines as we need for formatting our html
if ($this->minify) {
return false;
}
$return = null;
if ($count > 1) {
for ($i = 0; $i <= $count; $i++) {
$return .= "\r\n";
}
} else {
$return = "\r\n";
}
return $return;
}
protected function _t($count)
{
# adds as many tabs as we need for formatting our html
if ($this->minify) {
return false;
}
$return = null;
if ($count > 1) {
for ($i = 0; $i <= $count; $i++) {
$return .= "\t";
}
} else {
$return = "\t";
}
return $return;
}
protected function is_not_empty($value)
{
# check if value is not empty - including zeros
if (!empty($value) || (isset($value) && $value === "0") || (isset($value) && $value === 0)) {
return true;
} else {
return false;
}
}
# MESSAGING
public function messages($open_tag = '', $close_tag = '')
{
# this function prints client-side validation messages to the browser
# print a message if the following properties are set
if($this->success_message || $this->warning_message || $this->info_message || $this->error_message)
{
if($this->success_message) {
$alert_control = 'alert-s';
$heading = 'Success';
$parts = explode('|', $this->success_message);
if(count($parts) > 1) {
$heading = $parts[1];
}
$message = $parts[0];
}
if($this->warning_message) {
$alert_control = 'alert-w';
$heading = 'Warning';
$parts = explode('|', $this->warning_message);
if (count($parts) > 1) {
$heading = $parts[1];
}
$message = $parts[0];
}
if($this->info_message) {
$alert_control = 'alert-i';
$heading = 'Info';
$parts = explode('|', $this->info_message);
if (count($parts) > 1) {
$heading = $parts[1];
}
$message = $parts[0];
}
if($this->error_message) {
$alert_control = 'alert-e';
$heading = 'Error';
$parts = explode('|', $this->error_message);
if (count($parts) > 1) {
$heading = $parts[1];
}
$message = $parts[0];
}
if ($this->_wrapper_is('bootstrap')) {
$return = $this->_bootstrap_alert($alert_control, $message, $heading);
} elseif ($this->_wrapper_is('bulma')) {
$return = $this->_bulma_alert($alert_control, $message, $heading);
} else {
$return = $this->_formr_alert($alert_control, $message, $heading);
}
return $this->_echo($return);
}
$return = null;
# flash messages
if (isset($_SESSION['formr']['flash'])) {
if (!empty($_SESSION['formr']['flash']['success'])) {
$return .= $this->success_message($_SESSION['formr']['flash']['success']);
}
if (!empty($_SESSION['formr']['flash']['error'])) {
$return .= $this->error_message($_SESSION['formr']['flash']['error']);
}
if (!empty($_SESSION['formr']['flash']['warning'])) {
$return .= $this->warning_message($_SESSION['formr']['flash']['warning']);
}
if (!empty($_SESSION['formr']['flash']['info'])) {
$return .= $this->info_message($_SESSION['formr']['flash']['info']);
}
$_SESSION['formr']['flash'] = NULL;
unset($_SESSION['formr']['flash']);
return $this->_echo($return);
}
# returns a user-defined message
if (isset($this->message)) {
return $this->_echo($this->message);
}
# prints form errors
if ($this->inline_errors == false) {
if (empty($open_tag) && empty($close_tag)) {
$open_tag = null;
$close_tag = null;
}
if ($this->errors()) {
# check if the user has supplied their own error messages
if (empty($this->error_messages)) {
$return .= $open_tag;
$i=0;
foreach ($this->errors as $key => $value) {
if ($this->link_errors == true) {
# user wants to link to the form fields upon error
$return .= '<a href="#' . $key . '" class="' . $this->controls['link'] . '">' . $value . '</a><br>';
} else {
# print the message
if(strpos($value, '|')) {
# remove the key if a custom message was added via add_to_errors()
$return .= ltrim(strstr($value, '|'), '|') . '<br>';
} else {
$return .= $value.'<br>';
}
}
$i++;
}
$return .= $close_tag . $this->_nl(1);
} else {
$i=0;
foreach ($this->error_messages as $key => $value) {
if ($this->in_errors($key)) {
# print the message
$return .= $value . $this->_nl(1);
}
$i++;
}
}
# determine the heading message based on how many errors there are
if($i > 1) {
$heading = $this->error_heading_plural;
} else {
$heading = $this->error_heading_singular;
}
# display the appropriate error dialogue
if ($this->_wrapper_is('bootstrap')) {
return $this->_echo($this->_bootstrap_alert('alert-e', $return, $heading));
} elseif ($this->_wrapper_is('bulma')) {
return $this->_echo($this->_bulma_alert('alert-e', $return, $heading));
} else {
return $this->_echo($this->_formr_alert('alert-e', $return, $heading));
}
}
}
}
public function warning_message($message, $heading = null, $flash = false)
{
if ($flash == true) {
return $_SESSION['formr']['flash']['warning'] = $message;
}
if($this->_wrapper_is('bootstrap')) {
$return = $this->_bootstrap_alert('alert-w', $message, $heading);
} elseif($this->_wrapper_is('bulma')) {
$return = $this->_bulma_alert('alert-w', $message, $heading);
} else {
$return = $this->_formr_alert('alert-w', $message, $heading);
}
return $this->_echo($return);
}
public function success_message($message, $heading = null, $flash = false)
{
if ($flash == true) {
return $_SESSION['formr']['flash']['success'] = $message;
}
if ($this->_wrapper_is('bootstrap')) {
$return = $this->_bootstrap_alert('alert-s', $message, $heading);
} elseif ($this->_wrapper_is('bulma')) {
$return = $this->_bulma_alert('alert-s', $message, $heading);
} else {
$return = $this->_formr_alert('alert-s', $message, $heading);
}
return $this->_echo($return);
}
public function error_message($message, $heading = null, $flash = false)
{
if ($flash == true) {
return $_SESSION['formr']['flash']['error'] = $message;
}
if ($this->_wrapper_is('bootstrap')) {
$return = $this->_bootstrap_alert('alert-e', $message, $heading);
} elseif ($this->_wrapper_is('bulma')) {
$return = $this->_bulma_alert('alert-e', $message, $heading);
} else {
$return = $this->_formr_alert('alert-e', $message, $heading);
}
return $this->_echo($return);
}
public function info_message($message, $heading = null, $flash = false)
{
if ($flash == true) {
return $_SESSION['formr']['flash']['info'] = $message;
}
if ($this->_wrapper_is('bootstrap')) {
$return = $this->_bootstrap_alert('alert-i', $message, $heading);
} elseif ($this->_wrapper_is('bulma')) {
$return = $this->_bulma_alert('alert-i', $message, $heading);
} else {
$return = $this->_formr_alert('alert-i', $message, $heading);
}
return $this->_echo($return);
}
private function _success_message($str)
{
$return = '<div style="margin: 20px 20px 40px 20px; padding:15px; background: #53A451; color: white; border-radius: 5px; text-align: center">';
$return .= $str;
$return .= '</div>';
return $this->_echo($return);
}
private function _error_message($message)
{
if ($this->wrapper) {
$this->error_message($message);
} else {
$return = "\r\n<style>";
$return .= '.formr-error {margin: 20px; padding:15px; background: #CB444A; color: white; border-radius: 5px; text-align: center;}';
$return .= 'code {color: yellow;}';
$return .= "</style>\r\n";
$return .= '<div class="formr-error">';
$return .= $message;
$return .= '</div>';
return $this->_echo($return);
}
}
private function _get_alert_heading($type, $heading = null)
{
if (!$heading) {
if ($type == 'alert-w') {
$heading = 'Warning';
} elseif ($type == 'alert-s'
) {
$heading = 'Success';
} elseif ($type == 'alert-e') {
$heading = 'Error';
} else {
$heading = 'Info';
}
}
return $heading;
}
private function _bulma_alert($type, $message, $heading = '')
{
$return = "<article class=\"message {$this->controls[$type]}\">\r\n";
$return .= " <div class=\"message-header\">\r\n";
$return .= " <p>{$this->_get_alert_heading($type,$heading)}</p>\r\n";
$return .= " </div>\r\n";
$return .= " <div class=\"message-body\">\r\n";
$return .= " {$message}\r\n";
$return .= " </div>\r\n";
$return .= "</article>\r\n";
return $return;
}
private function _bootstrap_alert($type, $message, $heading = null)
{
$return = "<div class=\"{$this->controls[$type]} alert-dismissible fade show\" role=\"alert\">\r\n";
if($this->wrapper == 'bootstrap5' || $this->wrapper == 'bootstrap') {
$return .= "<button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"alert\" aria-label=\"Close\"></button>";
} else {
$return .= "<button type=\"button\" class=\"close\" data-dismiss=\"alert\"><span aria-hidden=\"true\">&times;</span><span class=\"sr-only\">Close</span></button>\r\n";
}
if ($heading) {
$return .= "<h4 class=\"alert-heading\">{$this->_get_alert_heading($type,$heading)}</h4>\r\n";
}
$return .= "{$message}\r\n";
$return .= "</div>\r\n";
return $return;
}
private function _formr_alert($type, $message, $heading = null)
{
if($type == 'alert-s') {
return $this->_success_message($message);
}
return $this->_error_message($message);
}
# PROCESS POST AND VALIDATE
public function post($name, $label = '', $rules = '')
{
return $this->_post($name, $label, $rules);
}
public function get($name, $label = '', $rules = '')
{
return $this->_post($name, $label, $rules);
}
public function fastpost($name)
{
# for the truly lazy! ;)
# returns an associative array of all posted keys/values, minus the submit button (if it's named 'submit')
if ($name === 'POST')
{
$keys = array();
foreach ($_POST as $key => $value) {
if ($key != $this->submit && $key != 'submit' && $key != 'button') {
# automatically validate based on field name, ie; email = valid_email
# if a field name matches, and rules are assigned in the fastpost_rules() method, they'll be applied
$keys[$key] = $this->post($key, $key, $this->_fp_rules($key));
}
}
return $keys;
} else {
# this part works with the Forms class to allow for quick validation by using pre-built form/validation sets
if(is_array($name)) {
$data = $name;
} else {
# create the array by passing the function name and the validate flag to the Forms class
if (!$this->use_default_wrapper) {
$data = \MyForms::$name('validate');
} else {
$data = \Forms::$name('validate');
}
}
# run it through the validate function
foreach ($data as $key => $value) {
# $value[0] = custom strings
# $value[1] = validation rules
if (isset($value[1])) {
# a validation rule was set
$keys[$key] = $this->post($key, $value[0], $value[1]);
} else {
# a validation rule was not set
$keys[$key] = $this->post($key, $value[0]);
}
}
return $keys;
}
}
protected function _post($name, $label = '', $rules = [])
{
# this method processes the $_POST/$_GET values and performs validation (if required)
$this->_check_for_honeypot();
# set the variable in which we'll store our $_POST/$_GET data
$post = null;
# check for uploaded files first
if ($this->uploads && !empty($_FILES[$name]['tmp_name'])) {
if (!$this->upload_dir) {
$this->_error_message('Please specify an upload directory with $form->upload_dir.');
return false;
}
if (!$this->upload_accepted_types && !$this->upload_accepted_mimes) {
$this->_error_message('Please specify the accepted file types with $upload_accepted_mimes or $upload_accepted_types.');
return false;
}
if ($return = $this->_upload_files($name)) {
return $return;
}
}
# prevents error classes from contaminating all the fields in a group
if (stristr($name, '[]')) {
$name = str_replace('[]', '', $name);
}
# process the POST data
# see if we're dealing with $_POST or $_GET
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
if (isset($_POST[$name]) && $_POST[$name] != '') {
$post = $_POST[$name];
}
} else {
if (isset($_GET[$name]) && $_GET[$name] != '') {
$post = $_GET[$name];
}
}
if (is_array($post)) {
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
foreach ($_POST[$name] as $key => $value) {
if ($this->session) {
if(@!in_array($value, $_SESSION[$this->session][$name])) {
$_SESSION[$this->session][$name][] = $value;
}
}
}
} else {
foreach ($_GET[$name] as $key => $value) {
if ($this->session) {
if (@!in_array($value, $_SESSION[$this->session][$name])) {
$_SESSION[$this->session][$name][] = $value;
}
}
}
}
} else {
if ($this->session && !empty($post)) {
$_SESSION[$this->session][$name] = $post;
}
}
# check to see if we have a human readable string and a custom error message string
if (!empty($label) && stristr($label, $this->delimiter[1])) {
# we have a custom error message string
$parts = explode($this->delimiter[1], $label);
# we'll put the human readable label into the $label property
$label = $parts[0];
# we'll put the custom error message string into the $string property
$string = $parts[1];
$data['string'] = $string;
}
# check if this field is required
# we can't check if isset($_POST[$name]) because checkboxes and radios
# don't post if they're not ticked so we have to check everything
if ($this->_check_required($name) && $post == null) {
if (!empty($label)) {
if (!isset($string)) {
$this->errors[$name] = '<strong>' . $label . '</strong> is required';
} else {
$this->errors[$name] = $string;
}
} else {
$this->errors[$name] = 'The <strong>' . $name . '</strong> field is required';
}
}
# validation rules are a string; let's put them into an array
if(! is_array($rules)) {
$rules = explode($this->delimiter[1], $rules);
}
# push 'allow_html' to the back so it processes last
if (($key = array_search('allow_html', $rules)) !== false) {
unset($rules[$key]);
array_push($rules, 'allow_html');
}
# get busy validating!
$return = null;
# get the $data array ready...
$data['post'] = $post;
$data['label'] = $label;
$data['name'] = $name;
# process validation rules
# if we're posting an array, don't run it through the validation rules because
# each individual value could break the validation for the entire group
if (!is_array($data['post']))
{
foreach ($rules as $rule) {
# process boolean validation rules
$return = $this->_validate_bool_rules($rule, $data);
}
foreach ($rules as $rule) {
# allow HTML?
$allow_html = ($rule == 'allow_html') ? true : null;
# process string validation rules
$return = $this->_validate_string_rules($rule, $return);
}
# run it through the cleaning method as a final step
return $this->_clean_value($return, $allow_html);
} else {
# return the array without validation
return $post;
}
}
protected function _validation_message($data, $message)
{
# determines which message to display during validation
if($this->_suppress_formr_validation_errors($data)) {
# always display the user-defined validation message
$this->errors[$data['name']] = $data['string'];
} else {
if(!empty($data['string'])) {
# display the user-defined validation message
$this->errors[$data['name']] = $data['string'];
} else {
if(!empty($data['label'])) {
# show the user-defined field name
$this->errors[$data['name']] = $data['label'].' '.$message;
} else {
# fallback to the field name
$this->errors[$data['name']] = $data['name'].' '.$message;
}
}
}
}
protected function _get_matches($rule)
{
preg_match_all("/\[(.*?)\]/", $rule, $matches);
if(! isset($matches[1][0])) {
$this->_error_message('Oops! The <strong>'.$rule.'</strong> validation rule is missing a required parameter.<br>Read the <a href="https://formr.github.io/validation/#validation-rules" style="color:white; text-decoration:underline" target="_blank">Validation Rule docs</a> for more information on using this rule.');
return false;
} else {
return $matches[1][0];
}
}
protected function _validate_bool_rules($rule, $data)
{
# the following rules evaluate the posted string
# this rule must match a user-defined regex
if (mb_substr($rule, 0, 5) == 'regex')
{
$rule = ltrim($rule, 'regex[');
$rule = rtrim($rule, ']');
if (preg_match($rule, $data['post']))
{
$this->_validation_message($data, 'does not match the required parameters');
}
return $data['post'];
}
# this rule must *not* match a user-defined regex
elseif (mb_substr($rule, 0, 9) == 'not_regex')
{
$rule = ltrim($rule, 'not_regex[');
$rule = rtrim($rule, ']');
if (!preg_match($rule, $data['post']))
{
$this->_validation_message($data, 'can not be an exact match');
}
return $data['post'];
}
# match one field's contents to another
elseif (mb_substr($rule, 0, 7) == 'matches')
{
preg_match_all("/\[(.*?)\]/", $rule, $matches);
$match_field = $matches[1][0];
if ($data['post'] != $_POST[$match_field])
{
if($this->_suppress_formr_validation_errors($data)) {
$this->errors[$data['name']] = $data['string'];
} else {
$this->_validation_message($data, ' does not match '.$match_field);
}
}
return $data['post'];
}
# min length
elseif (mb_substr($rule, 0, 10) == 'min_length' || mb_substr($rule, 0, 3) == 'min')
{
if(empty($data['post']) && ! $this->_check_required($data['name'])) {
return;
}
if(! $match = $this->_get_matches($rule)) {
return $data['post'];
}
if (strlen($data['post']) < $match)
{
$this->_validation_message($data, 'must be at least '.$match.' characters');
}
return $data['post'];
}
# max length
elseif (mb_substr($rule, 0, 10) == 'max_length' || mb_substr($rule, 0, 3) == 'max' || mb_substr($rule, 0, 2) == 'ml')
{
if(! $match = $this->_get_matches($rule)) {
return $data['post'];
}
if ($this->is_not_empty($data['post']) && (strlen($data['post']) > $match))
{
if($this->_suppress_formr_validation_errors($data)) {
$this->errors[$data['name']] = $data['string'];
} else {
if ($match == 1 && strlen($data['post']) > 1) {
$this->_validation_message($data, 'must be 1 character');
} else {
$this->_validation_message($data, 'can not be more than '.$match.' characters');
}
}
}
return $data['post'];
}
# exact length
elseif (mb_substr($rule, 0, 12) == 'exact_length' || mb_substr($rule, 0, 5) == 'exact' || mb_substr($rule, 0, 2) == 'el')
{
if(! $match = $this->_get_matches($rule)) {
return $data['post'];
}
if (strlen($data['post']) != $match)
{
if($this->_suppress_formr_validation_errors($data)) {
$this->errors[$data['name']] = $data['string'];
} else {
$this->_validation_message($data, 'must be exactly '.$match.' characters');
}
}
return $data['post'];
}
# less than or equal to (number)
elseif (mb_substr($rule, 0, 18) == 'less_than_or_equal' || mb_substr($rule, 0, 3) == 'lte')
{
if (!is_numeric($data['post']))
{
if(!empty($data['label'])) {
$this->errors[$data['name']] = $data['label'] . ' must be a number';
} else {
$this->errors[$data['name']] = $data['name'] . ' must be a number';
}
return $data['post'];
}
if(! $match = $this->_get_matches($rule)) {
return $data['post'];
}
if ($data['post'] > $match)
{
if($this->_suppress_formr_validation_errors($data)) {
$this->errors[$data['name']] = $data['string'];
} else {
$this->_validation_message($data, 'must be less than, or equal to '.$match);
}
}
return $data['post'];
}
# less than (number)
elseif (mb_substr($rule, 0, 9) == 'less_than' || mb_substr($rule, 0, 2) == 'lt')
{
if (!is_numeric($data['post']))
{
if(!empty($data['label'])) {
$this->errors[$data['name']] = $data['label'] . ' must be a number';
} else {
$this->errors[$data['name']] = $data['name'] . ' must be a number';
}
return $data['post'];
}
if(! $match = $this->_get_matches($rule)) {
return $data['post'];
}
if ($data['post'] >= $match)
{
if($this->_suppress_formr_validation_errors($data)) {
$this->errors[$data['name']] = $data['string'];
} else {
$this->_validation_message($data, 'must be less than '.$match);
}
}
return $data['post'];
}
# greater than or equal to (number)
elseif (mb_substr($rule, 0, 21) == 'greater_than_or_equal' || mb_substr($rule, 0, 3) == 'gte')
{
if (!is_numeric($data['post']))
{
if(!empty($data['label'])) {
$this->errors[$data['name']] = $data['label'] . ' must be a number';
} else {
$this->errors[$data['name']] = $data['name'] . ' must be a number';
}
return $data['post'];
}
$match = $this->_get_matches($rule);
if ($data['post'] < $match)
{
if($this->_suppress_formr_validation_errors($data)) {
$this->errors[$data['name']] = $data['string'];
} else {
$this->_validation_message($data, 'must be greater than, or equal to '.$match);
}
}
return $data['post'];
}
# greater than (number)
elseif (mb_substr($rule, 0, 12) == 'greater_than' || mb_substr($rule, 0, 2) == 'gt')
{
if (!is_numeric($data['post']))
{
if(!empty($data['label'])) {
$this->errors[$data['name']] = $data['label'] . ' must be a number';
} else {
$this->errors[$data['name']] = $data['name'] . ' must be a number';
}
return $data['post'];
}
if(! $match = $this->_get_matches($rule)) {
return $data['post'];
}
if ($data['post'] <= $match)
{
if($this->_suppress_formr_validation_errors($data)) {
$this->errors[$data['name']] = $data['string'];
} else {
$this->_validation_message($data, 'must be greater than '.$match);
}
}
return $data['post'];
}
# alpha
elseif ($rule == 'alpha' && !ctype_alpha(str_replace(' ', '', $data['post'])))
{
if($this->_suppress_formr_validation_errors($data)) {
$this->errors[$data['name']] = $data['string'];
} else {
$this->_validation_message($data, 'may only contain letters');
}
return $data['post'];
}
# before (the current date)
elseif ($rule == 'before' && strtotime($data['post']) > strtotime('now'))
{
if($this->_suppress_formr_validation_errors($data)) {
$this->errors[$data['name']] = $data['string'];
} else {
$this->_validation_message($data, 'must be before '.date($this->format_rule_dates, strtotime('now')));
}
return $data['post'];
}
# after (the current date)
elseif ($rule == 'after' && strtotime($data['post']) < strtotime('now'))
{
if($this->_suppress_formr_validation_errors($data)) {
$this->errors[$data['name']] = $data['string'];
} else {
$this->_validation_message($data, 'must be after '.date($this->format_rule_dates, strtotime('now')));
}
return $data['post'];
}
# alphanumeric
elseif ($rule == 'alpha_numeric' && !ctype_alnum(str_replace(' ', '', $data['post'])) || $rule == 'an' && !ctype_alnum(str_replace(' ', '', $data['post'])))
{
if($this->_suppress_formr_validation_errors($data)) {
$this->errors[$data['name']] = $data['string'];
} else {
$this->_validation_message($data, 'may only contain letters and numbers');
}
return $data['post'];
}
# alpha_dash
elseif ($rule == 'alpha_dash' && preg_match('/[^A-Za-z0-9_-]/', $data['post']) || $rule == 'ad' && preg_match('/[^A-Za-z0-9_-]/', $data['post']))
{
if($this->_suppress_formr_validation_errors($data)) {
$this->errors[$data['name']] = $data['string'];
} else {
$this->_validation_message($data, 'may only contain letters, numbers, hyphens and underscores');
}
return $data['post'];
}
# numeric
elseif ($rule == 'numeric' && !is_numeric($data['post']))
{
if($this->_suppress_formr_validation_errors($data)) {
$this->errors[$data['name']] = $data['string'];
} else {
$this->_validation_message($data, 'must be a number or a numeric string');
}
return $data['post'];
}
# integer
elseif (($rule == 'int' || $rule == 'integer') && !filter_var($data['post'], FILTER_VALIDATE_INT))
{
if($this->_suppress_formr_validation_errors($data)) {
$this->errors[$data['name']] = $data['string'];
} else {
$this->_validation_message($data, 'must be a number');
}
return $data['post'];
}
# valid email
elseif ($rule == 'valid_email' && !filter_var($data['post'], FILTER_VALIDATE_EMAIL) || $rule == 'email' && !filter_var($data['post'], FILTER_VALIDATE_EMAIL))
{
if($this->_suppress_formr_validation_errors($data)) {
$this->errors[$data['name']] = $data['string'];
} else {
$this->_validation_message($data, 'must be an email address');
}
return $data['post'];
}
# valid IP
elseif ($rule == 'valid_ip' && !filter_var($data['post'], FILTER_VALIDATE_IP) || $rule == 'ip' && !filter_var($data['post'], FILTER_VALIDATE_IP))
{
if($this->_suppress_formr_validation_errors($data)) {
$this->errors[$data['name']] = $data['string'];
} else {
$this->_validation_message($data, 'must be a properly formatted IP address');
}
return $data['post'];
}
# valid URL
elseif ($rule == 'valid_url' && !filter_var($data['post'], FILTER_VALIDATE_URL) || $rule == 'url' && !filter_var($data['post'], FILTER_VALIDATE_URL))
{
if($this->_suppress_formr_validation_errors($data)) {
$this->errors[$data['name']] = $data['string'];
} else {
$this->_validation_message($data, 'must be a properly formatted URL');
}
return $data['post'];
}
# required
elseif ($rule == 'required' && !$this->is_not_empty($data['post']))
{
if($this->_suppress_formr_validation_errors($data)) {
$this->errors[$data['name']] = $data['string'];
} else {
$this->_validation_message($data, 'is required');
}
return $data['post'];
}
elseif($rule == 'allow_html' || $rule == 'html') {
return $data['post'];
} else {
return $data['post'];
}
}
protected function _validate_string_rules($rule, $string)
{
# the following rules manipulate the posted string
# sanitize string
if ($rule == 'sanitize_string') {
return strip_tags($string);
}
# sanitize URL
elseif ($rule == 'sanitize_url') {
return filter_var($string, FILTER_SANITIZE_URL);
}
# sanitize email
elseif ($rule == 'sanitize_email') {
return filter_var($string, FILTER_SANITIZE_EMAIL);
}
# sanitize integer
elseif ($rule == 'sanitize_int') {
return filter_var($string, FILTER_SANITIZE_NUMBER_INT);
}
# md5
elseif ($rule == 'md5') {
return md5($string . $this->salt);
}
# sha1
elseif ($rule == 'sha1') {
return sha1($string . $this->salt);
}
# php's password_hash() function
elseif ($rule == 'hash') {
return password_hash($string, PASSWORD_DEFAULT);
}
# strip everything but numbers
elseif ($rule == 'strip_numeric') {
return preg_replace("/[^0-9]/", '', $string);
}
# create twitter-style username
elseif ($rule == 'slug') {
return $this->slug($string);
}
else {
return $string;
}
}
protected function _fp_rules($key)
{
# used during fastpost()
# if a field name matches, why not do some automatic validation?
$rules = $this->fastpost_rules();
if (array_key_exists($key, $rules)) {
return $rules[$key];
} else {
return false;
}
}
protected function fastpost_rules()
{
# validation rules for the fastpost() method
# basically we're using common field names, and if a posted field name
# matches one of these field names (keys), the validation rule will be applied
# 'field name' => 'validation rule'
$rules = array(
'email' => 'valid_email',
'zip' => 'int|min_length[5]|max_length[10]',
'zip_code' => 'int|min_length[5]|max_length[10]',
'postal' => 'alphanumeric|min_length[6]|max_length[7]',
'postal_code' => 'alphanumeric|min_length[6]|max_length[7]',
'age' => 'int',
'weight' => 'int',
'url' => 'valid_url',
'website' => 'valid_url',
'ip_address' => 'valid_ip'
);
return $rules;
}
public function validate($string)
{
# even easier and more automatic way to process and validate your form fields
# break apart the comma delimited string of form labels
$parts = explode(',', $string);
$array = array();
foreach ($parts as $label)
{
$key = strtolower(str_replace(' ', '_', trim($label)));
$rules = null;
# we are adding validation rules to this field
if(preg_match( '!\(([^\)]+)\)!', $label, $match))
{
# get our field's validation rule(s)
$rules = $match[1];
# get the text before the double pipe for our new label
$explode = explode('(', $label, 2);
# set our new label text
$label = $explode[0];
# set our field's name
$key = strtolower(str_replace(' ', '_', trim($label)));
}
if(strpos($key, 'email') !== false) {
# this is an email address, so let's add the valid_email rule as well
$array[$key] = $this->post($key, ucwords($key), 'valid_email|' . $rules);
} else {
$array[$key] = $this->post($key, $label, $rules);
}
}
return $array;
}
# FORM
protected function _form($data)
{
# define the form action
if (!empty($data['action'])) {
# use action passed directly to function
$action = $data['action'];
} else {
if (isset($this->action)) {
# use defined action
$action = $this->action;
} else {
# use the current script
$action = $_SERVER['SCRIPT_NAME'];
}
}
# the form's method
if (empty($data['method'])) {
$data['method'] = 'post';
}
# open the form tag
$return = $this->_nl(1) . '<form action="' . $action . '"';
# add the name
if (!empty($data['name'])) {
$return .= ' name="' . $data['name'] . '"';
} elseif (isset($this->name)) {
$return .= ' name="' . $this->name . '"';
}
# add an ID
if(isset($this->id)) {
$return .= ' id="' . $this->id . '"';
} else {
if (empty($data['id']) && !empty($data['name'])) {
$return .= ' id="' . $data['name'] . '"';
} elseif (!empty($data['id'])) {
$return .= ' id="' . $data['id'] . '"';
} else {
$return .= ' id="formr"';
}
}
# add the method and character set
$return .= ' method="' . $data['method'] . '" accept-charset="' . $this->charset . '"';
# print any additional user-defined attributes
if (!empty($data['string'])) {
$return .= ' ' . $data['string'];
}
# add multipart if required
if ($data['form_type'] == 'multipart') {
$return .= ' enctype="multipart/form-data"';
}
# close the form tag
$return .= '>' . $this->_nl(1);
# add a hidden input with the form's ID so we can check if it's been submitted
if(isset($this->id)) {
$return .= '<input type="hidden" name="FormrID" value="'.$this->id.'">';
}
elseif(! empty($data['id'])) {
$return .= '<input type="hidden" name="FormrID" value="'.$data['id'].'">';
}
if($this->recaptcha_secret_key && $this->recaptcha_site_key) {
$return .= '<input type="hidden" name="formrToken" id="formrToken" value="formrToken">';
}
# print hidden input fields if present
if (!empty($data['hidden'])) {
foreach ($data['hidden'] as $key => $value) {
$return .= '<input type="hidden" name="'.$key.'" id="'.$key.'" value="'.$value.'">'.$this->_nl(1);
}
$return .= $this->_nl(1);
}
# add the honeypot
if($this->honeypot) {
$return .= '<input type="text" name="'.$this->honeypot.'" style="display:none">';
}
if($this->wrapper == 'ul' || $this->wrapper == 'ol' || $this->wrapper == 'dl') {
$return .= '<'.$this->wrapper.'>';
}
return $return;
}
public function form_open($name = '', $id = '', $action = '', $method = '', $string = '', $hidden = '')
{
if (!$method) {
if ($this->method == 'get') {
$method = 'get';
} else {
$method = 'post';
}
}
$data = array(
'form_type' => 'open',
'action' => $action,
'method' => $method,
'name' => $name,
'id' => $id,
'string' => $string,
'hidden' => $hidden
);
return $this->_echo($this->_form($data));
}
public function form_open_multipart($name = '', $id = '', $action = '', $method = '', $string = '', $hidden = '')
{
$data = array(
'form_type' => 'multipart',
'action' => $action,
'method'=> $method,
'name' => $name,
'id' => $id,
'string' => $string,
'hidden' => $hidden
);
return $this->_echo($this->_form($data));
}
public function form_close()
{
$return = null;
# put checkbox array values into hidden elements
# we'll match them inside the submit() method after the form has been submitted
if ($this->session && $this->session_values && !empty($this->checkbox_values)) {
foreach ($this->checkbox_values as $key => $value) {
$return .= $this->_nl(1) . $this->input_hidden($key . '_values', implode(',', $value));
}
}
if ($this->wrapper == 'ul' || $this->wrapper == 'ol' || $this->wrapper == 'dl') {
$return .= '</' . $this->wrapper . '>';
}
$return .= $this->_nl(1) . '</form>' . $this->_nl(1);
return $this->_echo($return);
}
public function open($name = '', $id = '', $action = '', $method = '', $string = '', $hidden = '')
{
# alias of form_open()
return $this->form_open($name, $id, $action, $method, $string, $hidden);
}
public function open_multipart($name = '', $id = '', $action = '', $method = '', $string = '', $hidden = '')
{
# alias of form_open_multipart()
return $this->form_open_multipart($name, $id, $action, $method, $string, $hidden);
}
public function close()
{
# alias of form_close()
return $this->form_close();
}
# BUTTONS
protected function _button($data)
{
# build the button tag
$return = '<button type="'.$data['type'].'"';
# insert the button's name
if (empty($data['name'])) {
$data['name'] = 'button';
}
$return .= ' name="' . $data['name'] . '"';
if (empty($data['id'])) {
$data['id'] = $data['name'];
}
$return .= ' id="' . $data['id'] . '"';
if (empty($data['value'])) {
$data['value'] = 'Submit';
}
# add user-entered string and additional attributes
// $return .= $this->_attributes($data);
# 'fix' the classes attribute
$return .= $this->_fix_classes($return, $data);
# insert the value and close the <button>
$return .= '>' . $data['value'] . '</button>';
$element = null;
if (empty($data['fastform'])) {
return $this->_wrapper($return, $data);
} else {
# we're using fastform(), which will run the element through wrapper()
return $return;
}
}
public function input_submit($data = '', $label = '', $value = '', $id = '', $string = '')
{
if (!is_array($data)) {
if (!$data) {
$data = 'submit';
}
if (!$value) {
if ($this->submit) {
$value = $this->submit;
} else {
$value = 'Submit';
}
}
$data = array(
'type' => 'submit',
'name' => $data,
'label' => $label,
'value' => $value,
'id' => $id,
'string' => $string
);
} else {
$data['type'] = 'submit';
}
if ($this->_wrapper_is('framework') && !$string) {
$data['string'] = 'class="' . $this->controls['button-primary'] . '"';
}
return $this->_echo($this->_create_input($data));
}
public function input_reset($data = '', $label = '', $value = '', $id = '', $string = '')
{
if (!is_array($data)) {
$data = array(
'type' => 'reset',
'name' => $data,
'label' => $label,
'value' => $value,
'id' => $id,
'string' => $string
);
} else {
$data['type'] = 'reset';
}
return $this->_echo($this->_create_input($data));
}
public function input_button($data = '', $label = '', $value = '', $id = '', $string = '')
{
if (!is_array($data)) {
$data = array(
'type' => 'button',
'name' => $data,
'label' => $label,
'value' => $value,
'id' => $id,
'string' => $string
);
} else {
$data['type'] = 'button';
}
return $this->_echo($this->_button($data));
}
public function input_button_submit($data = '', $label = '', $value = '', $id = '', $string = '')
{
if (!is_array($data)) {
$data = array(
'type' => 'submit',
'name' => $data,
'label' => $label,
'value' => $value,
'id' => $id,
'string' => $string
);
} else {
$data['type'] = 'submit';
}
if ($this->_wrapper_is('framework') && !$string) {
$data['string'] = 'class="' . $this->controls['button-primary'] . '"';
}
return $this->_echo($this->_button($data));
}
public function submit_button($value = 'Submit')
{
$data = array(
'type' => 'submit',
'name' => 'submit',
'label' => null,
'value' => $value,
'id' => 'submit',
'string' => 'class="button"'
);
if ($this->_wrapper_is('framework')) {
$data['string'] = 'class="' . $this->controls['button-primary'] . '"';
}
return $this->_echo($this->_button($data));
}
public function reset_button($value = 'Reset')
{
$data = array(
'type' => 'reset',
'name' => 'reset',
'label' => null,
'value' => $value,
'id' => 'reset',
'string' => 'class="button"'
);
if ($this->_wrapper_is('framework')) {
$data['string'] = 'class="' . $this->controls['button-danger'] . '"';
}
return $this->_echo($this->_button($data));
}
# INPUTS
protected function _create_input($data)
{
# show an error if the field name hasn't been supplied
if (!$this->is_not_empty($data['name'])) {
$this->_error_message('You must provide a name for the <strong>' . $data['type'] . '</strong> element.');
return false;
}
# open the element
$return = '<input';
# populate the field's value (on page load) with the session value
if (!in_array($data['type'], $this->_input_types('checkbox'))) {
if ($data['value'] == '' && $this->session_values && $this->session && !empty($_SESSION[$this->session][$data['name']])) {
$data['value'] = $_SESSION[$this->session][$data['name']];
}
}
# if there are form errors, let's insert the posted value into
# the array so the user doesn't have to enter the value again.
# also, don't store passwords; always make the user re-type the password.
if (!in_array($data['type'], $this->_input_types('checkbox'))) {
# an ID wasn't specified, let's create one using the name
$data['id'] = $this->make_id($data);
# assign the value
if (isset($_POST[$data['name']]) && !empty($_POST[$data['name']]) && $data['type'] != 'password') {
if ($this->session_values && $this->session) {
if($data['type'] != 'submit' && $data['type'] != 'button') {
if(empty($data['value'])) {
$this->_error_message('Please define $'.$data['name'].' = $form->post(\''.$data['name'].'\')');
} else {
$data['value'] = $_SESSION[$this->session][$data['name']];
}
}
} else {
$data['value'] = $this->_clean_value($_POST[$data['name']], 'allow_html');
}
}
# if we're dealing with an input array: such as <input type="text" name="name[key]">
# we can print the array's value in a text field, but only with an array key
# and the array key must match the field's ID - hey, we need *something* to match it with! :P
if (!empty($_POST) && $data['type'] != 'file' && $data['type'] != 'submit' && $data['type'] != 'reset') {
# tells us we're dealing with an array because of the trailing bracket ]
if (substr(rtrim($data['name']), -1) == ']') {
# get the array key from between the brackets []
preg_match_all('^\[(.*?)\]^', $data['name'], $matches);
foreach ($matches[1] as $key) {
# strip out the brackets and array key to reveal the field name
$string = '[' . $key . ']';
$name = str_replace($string, '', $data['name']);
# if the POST array key matches the field's id, print the value
if ($key == $data['id']) {
$data['value'] = $_POST[$name][$key];
}
}
}
}
} else {
# checkboxes and radios..
if($this->session && $this->session_values) {
# let's see if our checkboxes are an array
if(strstr($data['name'], '[]')) {
# put the values into an array, then we'll put them into a hidden element inside the form_close() method
# we do this so we can match the form values against what was actually posted (or not posted)
if(!in_array($data['value'], $this->checkbox_values)) {
$this->checkbox_values[trim($data['name'], '[]')][] = $data['value'];
}
}
}
# an ID wasn't specified, let's create one using the value
if (empty($data['id'])) {
$data['id'] = $data['value'];
}
# print an error message alerting the user this field needs a value
if (!$this->is_not_empty($data['value'])) {
$this->_error_message('Please enter a value for the ' . $data['type'] . ': <strong>' . $data['name'] . '</strong>');
}
# check the element on initial form load
if (! $this->submitted())
{
if(!isset($_POST[$this->_strip_brackets($data['name'])]))
{
# tick the checkbox/radio if value is in the session
if ($this->session_values && $this->session && !empty($_SESSION[$this->session])) {
if (strstr($data['name'], '[]')) {
# we are in a checkbox array
if(isset($_SESSION[$this->session][$this->_strip_brackets($data['name'])])) {
foreach ($_SESSION[$this->session][$this->_strip_brackets($data['name'])] as $key => $value) {
if ($data['value'] == $value) {
$return .= ' checked';
}
}
}
} else {
foreach($_SESSION[$this->session] as $key => $value) {
if ($data['name'] == $key && $data['value'] == $value) {
$return .= ' checked';
}
}
}
} else {
# tick the checkbox/radio if value is selected
if (!empty($data['selected'])) {
if ($data['selected'] == $data['value'] || ($data['selected'] == 'checked' || $data['selected'] == 'selected')) {
$return .= ' checked';
}
}
}
}
# check the session for checkbox groups/arrays
if(!empty($_SESSION[$this->session])) {
foreach ($_SESSION[$this->session] as $value) {
if($data['value'] == $value) {
$return .= ' checked';
}
}
}
} else {
# check the element after the form has been posted
if (isset($_POST[$this->_strip_brackets($data['name'])]) && $_POST[$this->_strip_brackets($data['name'])] == $data['value']) {
$return .= ' checked';
}
# checkbox group / checkbox array
if (!empty($_POST[$this->_strip_brackets($data['name'])]) && is_array($_POST[$this->_strip_brackets($data['name'])])) {
foreach ($_POST[$this->_strip_brackets($data['name'])] as $pvalue) {
if ($pvalue == $data['value']) {
$return .= ' checked';
}
}
}
}
}
# loop through the array and print each attribute
foreach ($data as $key => $value) {
if (!in_array($key, $this->no_keys)) {
if($key != 'checkbox-inline') {
if ($value != '') {
$return .= ' ' . $key . '="' . $value . '"';
}
}
}
}
# last resort: an ID wasn't provided; use the name field as the ID
# do not auto-generate an ID if the field is an array
if (!$this->is_not_empty($data['id'])) {
if (substr(rtrim($data['name']), -1) != ']') {
$return .= ' id="' . trim($data['name'],'[]') . '"';
}
}
if (!empty($data['multiple'])) {
$return .= ' multiple';
}
# add user-entered string and additional attributes
// $return .= $this->_attributes($data);
# 'fix' the classes attribute
$return .= $this->_fix_classes($return, $data);
# if required
if ($this->_check_required($data['name']) && $data['type'] != 'submit' && $data['type'] != 'reset') {
$return .= ' required';
}
# insert the closing bracket
$return .= ' />';
# if using inline validation
$return .= $this->_inline($data['name']);
$return = str_replace(' ', ' ', $return);
if (empty($data['fastform'])) {
# the element is completely built, now all we need to do is wrap it
return $this->_wrapper($return, $data);
} else {
# we're using fastform(), which will run the element through wrapper()
return $return;
}
}
public function input_text($data, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
if (!is_array($data)) {
$data = array(
'type' => 'text',
'name' => $data,
'id' => $id,
'value' => $value,
'string' => $string,
'label' => $label,
'inline' => $inline
);
} else {
$data['type'] = 'text';
}
return $this->_create_input($data);
}
public function input_hidden($data, $value = '')
{
$return = '';
if (is_array($data)) {
# build the elements
foreach($data as $key => $value) {
$return .= '<input type="hidden" name="' . $key . '" id="' . $key . '" value="' . $value . '">'.$this->_nl();
}
} else {
# build the element
$return = '<input type="hidden" name="' . $data . '" id="' . $data . '" value="' . $value . '">'.$this->_nl();
}
return $this->_echo($return);
}
public function input_upload($data, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
if (!is_array($data)) {
$data = array(
'type' => 'file',
'name' => $data,
'id' => $id,
'value' => $value,
'string' => $string,
'label' => $label,
'inline' => $inline
);
} else {
$data['type'] = 'file';
}
return $this->_create_input($data);
}
public function input_file($data, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
if (!is_array($data)) {
$data = array(
'type' => 'file',
'name' => $data,
'id' => $id,
'value' => $value,
'string' => $string,
'label' => $label,
'inline' => $inline
);
} else {
$data['type'] = 'file';
}
return $this->_create_input($data);
}
public function input_upload_multiple($data, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
if (!is_array($data)) {
$data = array(
'type' => 'file',
'multiple' => true,
'name' => $data,
'id' => $id,
'value' => $value,
'string' => $string,
'label' => $label,
'inline' => $inline
);
} else {
$data['type'] = 'file';
$data['multiple'] = true;
}
return $this->_create_input($data);
}
public function input_password($data, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
if (!is_array($data)) {
$data = array(
'type' => 'password',
'name' => $data,
'id' => $id,
'value' => $value,
'string' => $string,
'label' => $label,
'inline' => $inline
);
} else {
$data['type'] = 'password';
}
return $this->_create_input($data);
}
public function input_radio($data, $label = '', $value = '', $id = '', $string = '', $inline = '', $selected = '')
{
if (!is_array($data)) {
$data = array(
'type' => 'radio',
'name' => $data,
'id' => $id,
'value' => $value,
'string' => $string,
'selected' => $selected,
'label' => $label,
'inline' => $inline
);
} else {
$data['type'] = 'radio';
}
return $this->_create_input($data);
}
public function input_radio_inline($data, $label = '', $value = '', $id = '', $string = '', $inline = '', $selected = '')
{
if (!is_array($data)) {
$data = array(
'type' => 'radio',
'name' => $data,
'id' => $id,
'value' => $value,
'string' => $string,
'selected' => $selected,
'label' => $label,
'inline' => $inline,
'checkbox-inline' => 'inline'
);
} else {
$data['type'] = 'radio';
$data['checkbox-inline'] = 'inline';
}
return $this->_create_input($data);
}
public function input_checkbox($data, $label = '', $value = '', $id = '', $string = '', $inline = '', $selected = '')
{
if (!is_array($data)) {
$data = array(
'type' => 'checkbox',
'name' => $data,
'id' => $id,
'value' => $value,
'string' => $string,
'selected' => $selected,
'label' => $label,
'inline' => $inline
);
} else {
$data['type'] = 'checkbox';
}
return $this->_create_input($data);
}
public function input_checkbox_inline($data, $label = '', $value = '', $id = '', $string = '', $inline = '', $selected = '')
{
if (!is_array($data)) {
$data = array(
'type' => 'checkbox',
'name' => $data,
'id' => $id,
'value' => $value,
'string' => $string,
'selected' => $selected,
'label' => $label,
'inline' => $inline,
'checkbox-inline' => 'inline'
);
} else {
$data['type'] = 'checkbox';
$data['checkbox-inline'] = 'inline';
}
return $this->_create_input($data);
}
public function input_image($data, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
if (!is_array($data)) {
$data = array(
'type' => 'image',
'name' => $data,
'label' => $label,
'value' => $value,
'id' => $id,
'string' => $string,
'inline' => $inline
);
} else {
$data['type'] = 'image';
}
return $this->_create_input($data);
}
# ADDITIONAL FIELD ELEMENTS
public function input_color($data, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
if (!is_array($data)) {
$data = array(
'type' => 'color',
'name' => $data,
'label' => $label,
'value' => $value,
'id' => $id,
'string' => $string,
'inline' => $inline
);
} else {
$data['type'] = 'color';
}
return $this->_create_input($data);
}
public function input_email($data, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
if (!is_array($data)) {
$data = array(
'type' => 'email',
'name' => $data,
'label' => $label,
'value' => $value,
'id' => $id,
'string' => $string,
'inline' => $inline
);
} else {
$data['type'] = 'email';
}
return $this->_create_input($data);
}
public function input_date($data, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
if (!is_array($data)) {
$data = array(
'type' => 'date',
'name' => $data,
'label' => $label,
'value' => $value,
'id' => $id,
'string' => $string,
'inline' => $inline
);
} else {
$data['type'] = 'date';
}
return $this->_create_input($data);
}
public function input_datetime($data, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
if (!is_array($data)) {
$data = array(
'type' => 'datetime',
'name' => $data,
'label' => $label,
'value' => $value,
'id' => $id,
'string' => $string,
'inline' => $inline
);
} else {
$data['type'] = 'datetime-local';
}
return $this->_create_input($data);
}
public function input_datetime_local($data, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
if (!is_array($data)) {
$data = array(
'type' => 'datetime-local',
'name' => $data,
'label' => $label,
'value' => $value,
'id' => $id,
'string' => $string,
'inline' => $inline
);
} else {
$data['type'] = 'datetime-local';
}
return $this->_create_input($data);
}
public function input_month($data, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
if (!is_array($data)) {
$data = array(
'type' => 'month',
'name' => $data,
'label' => $label,
'value' => $value,
'id' => $id,
'string' => $string,
'inline' => $inline
);
} else {
$data['type'] = 'month';
}
return $this->_create_input($data);
}
public function input_number($data, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
if (!is_array($data)) {
$data = array(
'type' => 'number',
'name' => $data,
'label' => $label,
'value' => $value,
'id' => $id,
'string' => $string,
'inline' => $inline
);
} else {
$data['type'] = 'number';
}
return $this->_create_input($data);
}
public function input_range($data, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
if (!is_array($data)) {
$data = array(
'type' => 'range',
'name' => $data,
'label' => $label,
'value' => $value,
'id' => $id,
'string' => $string,
'inline' => $inline
);
} else {
$data['type'] = 'range';
}
return $this->_create_input($data);
}
public function input_search($data, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
if (!is_array($data)) {
$data = array(
'type' => 'search',
'name' => $data,
'label' => $label,
'value' => $value,
'id' => $id,
'string' => $string,
'inline' => $inline
);
} else {
$data['type'] = 'search';
}
return $this->_create_input($data);
}
public function input_tel($data, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
if (!is_array($data)) {
$data = array(
'type' => 'tel',
'name' => $data,
'label' => $label,
'value' => $value,
'id' => $id,
'string' => $string,
'inline' => $inline
);
} else {
$data['type'] = 'tel';
}
return $this->_create_input($data);
}
public function input_time($data, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
if (!is_array($data)) {
$data = array(
'type' => 'time',
'name' => $data,
'label' => $label,
'value' => $value,
'id' => $id,
'string' => $string,
'inline' => $inline
);
} else {
$data['type'] = 'time';
}
return $this->_create_input($data);
}
public function input_url($data, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
if (!is_array($data)) {
$data = array(
'type' => 'url',
'name' => $data,
'label' => $label,
'value' => $value,
'id' => $id,
'string' => $string,
'inline' => $inline
);
} else {
$data['type'] = 'url';
}
return $this->_create_input($data);
}
public function input_week($data, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
if (!is_array($data)) {
$data = array(
'type' => 'week',
'name' => $data,
'label' => $label,
'value' => $value,
'id' => $id,
'string' => $string,
'inline' => $inline
);
} else {
$data['type'] = 'week';
}
return $this->_create_input($data);
}
public function input($data)
{
# create inputs directly from arrays
if(!array_key_exists('type', $data)) {
return $this->_error_message('You must assign a field type to the <code>'.$data['name'].'</code> array');
}
if ($data['type'] == 'select') {
return $this->input_select($data);
} elseif ($data['type'] == 'text') {
return $this->input_text($data);
} elseif ($data['type'] == 'password') {
return $this->input_password($data);
} elseif ($data['type'] == 'textarea') {
return $this->input_textarea($data);
} elseif ($data['type'] == 'file') {
return $this->input_upload($data);
} elseif ($data['type'] == 'color') {
return $this->input_color($data);
} elseif ($data['type'] == 'email') {
return $this->input_email($data);
} elseif ($data['type'] == 'date') {
return $this->input_date($data);
} elseif ($data['type'] == 'datetime') {
return $this->input_datetime($data);
} elseif ($data['type'] == 'datetime-local') {
return $this->input_datetime_local($data);
} elseif ($data['type'] == 'month') {
return $this->input_month($data);
} elseif ($data['type'] == 'number') {
return $this->input_number($data);
} elseif ($data['type'] == 'range') {
return $this->input_range($data);
} elseif ($data['type'] == 'search') {
return $this->input_search($data);
} elseif ($data['type'] == 'tel') {
return $this->input_tel($data);
} elseif ($data['type'] == 'time') {
return $this->input_time($data);
} elseif ($data['type'] == 'url') {
return $this->input_url($data);
} elseif ($data['type'] == 'week') {
return $this->input_week($data);
}
}
# TEXTAREA
protected function _create_textarea($data)
{
# show an error if the field name hasn't been supplied
if (!$this->is_not_empty($data['name'])) {
$this->_error_message('You must provide a name for the <strong>' . $data['type'] . '</strong> element.');
return false;
}
# if ID is empty, create an ID using the name
if (!$this->is_not_empty($data['id'])) {
$data['id'] = $data['name'];
}
# open the element
$return = '<textarea';
# populate the field's value (on page load) with the session value
if ($data['value'] == '' && $this->session_values && $this->session && !empty($_SESSION[$this->session][$data['name']])) {
$data['value'] = $_SESSION[$this->session][$data['name']];
}
# loop through the $data array and print each attribute
foreach ($data as $key => $value) {
if (!in_array($key, $this->no_keys) && $key != 'type' && $key != 'value') {
$return .= ' ' . $key . '="' . $value . '"';
}
}
# add user-entered string and additional attributes
// $return .= ' ' . $this->_attributes($data);
# 'fix' the classes attribute
$return .= $this->_fix_classes($return, $data);
# if required
if ($this->_check_required($data['name'], $data)) {
$return .= ' required';
}
# close the opening tag
$return .= '>';
# insert the posted value if available
if (isset($_POST[$data['name']]) && !empty($_POST[$data['name']])) {
$return .= $_POST[$data['name']];
} else {
# insert the default value if available
if ($this->is_not_empty($data['value'])) {
$return .= $data['value'];
}
}
# insert the closing tag
$return .= '</textarea>';
# if using inline validation
$return .= $this->_inline($data['name']);
$return = str_replace(' ', ' ', $return);
$element = null;
if (empty($data['fastform'])) {
return $this->_wrapper($return, $data);
} else {
# we're using fastform(), which will run the element through wrapper()
return $return;
}
}
public function input_textarea($data, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
if (!is_array($data)) {
$data = array(
'type' => 'textarea',
'name' => $data,
'label' => $label,
'value' => $value,
'id' => $id,
'string' => $string,
'inline' => $inline
);
} else {
$data['type'] = 'textarea';
}
return $this->_create_textarea($data);
}
# SELECT MENU
protected function _create_select($data)
{
# show an error if the field name hasn't been supplied
if (!$this->is_not_empty($data['name'])) {
$this->_error_message('You must provide a name for the <strong>' . $data['type'] . '</strong> element.');
return false;
}
# open the element
$return = '<select name="' . $data['name'] . '"';
# if an ID wasn't supplied, create one from the field name
if (!$this->is_not_empty($data['id'])) {
$data['id'] = $data['name'];
}
# if we're selecting multiple items
if (is_array($data['selected']) || isset($data['multiple'])) {
$return .= ' multiple';
}
# add ID
$return .= ' id="' . $data['id'] . '"';
# add user-entered string and additional attributes
// $return .= ' ' . $this->_attributes($data);
# 'fix' the classes attribute
$return .= $this->_fix_classes($return, $data);
# if required
if ($this->_check_required($data['name'], $data)) {
$return .= ' required';
}
# close the opening tag
$return .= '>' . $this->_nl(1);
# a string was entered, so we'll grab the appropriate function from the Dropdowns class
if (!empty($data['options']) && is_string($data['options'])) {
if(isset($data['myarray'])) {
# we're passing an array in the 9th parameter of the input_select() method
$data['options'] = $this->_dropdowns($data['options'], $data['myarray']);
} else {
$data['options'] = $this->_dropdowns($data['options']);
}
}
# if a default selected="selected" value is defined, use that one and give it an empty value
# if one is set in an array, insert that one as we loop through it later on
if (!is_array($data['selected']) && !array_key_exists($data['selected'], $data['options']) && !empty($data['selected'])) {
$return .= $this->_t(1) . '<option value="">' . $data['selected'] . '</option>';
}
# options are user-defined
# loop through the options array
foreach ($data['options'] as $key => $value) {
# if $value is an array, create an optgroup
if (is_array($value)) {
$return .= $this->_t(1) . '<optgroup label="' . $key . '">';
# loop through the array
foreach ($value as $value => $label) {
# if the form has been posted, print selected option
if (isset($_POST[$data['name']]) && $_POST[$data['name']] == $value) {
$return .= $this->_t(2) . '<option value="' . $value . '" selected="selected">' . $label . '</option>';
}
# print selected option(s) on form load
elseif ($data['selected'] == $value || (is_array($data['selected']) && in_array($value, $data['selected']))) {
$return .= $this->_t(2) . '<option value="' . $value . '" selected="selected">' . $label . '</option>';
}
# print remaining options
else {
$return .= $this->_t(2) . '<option value="' . $value . '">' . $label . '</option>';
}
}
$return .= $this->_t(1) . '</optgroup>';
} else {
# if the form has been posted, print selected option(s)
# check if the select is an array (key has brackets, e.g; <select name="foo[]">)
if (isset($_POST[trim($data['name'],'[]')]) && is_array($_POST[trim($data['name'],'[]')]) && in_array($key, $_POST[trim($data['name'],'[]')])) {
$return .= $this->_t(2) . '<option value="' . $key . '" selected>' . $value . '</option>' . $this->_nl(1);
}
elseif (isset($_POST[$data['name']]) && $_POST[$data['name']] == $key) {
$return .= $this->_t(2) . '<option value="' . $key . '" selected>' . $value . '</option>' . $this->_nl(1);
}
# print selected option on form load
elseif (!isset($_POST[$data['name']]) && $data['selected'] == $key || (is_array($data['selected']) && in_array($key, $data['selected']))) {
# populate the field's value (on page load) with the session value
if ($this->session_values && $this->session && !empty($_SESSION[$this->session][$data['name']])) {
if ($_SESSION[$this->session][$data['name']] == $key) {
$return .= $this->_t(2) . '<option value="' . $key . '" selected>' . $value . '</option>' . $this->_nl(1);
}
} else {
$return .= $this->_t(2) . '<option value="' . $key . '" selected>' . $value . '</option>' . $this->_nl(1);
}
}
# print remaining options
else {
# user has entered a value in the 'values' argument
if (!isset($_POST[$data['name']]) && $data['value'] === $key) {
$return .= $this->_t(2) . '<option value="' . $key . '" selected>' . $value . '</option>' . $this->_nl(1);
} else {
$return .= $this->_t(2) . '<option value="' . $key . '">' . $value . '</option>' . $this->_nl(1);
}
}
}
}
# close the element
$return .= $this->_t(1) . '</select>';
# if using inline validation
$return .= $this->_inline($data['name']);
$return = str_replace(' ', ' ', $return);
$element = null;
if (empty($data['fastform'])) {
if (!$this->wrapper) {
if (!empty($data['label'])) {
# output the element and label without a wrapper
if ($this->comments) {
$element .= $this->_nl(1) . '<!-- ' . $data['name'] . ' -->' . $this->_nl(1);
}
$element .= $this->label($data) . $this->_nl(1);
$element .= $return . $this->_nl(1);
return $element;
} else {
# just return the element
if ($this->comments) {
$element .= $this->_nl(1) . '<!-- ' . $data['name'] . ' -->' . $this->_nl(1);
}
$element .= $return . $this->_nl(1);
return $this->_wrapper($element, $data);
}
} else {
# wrap the element
$element .= $return;
return $this->_wrapper($element, $data);
}
} else {
# we're using fastform(), which will run the element through wrapper()
return $return;
}
}
protected function _dropdowns($menu, $data = null)
{
# this function enables the Dropdowns class to be used as a plugin
# all we're doing is returning the selected array from the Dropdowns class
# if needed, strip underscore from the beginning
$menu = ltrim($menu, '_');
# load the appropriate function from the Dropdowns class...
# we're passing an array in the 9th parameter of the input_select() method for the MyDropdowns class
if (file_exists(dirname(__FILE__) . '/my_classes/my.dropdowns.php')) {
if ($data) {
return \MyDropdowns::$menu($data);
}
return \MyDropdowns::$menu();
} else {
if ($data) {
return \Dropdowns::$menu($data);
}
return \Dropdowns::$menu();
}
}
public function input_select($data, $label = '', $value = '', $id = '', $string = '', $inline = '', $selected = '', $options = '', $myarray = null)
{
if (!is_array($data)) {
$data = array(
'type' => 'select',
'name' => $data,
'label' => $label,
'value' => $value,
'id' => $id,
'string' => $string,
'inline' => $inline,
'selected' => $selected,
'options' => $options,
'myarray' => $myarray
);
} else {
$data['type'] = 'select';
}
return $this->_create_select($data);
}
public function input_select_multiple($data, $label = '', $value = '', $id = '', $string = '', $inline = '', $selected = '', $options = '', $myarray = null)
{
if (!is_array($data)) {
$data = array(
'type' => 'select',
'name' => $data,
'label' => $label,
'value' => $value,
'id' => $id,
'string' => $string,
'inline' => $inline,
'selected' => $selected,
'options' => $options,
'myarray' => $myarray
);
} else {
$data['type'] = 'select';
}
$data['multiple'] = 'multiple';
return $this->_create_select($data);
}
# INPUT ALIASES, FOR EVEN FASTER FORM BUILDING
public function text($name, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
return $this->input_text($name, $label, $value, $id, $string, $inline);
}
public function hidden($name, $value = '')
{
return $this->input_hidden($name, $value);
}
public function file($name, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
return $this->input_file($name, $label, $value, $id, $string, $inline);
}
public function file_multiple($name, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
return $this->input_upload_multiple($name, $label, $value, $id, $string, $inline);
}
public function upload($name, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
return $this->input_upload($name, $label, $value, $id, $string, $inline);
}
public function upload_multiple($name, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
return $this->input_upload_multiple($name, $label, $value, $id, $string, $inline);
}
public function password($name, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
return $this->input_password($name, $label, $value, $id, $string, $inline);
}
public function radio($name, $label = '', $value = '', $id = '', $string = '', $inline = '', $selected = '')
{
return $this->input_radio($name, $label, $value, $id, $string, $inline, $selected);
}
public function radio_inline($name, $label = '', $value = '', $id = '', $string = '', $inline = '', $selected = '')
{
return $this->input_radio_inline($name, $label, $value, $id, $string, $inline, $selected);
}
public function checkbox($name, $label = '', $value = '', $id = '', $string = '', $inline = '', $selected = '')
{
return $this->input_checkbox($name, $label, $value, $id, $string, $inline, $selected);
}
public function checkbox_inline($name, $label = '', $value = '', $id = '', $string = '', $inline = '', $selected = '')
{
return $this->input_checkbox_inline($name, $label, $value, $id, $string, $inline, $selected);
}
public function email($name, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
return $this->input_email($name, $label, $value, $id, $string, $inline);
}
public function textarea($name, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
return $this->input_textarea($name, $label, $value, $id, $string, $inline);
}
public function select($name, $label = '', $value = '', $id = '', $string = '', $inline = '', $selected = '', $options = '', $myarray = null)
{
return $this->input_select($name, $label, $value, $id, $string, $inline, $selected, $options, $myarray);
}
public function select_multiple($name, $label = '', $value = '', $id = '', $string = '', $inline = '', $selected = '', $options = '', $myarray = null)
{
return $this->input_select_multiple($name, $label, $value, $id, $string, $inline, $selected, $options, $myarray);
}
public function dropdown($name, $label = '', $value = '', $id = '', $string = '', $inline = '', $selected = '', $options = '', $myarray = null)
{
return $this->input_select($name, $label, $value, $id, $string, $inline, $selected, $options, $myarray);
}
public function dropdown_multiple($name, $label = '', $value = '', $id = '', $string = '', $inline = '', $selected = '', $options = '', $myarray = null)
{
return $this->input_select_multiple($name, $label, $value, $id, $string, $inline, $selected, $options, $myarray);
}
public function color($name, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
return $this->input_color($name, $label, $value, $id, $string, $inline);
}
public function date($name, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
return $this->input_date($name, $label, $value, $id, $string, $inline);
}
public function datetime($name, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
return $this->input_datetime_local($name, $label, $value, $id, $string, $inline);
}
public function datetime_local($name, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
return $this->input_datetime_local($name, $label, $value, $id, $string, $inline);
}
public function month($name, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
return $this->input_month($name, $label, $value, $id, $string, $inline);
}
public function number($name, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
return $this->input_number($name, $label, $value, $id, $string, $inline);
}
public function range($name, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
return $this->input_range($name, $label, $value, $id, $string, $inline);
}
public function search($name, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
return $this->input_search($name, $label, $value, $id, $string, $inline);
}
public function tel($name, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
return $this->input_tel($name, $label, $value, $id, $string, $inline);
}
public function time($name, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
return $this->input_time($name, $label, $value, $id, $string, $inline);
}
public function url($name, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
return $this->input_url($name, $label, $value, $id, $string, $inline);
}
public function week($name, $label = '', $value = '', $id = '', $string = '', $inline = '')
{
return $this->input_week($name, $label, $value, $id, $string, $inline);
}
public function button($name = '', $label = '', $value = '', $id = '', $string = '')
{
return $this->input_button($name, $label, $value, $id, $string);
}
# FIELDSET
public function fieldset_open($legend = '', $string = '')
{
$return = '<fieldset';
if ($string) {
$return .= ' ' . $string;
}
$return .= '>' . $this->_nl(1);
if ($legend) {
$return .= '<legend>' . $legend . '</legend>';
}
return $this->_echo($return . $this->_nl(1));
}
public function fieldset_close($string = '')
{
$return = '</fieldset>';
if ($string) {
$return .= $string;
}
return $this->_echo($return . $this->_nl(1));
}
# LABELS
protected function _create_label($data)
{
$return = null;
# if there's a post error, create an <a> anchor for this field
if ($this->errors() && $this->link_errors) {
$return = '<a name="' . $data['name'] . '"></a>';
}
# create an ID if one wasn't supplied
$data['id'] = $this->make_id($data);
# open the element
$return .= '<label for="' . $data['id'] . '"';
# add an bootstrap error class if required
if ($this->in_errors($data['name']) && $this->_wrapper_is('bootstrap')) {
$return .= ' class="' . $this->controls['text-error'] . '"';
}
# insert the string data if available
if (!empty($data['string']) && !in_array($data['type'], $this->_input_types('button'))) {
$return .= ' ' . $data['string'];
}
# close the tag
$return .= '>';
# add the label text, etc. if not using the label_open() method
if ($data['label_type'] != 'open' && $data['type']) {
# don't include label text or indicators if this is a button
if (!in_array($data['type'], $this->_input_types('button'))) {
# add the label text
if ($this->is_not_empty($data['label'])) {
$return .= $data['label'];
}
# if required, let the user know by adding an asterisk, etc.
if ($this->_check_required($data['name']) && !empty($data['label'])) {
$return .= $this->required_indicator;
}
}
# close the element
$return .= '</label> ';
}
return $this->_echo($return);
}
public function label($data, $label = '', $id = '', $string = '')
{
if (!is_array($data)) {
$data = array(
'type' => 'label',
'name' => $data,
'label' => $label,
'id' => $id,
'string' => $string,
'label_type' => 'label'
);
} else {
$data['type'] = 'label';
$data['label_type'] = 'label';
}
return $this->_create_label($data);
}
public function label_open($data, $label = '', $id = '', $string = '')
{
# opens a <label> tag
if (!is_array($data)) {
$data = array(
'name' => $data,
'label' => $label,
'id' => $id,
'string' => $string,
'label_type' => 'open'
);
} else {
$data['label_type'] = 'open';
}
return $this->_create_label($data);
}
public function label_close($data = '')
{
# closes a <label> tag
# this is handy if we want to put our label text *after* the form element
$return = null;
if (!is_array($data)) {
if ($data) {
$return .= $data;
}
} else {
if ($this->_check_required($data['name']) && $data['type'] != 'radio' && !in_array($data['type'], $this->_input_types('button'))) {
# we don't want the indicator next to radios and checkboxes if they're in an group/array
if (empty($data['group'])) {
$return .= $this->required_indicator;
}
}
$return .= $data['label'];
}
$return .= $this->_nl(1) . '</label>';
return $this->_echo($return);
}
# SIMPLE FORM CREATION
public function create($string, $form = false)
{
# SIMPLE FORM CREATION
# create and wrap inputs using labels as our keys
# set our $return var for later
$return = null;
if($form) {
if(!$this->id) {
$this->id = 'myFormr';
}
if($form === 'multipart') {
$return .= $this->form_open_multipart();
} else {
$return .= $this->form_open();
}
}
# break apart the comma delimited string of form labels
$parts = explode(',', $string);
# loop through each part and set the $data array values
foreach ($parts as $label) {
$data = [
'type' => 'text',
'name' => strtolower(str_replace(' ', '_', trim($label))),
'id' => strtolower(str_replace(' ', '_', trim($label))),
'value' => null,
'string' => null,
'label' => trim($label),
'inline' => null
];
$return .= $this->_open_list_wrapper();
# label string contains the word 'email', use email input type
if(strpos(strtolower($label), 'email') !== false && strpos(strtolower($label), '|email') === false) {
$return .= $this->input_email($data);
}
elseif(strpos(strtolower($label), '|') !== false) {
# we want to use an specific input type
$type = substr($label, strpos($label, '|') + 1);
# correct our label text by removing the | and input type
$data['label'] = str_replace('|'.$type, '', $label);
# correct our input's name
$data['name'] = strtolower(str_replace(' ', '_', trim($data['label'])));
# correct our input's ID
$data['id'] = strtolower(str_replace(' ', '_', trim($data['label'])));
# define the method's name
$name = 'input_'.$type;
# add a default value for checkbox or radio
if($type == 'checkbox' || $type == 'radio') {
$data['value'] = $data['name'];
}
# we want to create a multiple file upload element
if($type == 'file[]') {
$data['name'] = $data['name'].'[]';
$return .= $this->input_upload_multiple($data);
} else {
# return the input
$return .= $this->$name($data);
}
}
else {
# default to text type
$return .= $this->input_text($data);
}
$return .= $this->_close_list_wrapper();
}
if($form) {
$return .= $this->input_button_submit();
$return .= $this->form_close();
}
return $return;
}
public function create_form($string)
{
# alias of create(), except opens and closes form tag, plus adds submit button
return $this->create($string, true);
}
public function create_form_multipart($string)
{
# alias of create_form(), except adds enctype="multipart/form-data"
return $this->create($string, 'multipart');
}
# FAST FORM
public function fastform($input, $csrf = false, $multipart = false)
{
# method for automatically building and laying out a form with multiple elements
if (is_string($input)) {
# user entered a string and wants to use a pre-built form in the Forms class
return $this->_faster_form($input, $csrf, $multipart);
}
# build the <form> tag
if ($multipart) {
$return = $this->form_open_multipart();
} else {
$return = $this->form_open();
}
if ($csrf) {
if (is_integer($csrf)) {
$timeout = (int)$csrf;
$return .= $this->csrf($timeout);
} else {
$return .= $this->csrf();
}
}
# lets see if we need to wrap this in a list...
$return .= $this->_open_list_wrapper();
# create an empty array outside of looping to store hidden inputs
$hidden = array();
# loop through the array and print/process each field value
foreach ($input as $key => $value)
{
# check if we're creating a fieldset
if(strstr($key, 'fieldset') !== false)
{
# open the fieldset and add the legend text
$return .= $this->fieldset_open($value['legend']);
# loop through the fieldset array and get each form field
foreach($value['fields'] as $fieldKey => $fieldValue) {
# check if the field is required
$this->_check_required($fieldValue);
# determine the type of form element we'll need
$data = $this->_parse_fastform_values($fieldKey, $fieldValue);
# tell other methods we're using FastForm
$data['fastform'] = true;
# print the form element
$return .= $this->_fastform_fields($data);
}
$return .= $this->fieldset_close();
} else {
# check if the field is required
$this->_check_required($value);
# determine the type of form element we'll need
$data = $this->_parse_fastform_values($key, $value);
# tell other methods we're using FastForm
$data['fastform'] = true;
# we're putting any hidden elements into an array and printing them at the end of the form
if ($data['type'] == 'hidden') {
if(isset($data['value'])) {
array_push($hidden, $this->input_hidden($data['name'], $data['value']));
} else {
array_push($hidden, $this->input_hidden($data['name'], $data['label']));
}
} else {
# print the form element
$return .= $this->_fastform_fields($data);
}
}
}
# see if a submit button was added while building the form
if ($data['type'] == 'button' || $data['type'] == 'submit') {
$item = $this->input_button_submit($data);
$return .= $this->_wrapper($item, $data);
} else {
# create a default submit with no options
$data['type'] = 'submit';
$data['name'] = 'submit';
$data['label'] = '';
$data['value'] = $this->submit;
$data['id'] = 'submit';
$data['string'] = '';
$data['inline'] = '';
$data['selected'] = '';
$data['options'] = '';
$data['class'] = '';
$item = $this->input_submit($data);
$return .= $this->_wrapper($item, $data);
}
# close the list tag
$return .= $this->_close_list_wrapper();
# if hidden fields are set, print them now
if (!empty($hidden)) {
foreach ($hidden as $hidval) {
$return .= $hidval."\r\n";
}
}
# close the </form>
$return .= $this->form_close();
return $return;
}
public function fastform_multipart($data, $csrf = false)
{
# for file uploads...
return $this->fastform($data, $csrf, 'multipart');
}
private function _faster_form($form_name, $csrf, $multipart)
{
# this method enables the Forms class to be used as a plugin so that we can store
# arrays of frequently used forms and pass them through the fastform() function
# create the array by passing the function name to the Forms class
if(!$this->id) {
$this->id = $form_name;
}
if (file_exists(dirname(__FILE__) . '/my_classes/my.forms.php')) {
$data = \MyForms::$form_name();
} else {
$data = \Forms::$form_name();
}
# pass the array to the fastform() method
if ($multipart) {
return $this->fastform_multipart($data, $csrf);
} else {
return $this->fastform($data, $csrf);
}
}
private function _parse_fastform_values($key, $data)
{
if (!is_array($data)) {
# the fastform() values are in a string
# explode them and get each value
$explode = explode($this->delimiter[0], $data);
# $data is currently a string, convert it to an array
$data = array();
# determine the field's type
$data = $this->_fastform_define_field_type($key, $data);
# start populating the $data array
if (!empty($explode[0])) {
$data['name'] = trim($explode[0]);
} else {
die('error: please provide a name for the <strong>' . $key . '</strong> field');
}
if (!empty($explode[1])) {
$data['label'] = trim($explode[1]);
} else {
$data['label'] = '';
}
if (!empty($explode[2])) {
$data['value'] = trim($explode[2]);
} else {
$data['value'] = '';
}
if (!empty($explode[3])) {
$data['id'] = trim($explode[3]);
} else {
$data['id'] = '';
}
if (!empty($explode[4])) {
$data['string'] = trim($explode[4]);
} else {
$data['string'] = '';
}
if (!empty($explode[5])) {
$data['inline'] = trim($explode[5]);
} else {
$data['inline'] = '';
}
if (!empty($explode[6])) {
$data['selected'] = trim($explode[6]);
} else {
$data['selected'] = '';
}
if (!empty($explode[7])) {
$data['options'] = trim($explode[7]);
} else {
$data['options'] = '';
}
# hidden types don't really require an id, so we'll insert the id into the value
if ($data['type'] == 'hidden') {
$data['value'] = $data['id'];
}
} else {
# determine the field's type
$data = $this->_fastform_define_field_type($key, $data);
if (empty($data['id'])) {
$data['id'] = '';
}
if (empty($data['value'])) {
$data['value'] = '';
}
if (empty($data['string'])) {
$data['string'] = '';
}
if (empty($data['label'])) {
$data['label'] = '';
}
if (empty($data['inline'])) {
$data['inline'] = '';
}
if (empty($data['selected'])) {
$data['selected'] = '';
}
if (empty($data['options'])) {
$data['options'] = '';
}
}
return $data;
}
private function _fastform_define_field_type($key, $data)
{
# this method assigns a field type based on the $key's value
if (!is_array($data)) {
$data = array();
}
# determines if the field name is in the array's key or value
if ($this->_starts_with($key, 'select') || $this->_starts_with($key, 'dropdown') || $this->_starts_with($key, 'state') || $this->_starts_with($key, 'states') || $this->_starts_with($key, 'country')) {
$data['type'] = 'select';
} elseif ($this->_starts_with($key, 'fieldset')) {
$data['type'] = 'fieldset';
} elseif ($this->_starts_with($key, 'submit')) {
$data['type'] = 'submit';
} elseif ($this->_starts_with($key, 'reset')) {
$data['type'] = 'reset';
} elseif ($this->_starts_with($key, 'button')) {
$data['type'] = 'button';
} elseif ($this->_starts_with($key, 'hidden')) {
$data['type'] = 'hidden';
} elseif ($this->_starts_with($key, 'password')) {
$data['type'] = 'password';
} elseif ($this->_starts_with($key, 'file')) {
$data['type'] = 'file';
} elseif ($this->_starts_with($key, 'image')) {
$data['type'] = 'image';
} elseif ($this->_starts_with($key, 'checkbox')) {
$data['type'] = 'checkbox';
} elseif ($this->_starts_with($key, 'radio')) {
$data['type'] = 'radio';
} elseif ($this->_starts_with($key, 'textarea')) {
$data['type'] = 'textarea';
} elseif ($this->_starts_with($key, 'color')) {
$data['type'] = 'color';
} elseif ($this->_starts_with($key, 'email')) {
$data['type'] = 'email';
} elseif ($this->_starts_with($key, 'datetime_local')) {
$data['type'] = 'datetime_local';
} elseif ($this->_starts_with($key, 'datetime')) {
$data['type'] = 'datetime';
} elseif ($this->_starts_with($key, 'date')) {
$data['type'] = 'date';
} elseif ($this->_starts_with($key, 'month')) {
$data['type'] = 'month';
} elseif ($this->_starts_with($key, 'number')) {
$data['type'] = 'number';
} elseif ($this->_starts_with($key, 'range')) {
$data['type'] = 'range';
} elseif ($this->_starts_with($key, 'search')) {
$data['type'] = 'search';
} elseif ($this->_starts_with($key, 'tel')) {
$data['type'] = 'tel';
} elseif ($this->_starts_with($key, 'time')) {
$data['type'] = 'time';
} elseif ($this->_starts_with($key, 'url')) {
$data['type'] = 'url';
} elseif ($this->_starts_with($key, 'week')) {
$data['type'] = 'week';
} elseif ($this->_starts_with($key, 'label')) {
$data['type'] = 'label';
} else {
$data['type'] = 'text';
}
return $data;
}
private function _fastform_fields($data)
{
# determines what kind of form field element we need
$return = null;
if($data['type'] == 'hidden' || $data['type'] == 'submit' || $data['type'] == 'button' || $data['type'] == 'reset') {
return;
}
if ($data['type'] == 'label')
{
$return .= $this->label($data);
}
elseif ($data['type'] == 'radio' || $data['type'] == 'checkbox')
{
if ($this->is_in_brackets($data['value'])) {
# we have a radio/checkbox array
# loop through the value in the array, create elements and put them all into one wrapper with one label
# put each element value into an array and return them
$item = $this->_build_input_groups($data);
# strip out the label for the element
$data['label'] = '';
# wrap the element
$return .= $this->_wrapper($item, $data);
} else {
# build each element individually and wrap it in a label
$item = "<label for=\"{$data['id']}\">\r\n";
if ($data['type'] == 'radio') {
$item .= $this->input_radio($data);
} else {
$item .= $this->input_checkbox($data);
}
$item .= " {$data['label']}\r\n</label>\r\n";
# empty the label value so the wrapper function won't build it again
$data['label'] = '';
# wrap it
$return .= $this->_wrapper($item, $data);
}
}
elseif ($data['type'] == 'select') {
$item = $this->input_select($data);
$return .= $this->_wrapper($item, $data);
} elseif ($data['type'] == 'text') {
$item = $this->input_text($data);
$return .= $this->_wrapper($item, $data);
} elseif ($data['type'] == 'password') {
$item = $this->input_password($data);
$return .= $this->_wrapper($item, $data);
} elseif ($data['type'] == 'textarea') {
$item = $this->input_textarea($data);
$return .= $this->_wrapper($item, $data);
} elseif ($data['type'] == 'file') {
$item = $this->input_upload($data);
$return .= $this->_wrapper($item, $data);
} elseif ($data['type'] == 'color') {
$item = $this->input_color($data);
$return .= $this->_wrapper($item, $data);
} elseif ($data['type'] == 'email') {
$item = $this->input_email($data);
$return .= $this->_wrapper($item, $data);
} elseif ($data['type'] == 'date') {
$item = $this->input_date($data);
$return .= $this->_wrapper($item, $data);
} elseif ($data['type'] == 'datetime' || $data['type'] == 'datetime-local') {
$item = $this->input_datetime_local($data);
$return .= $this->_wrapper($item, $data);
} elseif ($data['type'] == 'month') {
$item = $this->input_month($data);
$return .= $this->_wrapper($item, $data);
} elseif ($data['type'] == 'number') {
$item = $this->input_number($data);
$return .= $this->_wrapper($item, $data);
} elseif ($data['type'] == 'range') {
$item = $this->input_range($data);
$return .= $this->_wrapper($item, $data);
} elseif ($data['type'] == 'search') {
$item = $this->input_search($data);
$return .= $this->_wrapper($item, $data);
} elseif ($data['type'] == 'tel') {
$item = $this->input_tel($data);
$return .= $this->_wrapper($item, $data);
} elseif ($data['type'] == 'time') {
$item = $this->input_time($data);
$return .= $this->_wrapper($item, $data);
} elseif ($data['type'] == 'url') {
$item = $this->input_url($data);
$return .= $this->_wrapper($item, $data);
} elseif ($data['type'] == 'week') {
$item = $this->input_week($data);
$return .= $this->_wrapper($item, $data);
} elseif ($data['type'] == 'reset') {
$item = $this->input_reset($data);
$return .= $this->_wrapper($item, $data);
} else {
# default to text
$item = $this->input_text($data);
$return .= $this->_wrapper($item, $data);
}
return $return;
}
# MISC
private function _inline($name)
{
# add div if using inline errors
if ($this->in_errors($name) && $this->inline_errors) {
return '<div class="' . $this->inline_errors_class . '"></div>';
}
}
private function _starts_with($key, $str)
{
# check if a string starts with the given word
return mb_substr($key, 0, strlen($str)) == $str;
}
private function _strip_brackets($str)
{
# strip brackets from a string
return trim($str, '[]');
}
private function _suppress_formr_validation_errors($data)
{
# suppress Formr's default validation error messages and only show user-defined messages
if (array_key_exists('string', $data) && $this->custom_validation_messages) {
return true;
}
return false;
}
private function _wrapper_is($string)
{
# determines if the wrapper is a supported framework or default
if ($string == 'framework') {
if (strpos($this->wrapper, 'bootstrap') !== false) {
return true;
}
if (strpos($this->wrapper, 'bulma') !== false) {
return true;
}
return false;
}
if (strstr($this->wrapper, $string) !== false) {
return true;
}
return false;
}
public function heading($key, $string)
{
# put your string in here and it'll be highlighted when the field receives an error
# useful in questionnaires and the like.
if (array_key_exists($key, $this->errors)) {
return $this->_echo('<h2><span class="error">' . $string . '</span></h2>');
} else {
return $this->_echo('<h2>' . $string . '</h2>');
}
}
public function send_email($to, $subject, $message, $from = '', $html = false, $headers = null)
{
# really simple method for firing off a quick email
# something I was playing around with and forgot about...
# TODO? may add to/improve this in the future
$msg = null;
if ($html) {
# we're sending an HTML email
if (!$headers) {
$headers .= "MIME-Version: 1.0\r\n";
$headers .= "Content-Type: text/html; charset=ISO-8859-1\r\n";
if ($from) {
$headers .= "From: " . $this->_clean_value($from) . "\r\n";
}
}
$msg .= "<html>\r\n";
$msg .= "<body>\r\n";
$msg .= "<table cellpadding=\"4\" cellspacing=\"0\" border=\"0\">\r\n";
}
# loop through $_POST and print key => value
if (strtolower($message) == 'post' || is_array($message)) {
foreach ($_POST as $key => $value) {
if ($key != 'submit' && $key != 'button' && $key != 'FormrID') {
# make sure it's a valid email address
if (!empty($value) && (strpos(strtolower($key), 'email') !== false) && !filter_var($value, FILTER_VALIDATE_EMAIL)) {
$this->errors[$key] = 'Please enter a valid email address';
}
# check if required
if ($this->_check_required($key)) {
# add to errors array
if (empty($value)) {
$this->errors[$key] = '<strong>' . str_replace('_', ' ', ltrim($key, '_')) . '</strong> is required';
}
}
# if key is prepended with an underscore, replace all underscores with a space
# _First_Name becomes First Name
if ($key[0] == '_') {
$key = str_replace('_', ' ', ltrim($key, '_'));
}
# if key is an array, print all values
if (is_array($value)) {
$value = implode(', ',$value);
}
if ($html) {
$msg .= "<tr>\r\n";
$msg .= "\t<td><strong>$key:</strong></td>\r\n";
$msg .= "\t<td>" . $this->_clean_value($value) . "</td>\r\n";
$msg .= "</tr>\r\n";
} else {
$msg .= $key . ": \t" . $this->_clean_value($value) . "\r\n";
}
}
}
} else {
# message is supplied by user
$msg .= $message;
}
if ($html) {
$msg .= "</table>\r\n";
$msg .= "</body>\r\n";
$msg .= "</html>\r\n";
}
# send the email
if (!$this->errors()) {
if($html) {
if (mail($to, $subject, $msg, $headers)) {
return true;
}
} else {
if (mail($to, $subject, $msg)) {
return true;
}
}
}
return false;
}
public function send_html_email($to, $subject, $message, $from = '', $headers = null)
{
return $this->send_email($to, $subject, $message, $from, true, $headers);
}
public function get_ip_address($mysql = false)
{
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
$ip_address = $_SERVER['HTTP_CLIENT_IP'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$ip_address = $_SERVER['HTTP_X_FORWARDED_FOR'];
} else {
$ip_address = $_SERVER['REMOTE_ADDR'];
}
if ($mysql) {
return ip2long($ip_address);
} else {
return $ip_address;
}
}
public function make_id($data)
{
# create an ID from the element's name attribute (if an ID was not specified)
if($this->is_not_empty($data['id'])) {
return trim($data['id'], '[]');
}
return trim($data['name'], '[]');
}
public function insert_required_indicator($data)
{
# insert the required_field indicator if applicable
if(!in_array($data['type'], $this->excluded_types)) {
if($this->_check_required($data['name']) && $this->is_not_empty($data['label'])) {
return $this->required_indicator;
}
}
}
public function type_is_checkbox($data)
{
# determines if the element is a checkbox or radio
if($data['type'] == 'checkbox' || $data['type'] == 'radio') {
return true;
}
return false;
}
public function is_array($data)
{
# determines is the element's name is an array
if(substr($data, -1) == ']') {
return true;
}
return false;
}
public function is_in_brackets($data)
{
# determines if the given word is contained in brackets
if(mb_substr($data, 0, 1) == '[') {
return true;
}
return false;
}
public function csrf($timeout = 3600)
{
# add csrf protection
# remember to put session_start() at the top of your script!
if (session_status() == PHP_SESSION_NONE) {
$this->_error_message('CSRF requires <code>session_start()</code> at the top of the script.');
}
# put the token into a session
if(empty($_SESSION['formr']['token'])) {
if (function_exists('mcrypt_create_iv')) {
$_SESSION['formr']['token'] = bin2hex(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM));
} else {
$_SESSION['formr']['token'] = bin2hex(openssl_random_pseudo_bytes(32));
}
}
# we're putting the token and expiration time into the hidden element
$string = $_SESSION['formr']['token'] . '|' . (time()+$timeout);
return $this->_echo("<input type=\"hidden\" name=\"csrf_token\" value=\"{$string}\">\r\n\r\n");
}
public function redirect($url = null)
{
# redirect to the given url after the form has been submitted
if(!$url || $url == 'self') {
$url = $_SERVER['PHP_SELF'];
}
header('Location: '.$url);
exit;
}
public function unset_session()
{
# deletes the formr, and user-defined sessions, handy for testing
unset($_SESSION['formr']);
if (isset($_SESSION[$this->session])) {
unset($_SESSION[$this->session]);
}
echo $this->_success_message("SESSION[$this->session] has been unset");
$this->session = null;
$this->session_values = null;
}
public function ok()
{
if (isset($_POST['csrf_token']) && !isset($_SESSION['formr']['token'])) {
return false;
}
if (empty($this->errors)) {
return true;
}
return false;
}
private function _check_for_honeypot()
{
# die if the honeypot caught a bear
if($this->honeypot && $_SERVER['REQUEST_METHOD'] == 'POST') {
if(!empty($_POST[$this->honeypot])) {
die;
}
}
}
private function _check_for_csrf()
{
# check if we're using csrf
if (isset($_POST['csrf_token']) && isset($_SESSION['formr']['token'])) {
# grab the token and expiration time from the hidden element
$parts = explode('|', $_POST['csrf_token']);
# check if token in SESSION equals posted token value
if (hash_equals((string) $_SESSION['formr']['token'], strval($parts[0]))) {
# compare current time to time of token expiration
if (time() >= $parts[1]) {
$this->_error_message('Your session has expired. Please refresh the page.');
# reset the token
$_SESSION['formr']['token'] = null;
}
}
if (isset($message)) {
$this->error_message($message);
}
}
}
private function _handle_session_checkbox_arrays()
{
if($this->session && $this->session_values && isset($_SESSION[$this->session])) {
# Here is where we are handling checkbox arrays in our session.
# We have created a hidden element inside the _create_input() method which contains the array's values.
# example: <input type="hidden" name="colors" value="red,green,blue">
# We're going to go through those values and match them against what was posted...
# here's where we'll store the checkbox array values we get from the hidden element(s)
$created_checkbox_values = [];
# here's where we'll store the values of the checkboxes that were ticked upon submit
$posted_checkbox_values = [];
foreach ($_POST as $key => $value) {
# check if the post value is an array
if (is_array($value)) {
foreach($value as $k => $v) {
# put the posted checkbox value into the posted array
$posted_checkbox_values[$key][] = $v;
}
}
# the checkbox array's hidden element value is a string, so let's explode it and put it into our array
if (strpos($key, '_values') !== false) {
$created_checkbox_values[str_replace('_values', '', $key)] = explode(',', $_POST[$key]);
}
}
# we're now going to compare the form's checkbox values to the values that were actually posted
if(!empty($posted_checkbox_values)) {
foreach($created_checkbox_values as $key => $array) {
# if a checkbox value is *not* posted in an array group, remove it from the session
if(!empty($posted_checkbox_values[$key]) && isset($_SESSION[$this->session][$key])) {
$clean1 = array_diff($posted_checkbox_values[$key], $array);
$clean2 = array_diff($array, $posted_checkbox_values[$key]);
$output = array_merge($clean1, $clean2);
foreach ($output as $value) {
foreach ($_SESSION[$this->session][$key] as $skey => $svalue) {
if ($svalue == $value) {
unset($_SESSION[$this->session][$key][$skey]);
}
}
}
} else {
# no checkbox values were posted in an array group, so remove the checkbox value from the session's array group
foreach ($array as $array_key => $array_value) {
if (isset($_SESSION[$this->session][$key])) {
# if the array is empty, just remove it
if (empty($_SESSION[$this->session][$key])) {
unset($_SESSION[$this->session][$key]);
} else {
# remove each un-posted checkbox value from the session
foreach ($_SESSION[$this->session][$key] as $skey => $svalue) {
if ($svalue == $array_value) {
unset($_SESSION[$this->session][$key][$skey]);
}
}
}
}
}
}
}
} else {
# no checkbox arrays were posted at all, so remove the checkbox array(s) from the session
foreach ($created_checkbox_values as $key => $value) {
if(isset($_SESSION[$this->session][$key])) {
unset($_SESSION[$this->session][$key]);
}
}
}
}
}
public function recaptcha_passed()
{
# google recaptcha v3
# here's where we bring it all together and validate with google's servers on the back-end
# from Gatsby's answer on stackoverflow: https://stackoverflow.com/a/60036326
if(($_SERVER['REQUEST_METHOD'] == 'POST') && ($this->recaptcha_secret_key && $this->recaptcha_site_key))
{
$data = [
'secret' => $this->recaptcha_secret_key,
'response' => $_POST['formrToken'],
'remoteip' => $_SERVER['REMOTE_ADDR']
];
$options = [
'http' => [
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($data)
]
];
# creates and returns stream context with options supplied in options preset
$context = stream_context_create($options);
# use curl or file_get_contents()
if ($this->recaptcha_use_curl) {
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => 'https://www.google.com/recaptcha/api/siteverify',
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => [
'secret' => $this->recaptcha_secret_key,
'response' => $_POST['formrToken'],
'remoteip' => $_SERVER['REMOTE_ADDR']
],
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_RETURNTRANSFER => true
]);
$response = curl_exec($ch);
curl_close($ch);
} else {
$response = file_get_contents('https://www.google.com/recaptcha/api/siteverify', false, $context);
}
# convert the json encoded string to a php variable
$result = json_decode($response, true);
if (!empty($result) && ($result['success'] == true) && ($result['score'] >= $this->recaptcha_score)) {
return true;
}
return false;
}
}
public function recaptcha_head()
{
# google recaptcha v3
# prints script src for client-side validation
# from Gatsby's answer on stackoverflow: https://stackoverflow.com/a/60036326
$this->_echo("<script src=\"https://www.google.com/recaptcha/api.js?render={$this->recaptcha_site_key}\"></script>\r\n");
}
public function recaptcha_body()
{
# google recaptcha v3
# prints front-end javascript for client-side token retrieval
# from Gatsby's answer on stackoverflow: https://stackoverflow.com/a/60036326
$return = "<script>\r\n";
$return .= " grecaptcha.ready(function() {\r\n";
$return .= " grecaptcha.execute('{$this->recaptcha_site_key}', {\r\n";
if($this->recaptcha_action_name) {
$return .= " action:'".$this->recaptcha_action_name."'\r\n";
} else {
$return .= " action:'Formr'\r\n";
}
$return .= " }).then(function(formrToken) {\r\n";
$return .= " document.getElementById('formrToken').value = formrToken;\r\n";
$return .= " });\r\n";
$return .= " // refresh token every minute to prevent expiration\r\n";
$return .= " setInterval(function(){\r\n";
$return .= " grecaptcha.execute('{$this->recaptcha_site_key}', {\r\n";
if($this->recaptcha_action_name) {
$return .= " action:'".$this->recaptcha_action_name."'\r\n";
} else {
$return .= " action:'Formr'\r\n";
}
$return .= " }).then(function(formrToken) {\r\n";
$return .= " document.getElementById('formrToken').value = formrToken;\r\n";
$return .= " });\r\n";
$return .= " }, 60000);\r\n";
$return .= " });\r\n";
$return .= "</script>\r\n";
$this->_echo($return);
}
public function clear()
{
# will show empty form fields after form is submitted
$_POST = [];
}
}