arraypress/wp-sanitize-utils

A lean WordPress library for sanitization and validation utilities

dev-main 2025-07-16 13:26 UTC

This package is auto-updated.

Last update: 2025-09-02 10:37:15 UTC


README

A lean WordPress library for sanitization and validation utilities. Provides essential tools for cleaning user input and validating data with WordPress integration.

Installation

composer require arraypress/wp-clean-utils

Quick Start

use ArrayPress\CleanUtils\Sanitize;
use ArrayPress\CleanUtils\Validate;

// Sanitization
$clean_email  = Sanitize::email( ' USER@EXAMPLE.COM ' );    // "user@example.com"
$clean_amount = Sanitize::amount( '$1,234.56' );           // "1234.56"
$safe_html    = Sanitize::html( '<p>Safe content</p>' );      // Allows safe HTML

// Validation
$is_valid_email = Validate::email( 'user@example.com' );   // true
$is_in_range    = Validate::range( 15, 10, 20 );             // true
$missing_fields = Validate::required_fields( $data, [ 'name', 'email' ] ); // []

Sanitize Class

Core Sanitization

// Basic text cleaning
Sanitize::text( '  Hello World!  ' );          // "Hello World!"
Sanitize::clean( $dirty_data );                // Recursively clean arrays
Sanitize::email( ' USER@EXAMPLE.COM ' );       // "user@example.com"
Sanitize::url( 'https://example.com/path' );   // Clean URL
Sanitize::html( '<p>Content</p><script>' );    // Safe HTML only

// WordPress-specific
Sanitize::slug( 'Product Name Here' );         // "product-name-here"
Sanitize::username( 'User.Name!' );            // "user.name"
Sanitize::key( 'my-option_key' );              // "my-option_key"

Specialized Sanitization

// Numbers and amounts
Sanitize::int( '123.45' );                     // 123
Sanitize::float( '123.45' );                   // 123.45
Sanitize::amount( '$1,234.56' );               // "1234.56"
Sanitize::percentage( '125%' );                // 100.0 (clamped to 0-100)

// Lists and arrays
Sanitize::comma_list( 'item1, item2, item3' ); // ['item1', 'item2', 'item3']
Sanitize::emails( 'user1@ex.com,user2@ex.com' ); // ['user1@ex.com', 'user2@ex.com']
Sanitize::object_ids( [ 1, '2', 3, 'invalid' ] ); // [1, 2, 3]

// Ranges and constraints
Sanitize::range( 150, 0, 100 );                // 100.0 (clamped to range)
Sanitize::rating( '7', 1, 5 );                 // 5 (clamped to 1-5)

Business-Specific

// E-commerce
Sanitize::discount_type( 'Percentage' );       // "percentage"
Sanitize::status( 'Active' );                  // "active"

// Dates and times
Sanitize::date( '2024-01-15 10:30' );          // "2024-01-15 10:30:00"
Sanitize::time( '25:70' );                     // "" (invalid)
Sanitize::timezone( 'America/New_York' );      // "America/New_York"

// Technical
Sanitize::hex_color( '#FF0000' );              // "#ff0000"
Sanitize::phone( '+1 (555) 123-4567' );        // "+1 (555) 123-4567"
Sanitize::ip( '192.168.1.1' );                 // "192.168.1.1"

Validate Class

Basic Validation

// Required fields
Validate::required( '' );                      // false
Validate::required( '0' );                     // true
Validate::required( [] );                      // false

// Data types
Validate::email( 'user@example.com' );         // true
Validate::url( 'https://example.com' );        // true
Validate::numeric( '123.45' );                // true
Validate::integer( '123' );                    // true

Range and Constraints

// Numeric ranges
Validate::min( 15, 10 );                       // true (15 >= 10)
Validate::max( 15, 20 );                       // true (15 <= 20)
Validate::range( 15, 10, 20 );                 // true (10 <= 15 <= 20)
Validate::percentage( 85 );                    // true (0-100)

// String length
Validate::length( 'hello', 10, 3 );            // true (3 <= 5 <= 10)

// Options validation
Validate::in( 'active', [ 'active', 'inactive' ] ); // true

Specialized Validation

// Dates and times
Validate::date( '2024-01-15' );                // true
Validate::time( '14:30' );                     // true
Validate::timezone( 'America/New_York' );      // true

// Technical formats
Validate::hex_color( '#FF0000' );              // true
Validate::uuid( '550e8400-e29b-41d4-a716-446655440000' ); // true
Validate::json( '{"valid": true}' );           // true
Validate::phone( '+1-555-123-4567' );          // true

// WordPress-specific
Validate::username( 'valid_user' );            // true
Validate::slug( 'valid-slug' );                // true

Advanced Validation

// Password strength
Validate::strong_password( 'MyPass123!', 8, true, true, true, true ); // true

// Credit card (Luhn algorithm)
Validate::credit_card( '4532015112830366' );   // true

// Multiple required fields
$data    = [ 'name' => 'John', 'email' => 'john@example.com' ];
$missing = Validate::required_fields( $data, [ 'name', 'email', 'phone' ] );
// Returns: ['phone']

// Pattern matching
Validate::matches_pattern( 'ABC123', '/^[A-Z]{3}\d{3}$/' ); // true

Real-World Examples

Form Processing

// Clean and validate contact form
$data = [
	'name'    => $_POST['name'] ?? '',
	'email'   => $_POST['email'] ?? '',
	'phone'   => $_POST['phone'] ?? '',
	'message' => $_POST['message'] ?? ''
];

// Sanitize inputs
$clean_data = [
	'name'    => Sanitize::text( $data['name'] ),
	'email'   => Sanitize::email( $data['email'] ),
	'phone'   => Sanitize::phone( $data['phone'] ),
	'message' => Sanitize::textarea( $data['message'] )
];

// Validate required fields
$missing = Validate::required_fields( $clean_data, [ 'name', 'email' ] );
if ( ! empty( $missing ) ) {
	wp_die( 'Missing required fields: ' . implode( ', ', $missing ) );
}

// Validate email format
if ( ! Validate::email( $clean_data['email'] ) ) {
	wp_die( 'Invalid email address' );
}

E-commerce Product Management

// Clean product data
$product_data = [
	'name'           => Sanitize::text( $_POST['product_name'] ),
	'slug'           => Sanitize::slug( $_POST['product_slug'] ),
	'price'          => Sanitize::amount( $_POST['price'] ),
	'discount_type'  => Sanitize::discount_type( $_POST['discount_type'] ),
	'discount_value' => Sanitize::percentage( $_POST['discount_value'] ),
	'status'         => Sanitize::status( $_POST['status'] ),
	'categories'     => Sanitize::object_ids( $_POST['categories'] )
];

// Validate business rules
if ( ! Validate::min( $product_data['price'], 0.01 ) ) {
	wp_die( 'Price must be greater than $0.00' );
}

if ( $product_data['discount_type'] === 'percentage' &&
     ! Validate::percentage( $product_data['discount_value'] ) ) {
	wp_die( 'Discount percentage must be between 0-100%' );
}

User Registration

// Process user registration
$user_data = [
	'username'   => Sanitize::username( $_POST['username'] ),
	'email'      => Sanitize::email( $_POST['email'] ),
	'password'   => $_POST['password'], // Don't sanitize passwords
	'first_name' => Sanitize::text( $_POST['first_name'] ),
	'last_name'  => Sanitize::text( $_POST['last_name'] )
];

// Validate username
if ( ! Validate::username( $user_data['username'] ) ) {
	wp_die( 'Invalid username format' );
}

// Validate email
if ( ! Validate::email( $user_data['email'] ) ) {
	wp_die( 'Invalid email address' );
}

// Validate password strength
if ( ! Validate::strong_password( $user_data['password'], 8 ) ) {
	wp_die( 'Password must be at least 8 characters with uppercase, lowercase, number, and special character' );
}

// Check if username/email already exists
if ( username_exists( $user_data['username'] ) ) {
	wp_die( 'Username already exists' );
}

if ( email_exists( $user_data['email'] ) ) {
	wp_die( 'Email already registered' );
}

Settings Page

// Clean and validate settings
$settings = [
	'site_email'         => Sanitize::email( $_POST['site_email'] ),
	'items_per_page'     => Sanitize::int_range( $_POST['items_per_page'], 1, 100 ),
	'currency_symbol'    => Sanitize::text( $_POST['currency_symbol'] ),
	'allowed_file_types' => Sanitize::comma_list( $_POST['allowed_file_types'] ),
	'primary_color'      => Sanitize::hex_color( $_POST['primary_color'] ),
	'enable_feature'     => Sanitize::bool( $_POST['enable_feature'] )
];

// Validate critical settings
if ( ! Validate::email( $settings['site_email'] ) ) {
	add_settings_error( 'settings', 'invalid_email', 'Invalid email address' );
}

if ( ! Validate::range( $settings['items_per_page'], 1, 100 ) ) {
	add_settings_error( 'settings', 'invalid_range', 'Items per page must be between 1-100' );
}

// Save if valid
if ( empty( get_settings_errors() ) ) {
	update_option( 'my_plugin_settings', $settings );
}

API Data Processing

// Clean incoming API data
$api_data = json_decode( file_get_contents( 'php://input' ), true );

$clean_api_data = [
	'id'       => Sanitize::absint( $api_data['id'] ?? 0 ),
	'title'    => Sanitize::string_length( $api_data['title'] ?? '', 100 ),
	'content'  => Sanitize::html( $api_data['content'] ?? '' ),
	'status'   => Sanitize::option( $api_data['status'] ?? '', [ 'draft', 'published' ], 'draft' ),
	'tags'     => Sanitize::comma_list( $api_data['tags'] ?? '' ),
	'metadata' => Sanitize::json( $api_data['metadata'] ?? '{}' )
];

// Validate required fields
$required = [ 'id', 'title' ];
$missing  = Validate::required_fields( $clean_api_data, $required );

if ( ! empty( $missing ) ) {
	wp_send_json_error( [ 'message' => 'Missing required fields', 'fields' => $missing ] );
}

// Additional validation
if ( ! Validate::length( $clean_api_data['title'], 100, 1 ) ) {
	wp_send_json_error( [ 'message' => 'Title must be 1-100 characters' ] );
}

Security Best Practices

// ✅ Always sanitize user input
$clean_input = Sanitize::text( $_POST['user_input'] );

// ✅ Validate after sanitizing
if ( ! Validate::required( $clean_input ) ) {
	wp_die( 'Input is required' );
}

// ✅ Use appropriate sanitization for data type
$email  = Sanitize::email( $_POST['email'] );
$amount = Sanitize::amount( $_POST['price'] );
$html   = Sanitize::html( $_POST['content'] );

// ✅ Validate business rules
if ( ! Validate::min( $amount, 0 ) ) {
	wp_die( 'Amount must be positive' );
}

// ❌ Never trust user input without sanitization
// $unsafe = $_POST['data']; // Don't do this

// ❌ Don't sanitize passwords (just validate)
// $password = Sanitize::text($_POST['password']); // Wrong!

Requirements

  • PHP 7.4+
  • WordPress 5.0+

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is licensed under the GPL-2.0-or-later License.

Support