指定の時間が経過するまで投稿できないようにする連投防止 [Ask-me]

当ページのリンクには広告が含まれています。

荒らし対策や投稿に時間が掛かってしまった場合の連投を防止する方法です。例えば、投稿した人は5分経たないと再投稿できない、といった対策方法です。

ユーザーのmeta情報に最新の投稿日時を保存し、PHPのDateTimeクラスまたはDateTimeImmutableクラスを使い、日時の比較をして判定します。

動くところまでは確認しましたが、実装するのは止めました。なぜなら、怒りがフツフツと湧いていて、旦那デスノートへぶつけたいのに、投稿制限が掛かると、さらに火に油を注ぐような形になってしまうかな、と思ったからです。

連投防止措置として、過去に書き込みボタンを何度も押して同じ内容を連投しないようにする対処は完了しています。詳細は以下に書きました。もしよろしければ、参考にしてみてください。
デスノート書き込みが遅い時の2重押し送信連投を防止するために、ローディング画面としてアニメーションを表示するようにしました [Ask-me]

PHPのDateTimeクラスを使い、指定の時間が経過するまで書き込みをさせないよう対処した、ソースコードは以下です。


// プロフィール画面に追加 直接編集することはないが、確認用
add_filter('user_contactmethods', function( $profile ) {
    
    $profile['last_add_question_time'] = '前回の投稿日時';

    return $profile;
}
, 10, 1);




// デス書き込み時に投稿時間を保存
add_action( 'new_to_draft', function( $post ){
    
    $now = new DateTimeImmutable( null, new DateTimeZone( 'Asia/Tokyo' ) );
    $now = $now->format("Y-m-d H:i:s");
    update_user_meta( $post->post_author, 'last_add_question_time', $now );
}
, 10, 1 );





// 連投防止の画面

add_filter( 'the_content', function( $content ){
    
    $user = wp_get_current_user();
    
    // get_user_meta キーが無かったり値が取れなかったら、空の文字列を返す。NULLではない。
    $last_add_question_time = get_user_meta( $user->ID, 'last_add_question_time', true );

    
    if( $last_add_question_time !== '' ){



    $interval = '+5 minute';
    $last_add_question_time = new DateTimeImmutable( $last_add_question_time );
    $now = new DateTimeImmutable( null, new DateTimeZone( 'Asia/Tokyo' ) );
        
    $allow_add_time = $last_add_question_time->modify( $interval );

    $content = '';


        
        

    if(     is_user_logged_in()
        &&    strpos( $_SERVER['REQUEST_URI'], '/add-deathnote' ) !== false
//        &&    $now < $allow_add_time
        &&    $now->format('Y-m-d H:i:s') < $allow_add_time->format('Y-m-d H:i:s')
      ){
        
        remove_shortcode( 'ask_question' );
        add_shortcode('ask_question', function (){});
        
        $content .= <<< EOM
<br><p>前回の投稿日時から5分後に投稿できるようになります。<br>
前回の投稿日時:{$last_add_question_time->format('Y-m-d H:i:s')}<br>
投稿ができるようになる日時:{$allow_add_time->format('Y-m-d H:i:s')}</p>

EOM;
    }
    
    }
    
    return $content;
});

動きとしては、new_to_draftの投稿時に動く箇所にフックして、投稿時間を保存します。書き込みページを開く時、前回の投稿時間から指定の時間が経過していなければ、書き込みフォームを表示せずに、注意メッセージだけを表示するようにしています。

書き込みページは、the_contentで生成はしていません。the_contentは使っていますが、書き込みフォームを表示しているのはask_questionというショートコードです。なので、the_contentでフックして、contentをnullでreturnしても書き込みフォームは消えません。

そこで、ask_questionのショートコードをいったん削除し、空で再定義した上でcontentに注意メッセージを入れる、という流れになっています。

なぜ、ショートコードの削除だけでなく、再定義までしたかというと、ask_questionのショートコードを削除しただけでは、ask_questionという文字だけは表示されてしまいます。再定義することで、文字列の表示を回避しています。

55行目にコメントで残してありますが、DateTimeクラスは、オブジェクト同士の比較では、日時の比較として成立しません。もしかしたら、タイムゾーンが影響している可能性があります。というのも、しばらく時間が経ってから改めて確認したら比較出来ていたからです。

たぶん一番確実なのは、56行目のようにDateTimeオブジェクトでformatメソッドで比較することですね。秒で更新しながら確認したら、1秒過ぎたところできちんと投稿ができるようになったからです。

Ask-meにおいて、連投防止をしたい場合は、参考にしてみてください。繰り返しになりますが、このソースコードで動くことは確認しましたが実装はしていませんので、コピペで使うことは控えた方が良いです。

この記事を書いた人

旦那デスノートで実際に使っている、WordpressやPHPのコードなどを公開しています。公開しているものは、ネットには あまり載っていない、痒いところに手が届くような拡張です。
@koichiromakita2

コメント

コメントする