diff --git a/src/wp-includes/functions.php b/src/wp-includes/functions.php index 9a6938ed640de..006cd0b12da8b 100644 --- a/src/wp-includes/functions.php +++ b/src/wp-includes/functions.php @@ -7383,6 +7383,11 @@ function wp_is_stream( $path ) { * @return bool True if valid date, false if not valid date. */ function wp_checkdate( $month, $day, $year, $source_date ) { + + $checkdate = false; + if ( is_numeric( $month ) && is_numeric( $day ) && is_numeric( $year ) ) { + $checkdate = checkdate( intval( $month ), intval( $day ), intval( $year ) ); + } /** * Filters whether the given date is valid for the Gregorian calendar. * @@ -7391,7 +7396,7 @@ function wp_checkdate( $month, $day, $year, $source_date ) { * @param bool $checkdate Whether the given date is valid. * @param string $source_date Date to check. */ - return apply_filters( 'wp_checkdate', checkdate( $month, $day, $year ), $source_date ); + return apply_filters( 'wp_checkdate', $checkdate, $source_date ); } /** diff --git a/src/wp-includes/post.php b/src/wp-includes/post.php index 58504e140a139..87c02e294135a 100644 --- a/src/wp-includes/post.php +++ b/src/wp-includes/post.php @@ -5348,11 +5348,12 @@ function wp_resolve_post_date( $post_date = '', $post_date_gmt = '' ) { } // Validate the date. - $month = (int) substr( $post_date, 5, 2 ); - $day = (int) substr( $post_date, 8, 2 ); - $year = (int) substr( $post_date, 0, 4 ); + preg_match( "/^(?P[0-9]{4})-(?P0[1-9]|1[0-2])-(?P0[1-9]|[1-2][0-9]|3[0-1])/", $post_date, $matches ); - $valid_date = wp_checkdate( $month, $day, $year, $post_date ); + if ( empty( $matches ) || ! is_array( $matches ) || count( $matches ) < 4 ) { + return false; + } + $valid_date = wp_checkdate( $matches['month'], $matches['day'], $matches['year'], $post_date ); if ( ! $valid_date ) { return false; diff --git a/tests/phpunit/tests/post.php b/tests/phpunit/tests/post.php index 6e0207add28de..2e87bf02d546a 100644 --- a/tests/phpunit/tests/post.php +++ b/tests/phpunit/tests/post.php @@ -756,4 +756,237 @@ public function test_use_block_editor_for_post() { $this->assertTrue( use_block_editor_for_post( $restless_post_id ) ); remove_filter( 'use_block_editor_for_post', '__return_true' ); } + + /** + * @ticket 26798 + * + * @dataProvider data_wp_insert_post_handle_malformed_post_date + * + * The purpose of this test is to ensure that invalid dates do not + * cause PHP errors when wp_insert_post() is called, and that the + * posts are not actually "inserted" (created). + */ + public function test_wp_insert_post_handle_malformed_post_date( $input, $expected ) { + $post = array( + 'post_author' => self::$editor_id, + 'post_status' => 'publish', + 'post_content' => 'content', + 'post_title' => 'title', + 'post_date' => $input, + ); + // Inserting the post should fail gracefully. + $id = wp_insert_post( $post ); + // Check if the result is "0" or not. + $result = ! empty( $id ); + $this->assertEquals( $result, $expected ); + } + + /** + * @ticket 26798 + */ + public function data_wp_insert_post_handle_malformed_post_date() { + return array( + array( + '2012-01-01', + true, + ), + // 24-hour time format. + array( + '2012-01-01 13:00:00', + true, + ), + // ISO8601 date with timezone. + array( + '2016-01-16T00:00:00Z', + true, + ), + // ISO8601 date with timezone offset. + array( + '2016-01-16T00:00:00+0100', + true, + ), + // RFC3339 Format. + array( + '1970-01-01T01:00:00+01:00', + true, + ), + // RSS Format + array( + '1970-01-01T01:00:00+0100', + true, + ), + // Leap year. + array( + '2012-02-29', + true, + ), + // Strange formats. + array( + '2012-01-01 0', + true, + ), + array( + '2012-01-01 25:00:00', + true, + ), + array( + '2012-01-01 00:60:00', + true, + ), + // Failures. + array( + '2012-08-0z', + false, + ), + array( + '2012-08-1', + false, + ), + array( + '201-01-08 00:00:00', + false, + ), + array( + '201-01-08 00:60:00', + false, + ), + array( + '201a-01-08 00:00:00', + false, + ), + array( + '2012-1-08 00:00:00', + false, + ), + array( + '2012-31-08 00:00:00', + false, + ), + array( + '2012-01-8 00:00:00', + false, + ), + array( + '2012-01-48 00:00:00', + false, + ), + // Not a leap year. + array( + '2011-02-29', + false, + ), + ); + } + + /** + * @ticket 26798 + * + * @dataProvider data_wp_resolve_post_date_regex + * + * Tests the regex inside of wp_resolve_post_date(), with + * the emphasis on the date format (not the time). + */ + public function test_wp_resolve_post_date_regex( $date, $expected ) { + $out = wp_resolve_post_date( $date ); + $this->assertEquals( $out, $expected ); + } + + /** + * @ticket 26798 + */ + public function data_wp_resolve_post_date_regex() { + return array( + array( + '2012-01-01', + '2012-01-01', + ), + array( + '2012-01-01 00:00:00', + '2012-01-01 00:00:00', + ), + // ISO8601 date with timezone. + array( + '2016-01-16T00:00:00Z', + '2016-01-16T00:00:00Z', + ), + // ISO8601 date with timezone offset. + array( + '2016-01-16T00:00:00+0100', + '2016-01-16T00:00:00+0100', + ), + // RFC3339 Format. + array( + '1970-01-01T01:00:00+01:00', + '1970-01-01T01:00:00+01:00', + ), + // RSS Format + array( + '1970-01-01T01:00:00+0100', + '1970-01-01T01:00:00+0100', + ), + // 24-hour time format. + array( + '2012-01-01 13:00:00', + '2012-01-01 13:00:00', + ), + array( + '2016-01-16T00:0', + '2016-01-16T00:0', + ), + array( + '2012-01-01 0', + '2012-01-01 0', + ), + array( + '2012-01-01 00:00', + '2012-01-01 00:00', + ), + array( + '2012-01-01 25:00:00', + '2012-01-01 25:00:00', + ), + array( + '2012-01-01 00:60:00', + '2012-01-01 00:60:00', + ), + array( + '2012-01-01 00:00:60', + '2012-01-01 00:00:60', + ), + array( + '201-01-08', + false, + ), + array( + '201a-01-08', + false, + ), + array( + '2012-1-08', + false, + ), + array( + '2012-31-08', + false, + ), + array( + '2012-01-8', + false, + ), + array( + '2012-01-48 00:00:00', + false, + ), + // Leap year. + array( + '2012-02-29', + '2012-02-29', + ), + array( + '2011-02-29', + false, + ), + ); + } + }