Make WordPress Core

Ticket #34059: 34059.2.diff

File 34059.2.diff, 19.9 KB (added by johnbillion, 9 years ago)
  • src/wp-comments-post.php

     
    1717
    1818nocache_headers();
    1919
    20 $comment_post_ID = isset($_POST['comment_post_ID']) ? (int) $_POST['comment_post_ID'] : 0;
    21 
    22 $post = get_post($comment_post_ID);
    23 
    24 if ( empty( $post->comment_status ) ) {
    25         /**
    26          * Fires when a comment is attempted on a post that does not exist.
    27          *
    28          * @since 1.5.0
    29          *
    30          * @param int $comment_post_ID Post ID.
    31          */
    32         do_action( 'comment_id_not_found', $comment_post_ID );
    33         exit;
    34 }
    35 
    36 // get_post_status() will get the parent status for attachments.
    37 $status = get_post_status($post);
    38 
    39 $status_obj = get_post_status_object($status);
    40 
    41 if ( ! comments_open( $comment_post_ID ) ) {
    42         /**
    43          * Fires when a comment is attempted on a post that has comments closed.
    44          *
    45          * @since 1.5.0
    46          *
    47          * @param int $comment_post_ID Post ID.
    48          */
    49         do_action( 'comment_closed', $comment_post_ID );
    50         wp_die( __( 'Sorry, comments are closed for this item.' ), 403 );
    51 } elseif ( 'trash' == $status ) {
    52         /**
    53          * Fires when a comment is attempted on a trashed post.
    54          *
    55          * @since 2.9.0
    56          *
    57          * @param int $comment_post_ID Post ID.
    58          */
    59         do_action( 'comment_on_trash', $comment_post_ID );
    60         exit;
    61 } elseif ( ! $status_obj->public && ! $status_obj->private ) {
    62         /**
    63          * Fires when a comment is attempted on a post in draft mode.
    64          *
    65          * @since 1.5.1
    66          *
    67          * @param int $comment_post_ID Post ID.
    68          */
    69         do_action( 'comment_on_draft', $comment_post_ID );
    70         exit;
    71 } elseif ( post_password_required( $comment_post_ID ) ) {
    72         /**
    73          * Fires when a comment is attempted on a password-protected post.
    74          *
    75          * @since 2.9.0
    76          *
    77          * @param int $comment_post_ID Post ID.
    78          */
    79         do_action( 'comment_on_password_protected', $comment_post_ID );
    80         exit;
    81 } else {
    82         /**
    83          * Fires before a comment is posted.
    84          *
    85          * @since 2.8.0
    86          *
    87          * @param int $comment_post_ID Post ID.
    88          */
    89         do_action( 'pre_comment_on_post', $comment_post_ID );
    90 }
    91 
    92 $comment_author       = ( isset( $_POST['author'] ) && is_string( $_POST['author'] ) ) ? trim( strip_tags( $_POST['author'] ) ) : null;
    93 $comment_author_email = ( isset( $_POST['email'] ) && is_string( $_POST['email'] ) ) ? trim( $_POST['email'] ) : null;
    94 $comment_author_url   = ( isset( $_POST['url'] ) && is_string( $_POST['url'] ) ) ? trim( $_POST['url'] ) : null;
    95 $comment_content      = ( isset( $_POST['comment'] ) && is_string( $_POST['comment'] ) ) ? trim( $_POST['comment'] ) : null;
    96 
    97 // If the user is logged in
    98 $user = wp_get_current_user();
    99 if ( $user->exists() ) {
    100         if ( empty( $user->display_name ) )
    101                 $user->display_name=$user->user_login;
    102         $comment_author       = wp_slash( $user->display_name );
    103         $comment_author_email = wp_slash( $user->user_email );
    104         $comment_author_url   = wp_slash( $user->user_url );
    105         if ( current_user_can( 'unfiltered_html' ) ) {
    106                 if ( ! isset( $_POST['_wp_unfiltered_html_comment'] )
    107                         || ! wp_verify_nonce( $_POST['_wp_unfiltered_html_comment'], 'unfiltered-html-comment_' . $comment_post_ID )
    108                 ) {
    109                         kses_remove_filters(); // start with a clean slate
    110                         kses_init_filters(); // set up the filters
    111                 }
    112         }
    113 } else {
    114         if ( get_option( 'comment_registration' ) || 'private' == $status ) {
    115                 wp_die( __( 'Sorry, you must be logged in to post a comment.' ), 403 );
     20$comment = wp_handle_comment_post( wp_unslash( $_POST ) );
     21if ( is_wp_error( $comment ) ) {
     22        $data = $comment->get_error_data();
     23        if ( ! empty( $data ) ) {
     24                wp_die( $comment->get_error_message(), $data );
     25        } else {
     26                exit;
    11627        }
    11728}
    11829
    119 $comment_type = '';
    120 
    121 if ( get_option('require_name_email') && !$user->exists() ) {
    122         if ( 6 > strlen( $comment_author_email ) || '' == $comment_author ) {
    123                 wp_die( __( '<strong>ERROR</strong>: please fill the required fields (name, email).' ), 200 );
    124         } elseif ( ! is_email( $comment_author_email ) ) {
    125                 wp_die( __( '<strong>ERROR</strong>: please enter a valid email address.' ), 200 );
    126         }
    127 }
    128 
    129 if ( '' == $comment_content ) {
    130         wp_die( __( '<strong>ERROR</strong>: please type a comment.' ), 200 );
    131 }
    132 
    133 $comment_parent = isset($_POST['comment_parent']) ? absint($_POST['comment_parent']) : 0;
    134 
    135 $commentdata = compact('comment_post_ID', 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_content', 'comment_type', 'comment_parent', 'user_ID');
    136 
    137 $comment_id = wp_new_comment( $commentdata );
    138 if ( ! $comment_id ) {
    139         wp_die( __( "<strong>ERROR</strong>: The comment could not be saved. Please try again later." ) );
    140 }
    141 
    142 $comment = get_comment( $comment_id );
     30$user = wp_get_current_user();
    14331
    14432/**
    14533 * Perform other actions when comment cookies are set.
     
    15139 */
    15240do_action( 'set_comment_cookies', $comment, $user );
    15341
    154 $location = empty($_POST['redirect_to']) ? get_comment_link( $comment ) : $_POST['redirect_to'] . '#comment-' . $comment_id;
     42$location = empty( $_POST['redirect_to'] ) ? get_comment_link( $comment ) : $_POST['redirect_to'] . '#comment-' . $comment->comment_ID;
    15543
    15644/**
    15745 * Filter the location URI to send the commenter after posting.
  • tests/phpunit/tests/comments-post.php

     
     1<?php
     2
     3/**
     4 * @group comment
     5 */
     6class Tests_Comments_Post extends WP_UnitTestCase {
     7
     8        function setUp() {
     9                parent::setUp();
     10                require_once ABSPATH . WPINC . '/class-phpass.php';
     11        }
     12
     13        function tearDown() {
     14                wp_set_current_user( 0 );
     15                parent::tearDown();
     16        }
     17
     18        public function test_posting_comment_to_invalid_post_returns_error() {
     19
     20                $error = 'comment_id_not_found';
     21
     22                $this->assertSame( 0, did_action( $error ) );
     23
     24                $data = array(
     25                        'comment_post_ID' => 0,
     26                );
     27                $comment = wp_handle_comment_post( $data );
     28
     29                $this->assertSame( 1, did_action( $error ) );
     30                $this->assertWPError( $comment );
     31                $this->assertSame( $error, $comment->get_error_code() );
     32
     33        }
     34
     35        public function test_posting_comment_to_post_with_closed_comments_returns_error() {
     36
     37                $error = 'comment_closed';
     38
     39                $this->assertSame( 0, did_action( $error ) );
     40
     41                $post = $this->factory->post->create_and_get( array(
     42                        'comment_status' => 'closed',
     43                ) );
     44                $data = array(
     45                        'comment_post_ID' => $post->ID,
     46                );
     47                $comment = wp_handle_comment_post( $data );
     48
     49                $this->assertSame( 1, did_action( $error ) );
     50                $this->assertWPError( $comment );
     51                $this->assertSame( $error, $comment->get_error_code() );
     52
     53        }
     54
     55        public function test_posting_comment_to_trashed_post_returns_error() {
     56
     57                $error = 'comment_on_trash';
     58
     59                $this->assertSame( 0, did_action( $error ) );
     60
     61                $post = $this->factory->post->create_and_get();
     62                wp_trash_post( $post );
     63                $data = array(
     64                        'comment_post_ID' => $post->ID,
     65                );
     66                $comment = wp_handle_comment_post( $data );
     67
     68                $this->assertSame( 1, did_action( $error ) );
     69                $this->assertWPError( $comment );
     70                $this->assertSame( $error, $comment->get_error_code() );
     71
     72        }
     73
     74        public function test_posting_comment_to_draft_post_returns_error() {
     75
     76                $error = 'comment_on_draft';
     77
     78                $this->assertSame( 0, did_action( $error ) );
     79
     80                $post = $this->factory->post->create_and_get( array(
     81                        'post_status' => 'draft',
     82                ) );
     83                $data = array(
     84                        'comment_post_ID' => $post->ID,
     85                );
     86                $comment = wp_handle_comment_post( $data );
     87
     88                $this->assertSame( 1, did_action( $error ) );
     89                $this->assertWPError( $comment );
     90                $this->assertSame( $error, $comment->get_error_code() );
     91
     92        }
     93
     94        public function test_posting_comment_to_scheduled_post_returns_error() {
     95
     96                // Same error as commenting on a draft
     97                $error = 'comment_on_draft';
     98
     99                $this->assertSame( 0, did_action( $error ) );
     100
     101                $post = $this->factory->post->create_and_get( array(
     102                        'post_date' => date( 'Y-m-d H:i:s', strtotime( '+1 day' ) ),
     103                ) );
     104
     105                $this->assertSame( 'future', $post->post_status );
     106
     107                $data = array(
     108                        'comment_post_ID' => $post->ID,
     109                );
     110                $comment = wp_handle_comment_post( $data );
     111
     112                $this->assertSame( 1, did_action( $error ) );
     113                $this->assertWPError( $comment );
     114                $this->assertSame( $error, $comment->get_error_code() );
     115
     116        }
     117
     118        public function test_posting_comment_to_password_required_post_returns_error() {
     119
     120                $error = 'comment_on_password_protected';
     121
     122                $this->assertSame( 0, did_action( $error ) );
     123
     124                $post = $this->factory->post->create_and_get( array(
     125                        'post_password' => 'password',
     126                ) );
     127                $data = array(
     128                        'comment_post_ID' => $post->ID,
     129                );
     130                $comment = wp_handle_comment_post( $data );
     131
     132                $this->assertSame( 1, did_action( $error ) );
     133                $this->assertWPError( $comment );
     134                $this->assertSame( $error, $comment->get_error_code() );
     135
     136        }
     137
     138        public function test_posting_comment_to_password_protected_post_succeeds() {
     139
     140                $password = 'password';
     141                $hasher   = new PasswordHash( 8, true );
     142
     143                $_COOKIE['wp-postpass_' . COOKIEHASH] = $hasher->HashPassword( $password );
     144
     145                $post = $this->factory->post->create_and_get( array(
     146                        'post_password' => $password,
     147                ) );
     148                $data = array(
     149                        'comment_post_ID' => $post->ID,
     150                        'comment'         => 'Comment',
     151                        'author'          => 'Comment Author',
     152                        'email'           => 'comment@example.org',
     153                );
     154                $comment = wp_handle_comment_post( $data );
     155
     156                unset( $_COOKIE['wp-postpass_' . COOKIEHASH] );
     157
     158                $this->assertNotWPError( $comment );
     159                $this->assertInstanceOf( 'WP_Comment', $comment );
     160
     161        }
     162
     163        public function test_posting_valid_comment_as_logged_in_user_succeeds() {
     164
     165                $user = $this->factory->user->create_and_get( array(
     166                        'user_url' => 'http://user.example.org'
     167                ) );
     168
     169                wp_set_current_user( $user->ID );
     170
     171                $post = $this->factory->post->create_and_get();
     172                $data = array(
     173                        'comment_post_ID' => $post->ID,
     174                        'comment'         => 'Comment',
     175                );
     176                $comment = wp_handle_comment_post( $data );
     177
     178                $this->assertNotWPError( $comment );
     179                $this->assertInstanceOf( 'WP_Comment', $comment );
     180
     181                $this->assertSame( 'Comment', $comment->comment_content);
     182                $this->assertSame( $user->display_name, $comment->comment_author );
     183                $this->assertSame( $user->user_email, $comment->comment_author_email );
     184                $this->assertSame( $user->user_url, $comment->comment_author_url );
     185
     186        }
     187
     188        public function test_posting_valid_comment_anonymously_succeeds() {
     189
     190                $post = $this->factory->post->create_and_get();
     191                $data = array(
     192                        'comment_post_ID' => $post->ID,
     193                        'comment'         => 'Comment',
     194                        'author'          => 'Comment Author',
     195                        'email'           => 'comment@example.org',
     196                        'url'             => 'user.example.org'
     197                );
     198                $comment = wp_handle_comment_post( $data );
     199
     200                $this->assertNotWPError( $comment );
     201                $this->assertInstanceOf( 'WP_Comment', $comment );
     202
     203                $this->assertSame( 'Comment', $comment->comment_content);
     204                $this->assertSame( 'Comment Author', $comment->comment_author );
     205                $this->assertSame( 'comment@example.org', $comment->comment_author_email );
     206                $this->assertSame( 'http://user.example.org', $comment->comment_author_url );
     207
     208        }
     209
     210        public function test_posting_comment_anonymously_to_private_post_returns_error() {
     211
     212                $error = 'not_logged_in';
     213
     214                $post = $this->factory->post->create_and_get( array(
     215                        'post_status' => 'private',
     216                ) );
     217                $data = array(
     218                        'comment_post_ID' => $post->ID,
     219                );
     220                $comment = wp_handle_comment_post( $data );
     221
     222                $this->assertFalse( is_user_logged_in() );
     223                $this->assertWPError( $comment );
     224                $this->assertSame( $error, $comment->get_error_code() );
     225
     226        }
     227
     228        public function test_posting_comment_to_own_private_post_succeeds() {
     229
     230                $user = $this->factory->user->create_and_get();
     231
     232                wp_set_current_user( $user->ID );
     233
     234                $post = $this->factory->post->create_and_get( array(
     235                        'post_status' => 'private',
     236                        'post_author' => $user->ID,
     237                ) );
     238                $data = array(
     239                        'comment_post_ID' => $post->ID,
     240                        'comment'         => 'Comment',
     241                );
     242                $comment = wp_handle_comment_post( $data );
     243
     244                $this->assertTrue( current_user_can( 'read_post', $post->ID ) );
     245                $this->assertNotWPError( $comment );
     246                $this->assertInstanceOf( 'WP_Comment', $comment );
     247
     248        }
     249
     250        public function test_posting_comment_to_accessible_private_post_succeeds() {
     251
     252                $author = $this->factory->user->create_and_get( array(
     253                        'role' => 'author',
     254                ) );
     255                $user = $this->factory->user->create_and_get( array(
     256                        'role' => 'editor',
     257                ) );
     258
     259                wp_set_current_user( $user->ID );
     260
     261                $post = $this->factory->post->create_and_get( array(
     262                        'post_status' => 'private',
     263                        'post_author' => $author->ID,
     264                ) );
     265                $data = array(
     266                        'comment_post_ID' => $post->ID,
     267                        'comment'         => 'Comment',
     268                );
     269                $comment = wp_handle_comment_post( $data );
     270
     271                $this->assertTrue( current_user_can( 'read_post', $post->ID ) );
     272                $this->assertNotWPError( $comment );
     273                $this->assertInstanceOf( 'WP_Comment', $comment );
     274
     275        }
     276
     277        public function test_anonymous_user_cannot_comment_unfiltered_html() {
     278
     279                $post = $this->factory->post->create_and_get();
     280                $data = array(
     281                        'comment_post_ID' => $post->ID,
     282                        'comment'         => 'Comment <script>alert(document.cookie);</script>',
     283                        'author'          => 'Comment Author',
     284                        'email'           => 'comment@example.org',
     285                );
     286                $comment = wp_handle_comment_post( $data );
     287
     288                $this->assertNotWPError( $comment );
     289                $this->assertInstanceOf( 'WP_Comment', $comment );
     290                $this->assertNotContains( '<script', $comment->comment_content );
     291
     292        }
     293
     294        public function test_unprivileged_user_cannot_comment_unfiltered_html() {
     295
     296                $user = $this->factory->user->create_and_get( array(
     297                        'role' => 'author',
     298                ) );
     299                wp_set_current_user( $user->ID );
     300
     301                $this->assertFalse( current_user_can( 'unfiltered_html' ) );
     302
     303                $post = $this->factory->post->create_and_get();
     304                $data = array(
     305                        'comment_post_ID' => $post->ID,
     306                        'comment'         => 'Comment <script>alert(document.cookie);</script>',
     307                        'author'          => 'Comment Author',
     308                        'email'           => 'comment@example.org',
     309                );
     310                $comment = wp_handle_comment_post( $data );
     311
     312                $this->assertNotWPError( $comment );
     313                $this->assertInstanceOf( 'WP_Comment', $comment );
     314                $this->assertNotContains( '<script', $comment->comment_content );
     315
     316        }
     317
     318        public function test_unprivileged_user_cannot_comment_unfiltered_html_even_with_valid_nonce() {
     319
     320                $user = $this->factory->user->create_and_get( array(
     321                        'role' => 'author',
     322                ) );
     323                wp_set_current_user( $user->ID );
     324
     325                $this->assertFalse( current_user_can( 'unfiltered_html' ) );
     326
     327                $post   = $this->factory->post->create_and_get();
     328                $action = 'unfiltered-html-comment_' . $post->ID;
     329                $nonce  = wp_create_nonce( $action );
     330
     331                $this->assertNotFalse( wp_verify_nonce( $nonce, $action ) );
     332
     333                $data = array(
     334                        'comment_post_ID'             => $post->ID,
     335                        'comment'                     => 'Comment <script>alert(document.cookie);</script>',
     336                        'author'                      => 'Comment Author',
     337                        'email'                       => 'comment@example.org',
     338                        '_wp_unfiltered_html_comment' => $nonce,
     339                );
     340                $comment = wp_handle_comment_post( $data );
     341
     342                $this->assertNotWPError( $comment );
     343                $this->assertInstanceOf( 'WP_Comment', $comment );
     344                $this->assertNotContains( '<script', $comment->comment_content );
     345
     346        }
     347
     348        public function test_privileged_user_can_comment_unfiltered_html_with_valid_nonce() {
     349
     350                $user = $this->factory->user->create_and_get( array(
     351                        'role' => 'editor',
     352                ) );
     353                wp_set_current_user( $user->ID );
     354
     355                $this->assertTrue( current_user_can( 'unfiltered_html' ) );
     356
     357                $post   = $this->factory->post->create_and_get();
     358                $action = 'unfiltered-html-comment_' . $post->ID;
     359                $nonce  = wp_create_nonce( $action );
     360
     361                $this->assertNotFalse( wp_verify_nonce( $nonce, $action ) );
     362
     363                $data = array(
     364                        'comment_post_ID'             => $post->ID,
     365                        'comment'                     => 'Comment <script>alert(document.cookie);</script>',
     366                        'author'                      => 'Comment Author',
     367                        'email'                       => 'comment@example.org',
     368                        '_wp_unfiltered_html_comment' => $nonce,
     369                );
     370                $comment = wp_handle_comment_post( $data );
     371
     372                $this->assertNotWPError( $comment );
     373                $this->assertInstanceOf( 'WP_Comment', $comment );
     374                $this->assertContains( '<script', $comment->comment_content );
     375
     376        }
     377
     378        public function test_privileged_user_cannot_comment_unfiltered_html_without_valid_nonce() {
     379
     380                $user = $this->factory->user->create_and_get( array(
     381                        'role' => 'editor',
     382                ) );
     383                wp_set_current_user( $user->ID );
     384
     385                $this->assertTrue( current_user_can( 'unfiltered_html' ) );
     386
     387                $post   = $this->factory->post->create_and_get();
     388                $data = array(
     389                        'comment_post_ID' => $post->ID,
     390                        'comment'         => 'Comment <script>alert(document.cookie);</script>',
     391                        'author'          => 'Comment Author',
     392                        'email'           => 'comment@example.org',
     393                );
     394                $comment = wp_handle_comment_post( $data );
     395
     396                $this->assertNotWPError( $comment );
     397                $this->assertInstanceOf( 'WP_Comment', $comment );
     398                $this->assertNotContains( '<script', $comment->comment_content );
     399
     400        }
     401
     402        public function test_posting_comment_as_anonymous_user_when_registration_required_returns_error() {
     403
     404                $error = 'not_logged_in';
     405
     406                $_comment_registration = get_option( 'comment_registration' );
     407                update_option( 'comment_registration', '1' );
     408
     409                $post = $this->factory->post->create_and_get();
     410                $data = array(
     411                        'comment_post_ID' => $post->ID,
     412                );
     413                $comment = wp_handle_comment_post( $data );
     414
     415                update_option( 'comment_registration', $_comment_registration );
     416
     417                $this->assertWPError( $comment );
     418                $this->assertSame( $error, $comment->get_error_code() );
     419
     420        }
     421
     422        public function test_posting_comment_with_no_name_when_name_email_required_returns_error() {
     423
     424                $error = 'require_name_email';
     425
     426                $_require_name_email = get_option( 'require_name_email' );
     427                update_option( 'require_name_email', '1' );
     428
     429                $post = $this->factory->post->create_and_get();
     430                $data = array(
     431                        'comment_post_ID' => $post->ID,
     432                        'comment'         => 'Comment',
     433                        'email'           => 'comment@example.org',
     434                );
     435                $comment = wp_handle_comment_post( $data );
     436
     437                update_option( 'require_name_email', $_require_name_email );
     438
     439                $this->assertWPError( $comment );
     440                $this->assertSame( $error, $comment->get_error_code() );
     441
     442        }
     443
     444        public function test_posting_comment_with_no_email_when_name_email_required_returns_error() {
     445
     446                $error = 'require_name_email';
     447
     448                $_require_name_email = get_option( 'require_name_email' );
     449                update_option( 'require_name_email', '1' );
     450
     451                $post = $this->factory->post->create_and_get();
     452                $data = array(
     453                        'comment_post_ID' => $post->ID,
     454                        'comment'         => 'Comment',
     455                        'author'          => 'Comment Author',
     456                );
     457                $comment = wp_handle_comment_post( $data );
     458
     459                update_option( 'require_name_email', $_require_name_email );
     460
     461                $this->assertWPError( $comment );
     462                $this->assertSame( $error, $comment->get_error_code() );
     463
     464        }
     465
     466        public function test_posting_comment_with_invalid_email_when_name_email_required_returns_error() {
     467
     468                $error = 'require_valid_email';
     469
     470                $_require_name_email = get_option( 'require_name_email' );
     471                update_option( 'require_name_email', '1' );
     472
     473                $post = $this->factory->post->create_and_get();
     474                $data = array(
     475                        'comment_post_ID' => $post->ID,
     476                        'comment'         => 'Comment',
     477                        'author'          => 'Comment Author',
     478                        'email'           => 'not_an_email',
     479                );
     480                $comment = wp_handle_comment_post( $data );
     481
     482                update_option( 'require_name_email', $_require_name_email );
     483
     484                $this->assertWPError( $comment );
     485                $this->assertSame( $error, $comment->get_error_code() );
     486
     487        }
     488
     489        public function test_posting_comment_with_no_comment_content_returns_error() {
     490
     491                $error = 'require_valid_comment';
     492
     493                $post = $this->factory->post->create_and_get();
     494                $data = array(
     495                        'comment_post_ID' => $post->ID,
     496                        'comment'         => '',
     497                        'author'          => 'Comment Author',
     498                        'email'           => 'comment@example.org',
     499                );
     500                $comment = wp_handle_comment_post( $data );
     501
     502                $this->assertWPError( $comment );
     503                $this->assertSame( $error, $comment->get_error_code() );
     504
     505        }
     506
     507}