first commit

This commit is contained in:
fuzi_fauzia committed 2024-07-31 13:12:38 +07:00
commit b4e8cbe182
10213 files changed
+3125839

No files matched your search

@@ -0,0 +1,6 @@
<?php
return array(
'dependencies' => array(),
'version' => WPCF7_VERSION,
);
@@ -0,0 +1 @@
(()=>{"use strict";var t={d:(e,i)=>{for(var s in i)t.o(i,s)&&!t.o(e,s)&&Object.defineProperty(e,s,{enumerable:!0,get:i[s]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},e={};function i(t){if(this.formData={},this.tree={},!(t instanceof FormData))return this;this.formData=t;const e=()=>{const t=new Map;return t.largestIndex=0,t.set=function(e,i){""===e?e=t.largestIndex++:/^[0-9]+$/.test(e)&&(e=parseInt(e),t.largestIndex<=e&&(t.largestIndex=e+1)),Map.prototype.set.call(t,e,i)},t};this.tree=e();const i=/^(?<name>[a-z][-a-z0-9_:]*)(?<array>(?:\[(?:[a-z][-a-z0-9_:]*|[0-9]*)\])*)/i;for(const[t,s]of this.formData){const o=t.match(i);if(o)if(""===o.groups.array)this.tree.set(o.groups.name,s);else{const t=[...o.groups.array.matchAll(/\[([a-z][-a-z0-9_:]*|[0-9]*)\]/gi)].map((([t,e])=>e));t.unshift(o.groups.name);const i=t.pop();t.reduce(((t,i)=>{if(/^[0-9]+$/.test(i)&&(i=parseInt(i)),t.get(i)instanceof Map)return t.get(i);const s=e();return t.set(i,s),s}),this.tree).set(i,s)}}}t.r(e),t.d(e,{all:()=>D,any:()=>M,date:()=>f,dayofweek:()=>u,email:()=>r,enum:()=>h,file:()=>m,maxdate:()=>z,maxfilesize:()=>$,maxitems:()=>v,maxlength:()=>x,maxnumber:()=>b,mindate:()=>A,minfilesize:()=>j,minitems:()=>w,minlength:()=>g,minnumber:()=>y,number:()=>c,required:()=>n,requiredfile:()=>a,tel:()=>l,time:()=>d,url:()=>p}),i.prototype.entries=function(){return this.tree.entries()},i.prototype.get=function(t){return this.tree.get(t)},i.prototype.getAll=function(t){if(!this.has(t))return[];const e=t=>{const i=[];if(t instanceof Map)for(const[s,o]of t)i.push(...e(o));else""!==t&&i.push(t);return i};return e(this.get(t))},i.prototype.has=function(t){return this.tree.has(t)},i.prototype.keys=function(){return this.tree.keys()},i.prototype.values=function(){return this.tree.values()};const s=i;function o({rule:t,field:e,error:i,...s}){this.rule=t,this.field=e,this.error=i,this.properties=s}const n=function(t){if(0===t.getAll(this.field).length)throw new o(this)},a=function(t){if(0===t.getAll(this.field).length)throw new o(this)},r=function(t){if(!t.getAll(this.field).every((t=>{if((t=t.trim()).length<6)return!1;if(-1===t.indexOf("@",1))return!1;if(t.indexOf("@")!==t.lastIndexOf("@"))return!1;const[e,i]=t.split("@",2);if(!/^[a-zA-Z0-9!#$%&\'*+\/=?^_`{|}~\.-]+$/.test(e))return!1;if(/\.{2,}/.test(i))return!1;if(/(?:^[ \t\n\r\0\x0B.]|[ \t\n\r\0\x0B.]$)/.test(i))return!1;const s=i.split(".");if(s.length<2)return!1;for(const t of s){if(/(?:^[ \t\n\r\0\x0B-]|[ \t\n\r\0\x0B-]$)/.test(t))return!1;if(!/^[a-z0-9-]+$/i.test(t))return!1}return!0})))throw new o(this)},p=function(t){const e=t.getAll(this.field);if(!e.every((t=>{if(""===(t=t.trim()))return!1;try{return(t=>-1!==["http","https","ftp","ftps","mailto","news","irc","irc6","ircs","gopher","nntp","feed","telnet","mms","rtsp","sms","svn","tel","fax","xmpp","webcal","urn"].indexOf(t))(new URL(t).protocol.replace(/:$/,""))}catch{return!1}})))throw new o(this)},l=function(t){if(!t.getAll(this.field).every((t=>(t=(t=t.trim()).replaceAll(/[()/.*#\s-]+/g,""),/^[+]?[0-9]+$/.test(t)))))throw new o(this)},c=function(t){if(!t.getAll(this.field).every((t=>(t=t.trim(),!!/^[-]?[0-9]+(?:[eE][+-]?[0-9]+)?$/.test(t)||!!/^[-]?(?:[0-9]+)?[.][0-9]+(?:[eE][+-]?[0-9]+)?$/.test(t)))))throw new o(this)},f=function(t){if(!t.getAll(this.field).every((t=>{if(t=t.trim(),!/^[0-9]{4,}-[0-9]{2}-[0-9]{2}$/.test(t))return!1;const e=new Date(t);return!Number.isNaN(e.valueOf())})))throw new o(this)},d=function(t){if(!t.getAll(this.field).every((t=>{const e=t.trim().match(/^([0-9]{2})\:([0-9]{2})(?:\:([0-9]{2}))?$/);if(!e)return!1;const i=parseInt(e[1]),s=parseInt(e[2]),o=e[3]?parseInt(e[3]):0;return 0<=i&&i<=23&&0<=s&&s<=59&&0<=o&&o<=59})))throw new o(this)},m=function(t){if(!t.getAll(this.field).every((t=>t instanceof File&&this.accept?.some((e=>/^\.[a-z0-9]+$/i.test(e)?t.name.toLowerCase().endsWith(e.toLowerCase()):(t=>{const e=[],i=t.match(/^(?<toplevel>[a-z]+)\/(?<sub>[*]|[a-z0-9.+-]+)$/i);if(i){const t=i.groups.toplevel.toLowerCase(),s=i.groups.sub.toLowerCase();for(const[o,n]of(()=>{const t=new Map;return t.set("jpg|jpeg|jpe","image/jpeg"),t.set("gif","image/gif"),t.set("png","image/png"),t.set("bmp","image/bmp"),t.set("tiff|tif","image/tiff"),t.set("webp","image/webp"),t.set("ico","image/x-icon"),t.set("heic","image/heic"),t.set("asf|asx","video/x-ms-asf"),t.set("wmv","video/x-ms-wmv"),t.set("wmx","video/x-ms-wmx"),t.set("wm","video/x-ms-wm"),t.set("avi","video/avi"),t.set("divx","video/divx"),t.set("flv","video/x-flv"),t.set("mov|qt","video/quicktime"),t.set("mpeg|mpg|mpe","video/mpeg"),t.set("mp4|m4v","video/mp4"),t.set("ogv","video/ogg"),t.set("webm","video/webm"),t.set("mkv","video/x-matroska"),t.set("3gp|3gpp","video/3gpp"),t.set("3g2|3gp2","video/3gpp2"),t.set("txt|asc|c|cc|h|srt","text/plain"),t.set("csv","text/csv"),t.set("tsv","text/tab-separatedLine truncated
@@ -0,0 +1,191 @@
<?php
namespace Contactable\SWV;
use WP_Error;
/**
* The base class of SWV rules.
*/
abstract class Rule {
protected $properties = array();
public function __construct( $properties = '' ) {
$this->properties = wp_parse_args( $properties, array() );
}
/**
* Returns true if this rule matches the given context.
*
* @param array $context Context.
*/
public function matches( $context ) {
$field = $this->get_property( 'field' );
if ( ! empty( $context['field'] ) ) {
if ( $field and ! in_array( $field, (array) $context['field'], true ) ) {
return false;
}
}
return true;
}
/**
* Validates with this rule's logic.
*
* @param array $context Context.
*/
public function validate( $context ) {
return true;
}
/**
* Converts the properties to an array.
*
* @return array Array of properties.
*/
public function to_array() {
$properties = (array) $this->properties;
if ( defined( 'static::rule_name' ) and static::rule_name ) {
$properties = array( 'rule' => static::rule_name ) + $properties;
}
return $properties;
}
/**
* Returns the property value specified by the given property name.
*
* @param string $name Property name.
* @return mixed Property value.
*/
public function get_property( $name ) {
if ( isset( $this->properties[$name] ) ) {
return $this->properties[$name];
}
}
/**
* Returns the default user input value from $_POST.
*
* @return mixed Default user input value.
*/
public function get_default_input() {
$field = $this->get_property( 'field' );
if ( isset( $_POST[$field] ) ) {
return wp_unslash( $_POST[$field] );
}
return '';
}
/**
* Creates an error object. Returns false if the error property is omitted.
*/
protected function create_error() {
$error_code = defined( 'static::rule_name' )
? sprintf( 'swv_%s', static::rule_name )
: 'swv';
return new WP_Error(
$error_code,
(string) $this->get_property( 'error' ),
$this
);
}
}
/**
* The base class of SWV composite rules.
*/
abstract class CompositeRule extends Rule {
protected $rules = array();
/**
* Adds a sub-rule to this composite rule.
*
* @param Rule $rule Sub-rule to be added.
*/
public function add_rule( $rule ) {
if ( $rule instanceof Rule ) {
$this->rules[] = $rule;
}
}
/**
* Returns an iterator of sub-rules.
*/
public function rules() {
foreach ( $this->rules as $rule ) {
yield $rule;
}
}
/**
* Returns true if this rule matches the given context.
*
* @param array $context Context.
*/
public function matches( $context ) {
return true;
}
/**
* Validates with this rule's logic.
*
* @param array $context Context.
*/
public function validate( $context ) {
foreach ( $this->rules() as $rule ) {
if ( $rule->matches( $context ) ) {
$result = $rule->validate( $context );
if ( is_wp_error( $result ) ) {
return $result;
}
}
}
return true;
}
/**
* Converts the properties to an array.
*
* @return array Array of properties.
*/
public function to_array() {
$rules_arrays = array_map(
static function ( $rule ) {
return $rule->to_array();
},
$this->rules
);
return array_merge(
parent::to_array(),
array(
'rules' => $rules_arrays,
)
);
}
}
@@ -0,0 +1,35 @@
<?php
namespace Contactable\SWV;
class AllRule extends CompositeRule {
const rule_name = 'all';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
return true;
}
public function validate( $context ) {
foreach ( $this->rules() as $rule ) {
if ( $rule->matches( $context ) ) {
$result = $rule->validate( $context );
if ( is_wp_error( $result ) ) {
if ( $result->get_error_message() ) {
return $result;
} else {
return $this->create_error();
}
}
}
}
return true;
}
}
@@ -0,0 +1,31 @@
<?php
namespace Contactable\SWV;
class AnyRule extends CompositeRule {
const rule_name = 'any';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
return true;
}
public function validate( $context ) {
foreach ( $this->rules() as $rule ) {
if ( $rule->matches( $context ) ) {
$result = $rule->validate( $context );
if ( ! is_wp_error( $result ) ) {
return true;
}
}
}
return $this->create_error();
}
}
@@ -0,0 +1,35 @@
<?php
namespace Contactable\SWV;
class DateRule extends Rule {
const rule_name = 'date';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['text'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$input = $this->get_default_input();
$input = wpcf7_array_flatten( $input );
$input = wpcf7_exclude_blank( $input );
foreach ( $input as $i ) {
if ( ! wpcf7_is_date( $i ) ) {
return $this->create_error();
}
}
return true;
}
}
@@ -0,0 +1,45 @@
<?php
namespace Contactable\SWV;
class DayofweekRule extends Rule {
const rule_name = 'dayofweek';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['text'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$input = $this->get_default_input();
$input = wpcf7_array_flatten( $input );
$input = wpcf7_exclude_blank( $input );
$acceptable_values = (array) $this->get_property( 'accept' );
$acceptable_values = array_map( 'intval', $acceptable_values );
$acceptable_values = array_filter( $acceptable_values );
$acceptable_values = array_unique( $acceptable_values );
foreach ( $input as $i ) {
if ( wpcf7_is_date( $i ) ) {
$datetime = date_create_immutable( $i, wp_timezone() );
$dow = (int) $datetime->format( 'N' );
if ( ! in_array( $dow, $acceptable_values, true ) ) {
return $this->create_error();
}
}
}
return true;
}
}
@@ -0,0 +1,35 @@
<?php
namespace Contactable\SWV;
class EmailRule extends Rule {
const rule_name = 'email';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['text'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$input = $this->get_default_input();
$input = wpcf7_array_flatten( $input );
$input = wpcf7_exclude_blank( $input );
foreach ( $input as $i ) {
if ( ! wpcf7_is_email( $i ) ) {
return $this->create_error();
}
}
return true;
}
}
@@ -0,0 +1,45 @@
<?php
namespace Contactable\SWV;
class EnumRule extends Rule {
const rule_name = 'enum';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['text'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$input = $this->get_default_input();
$input = wpcf7_array_flatten( $input );
$input = wpcf7_exclude_blank( $input );
$acceptable_values = (array) $this->get_property( 'accept' );
$acceptable_values = array_map( 'strval', $acceptable_values );
$acceptable_values = array_unique( $acceptable_values );
$acceptable_values = array_filter( $acceptable_values,
static function ( $val ) {
return '' !== $val;
}
);
foreach ( $input as $i ) {
if ( ! in_array( $i, $acceptable_values, true ) ) {
return $this->create_error();
}
}
return true;
}
}
@@ -0,0 +1,61 @@
<?php
namespace Contactable\SWV;
class FileRule extends Rule {
const rule_name = 'file';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['file'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$field = $this->get_property( 'field' );
$input = $_FILES[$field]['name'] ?? '';
$input = wpcf7_array_flatten( $input );
$input = wpcf7_exclude_blank( $input );
$acceptable_filetypes = array();
foreach ( (array) $this->get_property( 'accept' ) as $accept ) {
if ( preg_match( '/^\.[a-z0-9]+$/i', $accept ) ) {
$acceptable_filetypes[] = strtolower( $accept );
} else {
foreach ( wpcf7_convert_mime_to_ext( $accept ) as $ext ) {
$acceptable_filetypes[] = sprintf(
'.%s',
strtolower( trim( $ext, ' .' ) )
);
}
}
}
$acceptable_filetypes = array_unique( $acceptable_filetypes );
foreach ( $input as $i ) {
$last_period_pos = strrpos( $i, '.' );
if ( false === $last_period_pos ) { // no period
return $this->create_error();
}
$suffix = strtolower( substr( $i, $last_period_pos ) );
if ( ! in_array( $suffix, $acceptable_filetypes, true ) ) {
return $this->create_error();
}
}
return true;
}
}
@@ -0,0 +1,41 @@
<?php
namespace Contactable\SWV;
class MaxDateRule extends Rule {
const rule_name = 'maxdate';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['text'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$input = $this->get_default_input();
$input = wpcf7_array_flatten( $input );
$input = wpcf7_exclude_blank( $input );
$threshold = $this->get_property( 'threshold' );
if ( ! wpcf7_is_date( $threshold ) ) {
return true;
}
foreach ( $input as $i ) {
if ( wpcf7_is_date( $i ) and $threshold < $i ) {
return $this->create_error();
}
}
return true;
}
}
@@ -0,0 +1,40 @@
<?php
namespace Contactable\SWV;
class MaxFileSizeRule extends Rule {
const rule_name = 'maxfilesize';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['file'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$field = $this->get_property( 'field' );
$input = $_FILES[$field]['size'] ?? '';
$input = wpcf7_array_flatten( $input );
$input = wpcf7_exclude_blank( $input );
if ( empty( $input ) ) {
return true;
}
$threshold = $this->get_property( 'threshold' );
if ( $threshold < array_sum( $input ) ) {
return $this->create_error();
}
return true;
}
}
@@ -0,0 +1,39 @@
<?php
namespace Contactable\SWV;
class MaxItemsRule extends Rule {
const rule_name = 'maxitems';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['text'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$input = $this->get_default_input();
$input = wpcf7_array_flatten( $input );
$input = wpcf7_exclude_blank( $input );
$threshold = $this->get_property( 'threshold' );
if ( ! wpcf7_is_number( $threshold ) ) {
return true;
}
if ( (int) $threshold < count( $input ) ) {
return $this->create_error();
}
return true;
}
}
@@ -0,0 +1,45 @@
<?php
namespace Contactable\SWV;
class MaxLengthRule extends Rule {
const rule_name = 'maxlength';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['text'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$input = $this->get_default_input();
$input = wpcf7_array_flatten( $input );
$input = wpcf7_exclude_blank( $input );
if ( empty( $input ) ) {
return true;
}
$total = 0;
foreach ( $input as $i ) {
$total += wpcf7_count_code_units( $i );
}
$threshold = (int) $this->get_property( 'threshold' );
if ( $total <= $threshold ) {
return true;
} else {
return $this->create_error();
}
}
}
@@ -0,0 +1,41 @@
<?php
namespace Contactable\SWV;
class MaxNumberRule extends Rule {
const rule_name = 'maxnumber';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['text'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$input = $this->get_default_input();
$input = wpcf7_array_flatten( $input );
$input = wpcf7_exclude_blank( $input );
$threshold = $this->get_property( 'threshold' );
if ( ! wpcf7_is_number( $threshold ) ) {
return true;
}
foreach ( $input as $i ) {
if ( wpcf7_is_number( $i ) and (float) $threshold < (float) $i ) {
return $this->create_error();
}
}
return true;
}
}
@@ -0,0 +1,41 @@
<?php
namespace Contactable\SWV;
class MinDateRule extends Rule {
const rule_name = 'mindate';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['text'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$input = $this->get_default_input();
$input = wpcf7_array_flatten( $input );
$input = wpcf7_exclude_blank( $input );
$threshold = $this->get_property( 'threshold' );
if ( ! wpcf7_is_date( $threshold ) ) {
return true;
}
foreach ( $input as $i ) {
if ( wpcf7_is_date( $i ) and $i < $threshold ) {
return $this->create_error();
}
}
return true;
}
}
@@ -0,0 +1,40 @@
<?php
namespace Contactable\SWV;
class MinFileSizeRule extends Rule {
const rule_name = 'minfilesize';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['file'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$field = $this->get_property( 'field' );
$input = $_FILES[$field]['size'] ?? '';
$input = wpcf7_array_flatten( $input );
$input = wpcf7_exclude_blank( $input );
if ( empty( $input ) ) {
return true;
}
$threshold = $this->get_property( 'threshold' );
if ( array_sum( $input ) < $threshold ) {
return $this->create_error();
}
return true;
}
}
@@ -0,0 +1,39 @@
<?php
namespace Contactable\SWV;
class MinItemsRule extends Rule {
const rule_name = 'minitems';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['text'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$input = $this->get_default_input();
$input = wpcf7_array_flatten( $input );
$input = wpcf7_exclude_blank( $input );
$threshold = $this->get_property( 'threshold' );
if ( ! wpcf7_is_number( $threshold ) ) {
return true;
}
if ( count( $input ) < (int) $threshold ) {
return $this->create_error();
}
return true;
}
}
@@ -0,0 +1,45 @@
<?php
namespace Contactable\SWV;
class MinLengthRule extends Rule {
const rule_name = 'minlength';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['text'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$input = $this->get_default_input();
$input = wpcf7_array_flatten( $input );
$input = wpcf7_exclude_blank( $input );
if ( empty( $input ) ) {
return true;
}
$total = 0;
foreach ( $input as $i ) {
$total += wpcf7_count_code_units( $i );
}
$threshold = (int) $this->get_property( 'threshold' );
if ( $threshold <= $total ) {
return true;
} else {
return $this->create_error();
}
}
}
@@ -0,0 +1,41 @@
<?php
namespace Contactable\SWV;
class MinNumberRule extends Rule {
const rule_name = 'minnumber';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['text'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$input = $this->get_default_input();
$input = wpcf7_array_flatten( $input );
$input = wpcf7_exclude_blank( $input );
$threshold = $this->get_property( 'threshold' );
if ( ! wpcf7_is_number( $threshold ) ) {
return true;
}
foreach ( $input as $i ) {
if ( wpcf7_is_number( $i ) and (float) $i < (float) $threshold ) {
return $this->create_error();
}
}
return true;
}
}
@@ -0,0 +1,35 @@
<?php
namespace Contactable\SWV;
class NumberRule extends Rule {
const rule_name = 'number';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['text'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$input = $this->get_default_input();
$input = wpcf7_array_flatten( $input );
$input = wpcf7_exclude_blank( $input );
foreach ( $input as $i ) {
if ( ! wpcf7_is_number( $i ) ) {
return $this->create_error();
}
}
return true;
}
}
@@ -0,0 +1,33 @@
<?php
namespace Contactable\SWV;
class RequiredRule extends Rule {
const rule_name = 'required';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['text'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$input = $this->get_default_input();
$input = wpcf7_array_flatten( $input );
$input = wpcf7_exclude_blank( $input );
if ( empty( $input ) ) {
return $this->create_error();
}
return true;
}
}
@@ -0,0 +1,34 @@
<?php
namespace Contactable\SWV;
class RequiredFileRule extends Rule {
const rule_name = 'requiredfile';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['file'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$field = $this->get_property( 'field' );
$input = $_FILES[$field]['tmp_name'] ?? '';
$input = wpcf7_array_flatten( $input );
$input = wpcf7_exclude_blank( $input );
if ( empty( $input ) ) {
return $this->create_error();
}
return true;
}
}
@@ -0,0 +1,35 @@
<?php
namespace Contactable\SWV;
class TelRule extends Rule {
const rule_name = 'tel';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['text'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$input = $this->get_default_input();
$input = wpcf7_array_flatten( $input );
$input = wpcf7_exclude_blank( $input );
foreach ( $input as $i ) {
if ( ! wpcf7_is_tel( $i ) ) {
return $this->create_error();
}
}
return true;
}
}
@@ -0,0 +1,35 @@
<?php
namespace Contactable\SWV;
class TimeRule extends Rule {
const rule_name = 'time';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['text'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$input = $this->get_default_input();
$input = wpcf7_array_flatten( $input );
$input = wpcf7_exclude_blank( $input );
foreach ( $input as $i ) {
if ( ! wpcf7_is_time( $i ) ) {
return $this->create_error();
}
}
return true;
}
}
@@ -0,0 +1,35 @@
<?php
namespace Contactable\SWV;
class URLRule extends Rule {
const rule_name = 'url';
public function matches( $context ) {
if ( false === parent::matches( $context ) ) {
return false;
}
if ( empty( $context['text'] ) ) {
return false;
}
return true;
}
public function validate( $context ) {
$input = $this->get_default_input();
$input = wpcf7_array_flatten( $input );
$input = wpcf7_exclude_blank( $input );
foreach ( $input as $i ) {
if ( ! wpcf7_is_url( $i ) ) {
return $this->create_error();
}
}
return true;
}
}
@@ -0,0 +1,46 @@
<?php
trait WPCF7_SWV_SchemaHolder {
protected $schema;
/**
* Retrieves SWV schema for this holder object (contact form).
*
* @return WPCF7_SWV_Schema The schema object.
*/
public function get_schema() {
if ( isset( $this->schema ) ) {
return $this->schema;
}
$schema = new WPCF7_SWV_Schema( array(
'locale' => isset( $this->locale ) ? $this->locale : '',
) );
do_action( 'wpcf7_swv_create_schema', $schema, $this );
return $this->schema = $schema;
}
/**
* Validates form inputs based on the schema and given context.
*/
public function validate_schema( $context, WPCF7_Validation $validity ) {
$schema = $this->get_schema();
foreach ( $schema->validate( $context ) as $result ) {
if ( is_wp_error( $result ) ) {
$rule = $result->get_error_data();
$field = $rule->get_property( 'field' );
if ( isset( $field ) and $validity->is_valid( $field ) ) {
$validity->invalidate( $field, $result );
}
}
}
}
}
@@ -0,0 +1,26 @@
<?php
add_action(
'wp_enqueue_scripts',
static function () {
$assets = array();
$asset_file = wpcf7_plugin_path( 'includes/swv/js/index.asset.php' );
if ( file_exists( $asset_file ) ) {
$assets = include( $asset_file );
}
$assets = wp_parse_args( $assets, array(
'dependencies' => array(),
'version' => WPCF7_VERSION,
) );
wp_register_script( 'swv',
wpcf7_plugin_url( 'includes/swv/js/index.js' ),
$assets['dependencies'],
$assets['version'],
array( 'in_footer' => true )
);
},
10, 0
);
@@ -0,0 +1,164 @@
<?php
/**
* Schema-Woven Validation API
*/
require_once WPCF7_PLUGIN_DIR . '/includes/swv/schema-holder.php';
require_once WPCF7_PLUGIN_DIR . '/includes/swv/script-loader.php';
require_once WPCF7_PLUGIN_DIR . '/includes/swv/php/abstract-rules.php';
/**
* Returns an associative array of SWV rules.
*/
function wpcf7_swv_available_rules() {
$rules = array(
'required' => 'Contactable\SWV\RequiredRule',
'requiredfile' => 'Contactable\SWV\RequiredFileRule',
'email' => 'Contactable\SWV\EmailRule',
'url' => 'Contactable\SWV\URLRule',
'tel' => 'Contactable\SWV\TelRule',
'number' => 'Contactable\SWV\NumberRule',
'date' => 'Contactable\SWV\DateRule',
'time' => 'Contactable\SWV\TimeRule',
'file' => 'Contactable\SWV\FileRule',
'enum' => 'Contactable\SWV\EnumRule',
'dayofweek' => 'Contactable\SWV\DayofweekRule',
'minitems' => 'Contactable\SWV\MinItemsRule',
'maxitems' => 'Contactable\SWV\MaxItemsRule',
'minlength' => 'Contactable\SWV\MinLengthRule',
'maxlength' => 'Contactable\SWV\MaxLengthRule',
'minnumber' => 'Contactable\SWV\MinNumberRule',
'maxnumber' => 'Contactable\SWV\MaxNumberRule',
'mindate' => 'Contactable\SWV\MinDateRule',
'maxdate' => 'Contactable\SWV\MaxDateRule',
'minfilesize' => 'Contactable\SWV\MinFileSizeRule',
'maxfilesize' => 'Contactable\SWV\MaxFileSizeRule',
'all' => 'Contactable\SWV\AllRule',
'any' => 'Contactable\SWV\AnyRule',
);
return apply_filters( 'wpcf7_swv_available_rules', $rules );
}
add_action( 'wpcf7_init', 'wpcf7_swv_load_rules', 10, 0 );
/**
* Loads SWV fules.
*/
function wpcf7_swv_load_rules() {
$rules = wpcf7_swv_available_rules();
foreach ( array_keys( $rules ) as $rule ) {
$file = sprintf( '%s.php', $rule );
$path = path_join( WPCF7_PLUGIN_DIR . '/includes/swv/php/rules', $file );
if ( file_exists( $path ) ) {
include_once $path;
}
}
}
/**
* Creates an SWV rule object.
*
* @param string $rule_name Rule name.
* @param string|array $properties Optional. Rule properties.
* @return \Contactable\SWV\Rule|null The rule object, or null if it failed.
*/
function wpcf7_swv_create_rule( $rule_name, $properties = '' ) {
$rules = wpcf7_swv_available_rules();
if ( isset( $rules[$rule_name] ) ) {
return new $rules[$rule_name]( $properties );
}
}
/**
* Returns an associative array of JSON Schema for Contact Form 7 SWV.
*/
function wpcf7_swv_get_meta_schema() {
return array(
'$schema' => 'https://json-schema.org/draft/2020-12/schema',
'title' => 'Contact Form 7 SWV',
'description' => 'Contact Form 7 SWV meta-schema',
'type' => 'object',
'properties' => array(
'version' => array(
'type' => 'string',
),
'locale' => array(
'type' => 'string',
),
'rules' => array(
'type' => 'array',
'items' => array(
'type' => 'object',
'properties' => array(
'rule' => array(
'type' => 'string',
'enum' => array_keys( wpcf7_swv_available_rules() ),
),
'field' => array(
'type' => 'string',
'pattern' => '^[A-Za-z][-A-Za-z0-9_:]*$',
),
'error' => array(
'type' => 'string',
),
'accept' => array(
'type' => 'array',
'items' => array(
'type' => 'string',
),
),
'threshold' => array(
'type' => 'string',
),
),
'required' => array( 'rule' ),
),
),
),
);
}
/**
* The schema class as a composite rule.
*/
class WPCF7_SWV_Schema extends \Contactable\SWV\CompositeRule {
/**
* The human-readable version of the schema.
*/
const version = 'Contact Form 7 SWV Schema 2024-02';
/**
* Constructor.
*/
public function __construct( $properties = '' ) {
$this->properties = wp_parse_args( $properties, array(
'version' => self::version,
) );
}
/**
* Validates with this schema.
*
* @param array $context Context.
*/
public function validate( $context ) {
foreach ( $this->rules() as $rule ) {
if ( $rule->matches( $context ) ) {
yield $rule->validate( $context );
}
}
}
}