diff --git a/includes/fields/class-acf-field-url.php b/includes/fields/class-acf-field-url.php index 8333bda6..f54d7009 100644 --- a/includes/fields/class-acf-field-url.php +++ b/includes/fields/class-acf-field-url.php @@ -129,6 +129,11 @@ public function validate_value( $valid, $value, $field, $input ) { return $valid; } + // A non-string value (e.g. an array from a crafted submission) is never a valid URL. + if ( ! is_string( $value ) ) { + return __( 'Value must be a valid URL', 'secure-custom-fields' ); + } + if ( strpos( $value, '://' ) !== false ) { // url @@ -156,7 +161,8 @@ public function validate_value( $valid, $value, $field, $input ) { */ public function format_value( $value, $post_id, $field, $escape_html ) { if ( $escape_html ) { - return esc_url( $value ); + // esc_url() expects a string; treat a non-string value as empty. + return is_string( $value ) ? esc_url( $value ) : ''; } return $value; } diff --git a/tests/php/includes/fields/test-class-acf-field-url.php b/tests/php/includes/fields/test-class-acf-field-url.php index a3e3894d..73754fcb 100644 --- a/tests/php/includes/fields/test-class-acf-field-url.php +++ b/tests/php/includes/fields/test-class-acf-field-url.php @@ -137,6 +137,35 @@ public function test_validate_value_empty_required() { $this->assertTrue( $valid ); } + /** + * Test validate_value does not crash on a non-scalar value. + * + * A crafted form submission can deliver an array (e.g. acf[field_key][]) + * as the value. The field should treat it as invalid rather than raising + * a TypeError from strpos(). + */ + public function test_validate_value_non_scalar() { + $field = $this->get_field( array( 'required' => 1 ) ); + + $valid = $this->field_instance->validate_value( true, array( 'a' => 'b' ), $field, 'acf[field_url_test]' ); + + $this->assertEquals( __( 'Value must be a valid URL', 'secure-custom-fields' ), $valid ); + } + + /** + * Test format_value does not crash on a non-scalar value when escaping. + * + * Calling esc_url() on an array would raise a TypeError. The field should + * return an empty string, matching how it treats an empty value. + */ + public function test_format_value_non_scalar_escaped() { + $field = $this->get_field(); + + $result = $this->field_instance->format_value( array( 'a' => 'b' ), $this->post_id, $field, true ); + + $this->assertEquals( '', $result ); + } + /** * Test get_rest_schema returns valid schema. */