/onload * handler, and stock WordPress already excludes it from * wp_handle_upload()'s default MIME allowlist for the same reason. */ const DANGEROUS_EXTENSIONS = [ 'php', 'php3', 'php4', 'php5', 'php7', 'phtml', 'pht', 'phar', 'exe', 'sh', 'cgi', 'asp', 'aspx', 'js', 'jsp', 'htaccess', 'py', 'rb', 'svg', 'svgz', 'html', 'htm' ]; /** A generic File field with no allowedExtensions configured falls back to this rather than "anything wp_handle_upload()'s own MIME list allows". */ const DEFAULT_ALLOWED_EXTENSIONS = [ 'jpg', 'jpeg', 'png', 'gif', 'webp', 'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'csv', 'txt', 'zip' ]; /** Image Upload is restricted to actual image extensions regardless of the field's own allowedExtensions — the field type is a promise to visitors and to whatever displays the result, not just a filter. */ const IMAGE_EXTENSIONS = [ 'jpg', 'jpeg', 'png', 'gif', 'webp' ]; /** * `$file` is one $_FILES-shaped entry: `['name','type','tmp_name', * 'error','size']`. Returns a translated error message, or null when * the file passes every check. Never touches the filesystem itself — * purely inspects the metadata PHP already parsed from the upload. */ public static function validate( array $field, array $file ) { if ( UPLOAD_ERR_OK !== ( $file['error'] ?? UPLOAD_ERR_NO_FILE ) ) { return __( 'There was a problem uploading your file. Please try again.', 'chargeforms' ); } $max_bytes = (int) ( $field['maxSizeMb'] ?? 5 ) * MB_IN_BYTES; if ( ( $file['size'] ?? 0 ) > $max_bytes ) { return Settings::get( 'validation_msg_file_size', __( 'Validation fails for maximum file size', 'chargeforms' ) ); } $ext = strtolower( pathinfo( (string) ( $file['name'] ?? '' ), PATHINFO_EXTENSION ) ); if ( in_array( $ext, self::DANGEROUS_EXTENSIONS, true ) ) { return __( 'That file type is not allowed.', 'chargeforms' ); } $allowed = in_array( $field['type'] ?? '', [ 'image_upload', 'featured_image' ], true ) ? self::IMAGE_EXTENSIONS : ( array_filter( array_map( 'trim', explode( ',', $field['allowedExtensions'] ?? '' ) ) ) ?: self::DEFAULT_ALLOWED_EXTENSIONS ); if ( ! empty( $allowed ) && ! in_array( $ext, array_map( 'strtolower', $allowed ), true ) ) { $message_key = 'image_upload' === $field['type'] ? 'validation_msg_image_type' : 'validation_msg_file_type'; $default = 'image_upload' === $field['type'] ? __( 'Allowed image types does not match', 'chargeforms' ) : __( 'Invalid file type', 'chargeforms' ); return Settings::get( $message_key, $default ); } return null; } }