密码提交时使用 AJAX 保护帖子内容并避免页面刷新

如何解决密码提交时使用 AJAX 保护帖子内容并避免页面刷新

这是针对 WordPress 的,只是为了说明这一点。我在这里问是因为我怀疑我需要为这个问题提供赏金(价值 400)。

我需要在表单提交中添加 AJAX 以避免页面重新加载/页面刷新。我尝试了几个不同的版本,但没有一个有效。

这里的总体思路是保护帖子的一部分,该部分代码包含在 <pre><code> 标签中。

这些标签来自 prismjs 荧光笔,如下所示:

<pre><code class="language-php">code here</code></pre>

这些标签有四个不同的类;

  • PHP
  • HTML
  • CSS
  • JS

这就是 preg_replace 使用 ('/(<pre[^>]*>\s*<code[^>]*>) 格式的原因,因为它需要覆盖(处理)添加的类。

此外,还设置了 cookie,以便一旦用户提供了正确的密码,密码就会被记住。用户不必在每次查看包含受保护内容的帖子时都重新输入密码。

我有一个空的 DIV 作为显示消息(成功和错误)的占位符。这里的想法是在用户提交错误密码时显示错误。如果密码匹配,则显示内容(代码)。

这是我正在处理的代码:

add_filter( 'the_content','wrap_code_in_shortcode',9 );
function wrap_code_in_shortcode( $content ) {

    if ( ! in_category( 'premium' ) ) return $content;
    
    $content = preg_replace('/(<pre[^>]*>\s*<code[^>]*>)/',"[protected]$1",$content);

    $content = preg_replace('/(<\/code>\s*<\/pre>)/',"$1[/protected]",$content);

    return $content;
}

add_shortcode( 'protected','protected_function' );
function protected_function($atts,$content=null){

    $userpass = isset( $_REQUEST['password']) ? $_REQUEST['password'] : (isset($_COOKIE['userpass']) ? $_COOKIE['userpass'] : NULL );

        if ( in_array( $userpass,array('testpw') ) ) {

            $return_code = do_shortcode( $content );

        } else {

    $return_code = '<div style="margin-top:20px; font-size:15px">Submit password to view.</div>
    
    <div id="errorPWdata"></div>

        <form method="post" onsubmit="protectedFunction(this);">

            <input required style="display: block; width: 69%; height: 50px; margin-right: 1%; float: left; border: 2px solid #333;" type="text" placeholder="&#32;Password Here" name="password" id="userpass">

            <input style="display: block; margin: 0px; width: 30%; height: 50px; background-color: #333; color: #fff;" id="protectedButton" type="submit" value="Submit">

        </form>';
    
        ?>
    <script>

        function protectedFunction(form) {
        $('#protectedButton').on( 'click',function(e) {
        e.preventDefault();
        $.ajax({
                success: function(data) {
                    $("#errorPWdata").html(data);
                },error: function() {
                    alert("Password record error. Contact the administrator.");
                }
            });
        document.cookie = "userpass=" + escape(form.userpass.value) + "; path=/";
    }
}
    </script>
    <?php
}

    return $return_code;

}

解决方法

我学会了详细说明您的代码片段并注意错误。 请先阅读所有内容,然后您可以尝试。

错误 1

Shortcode 定义了错误的函数名

add_shortcode( 'protected','shortcode_protected' );

应该换成

add_shortcode( 'protected','bio_protected_function' );

错误 2

脚本标签应该由入队系统替换以保证脚本序列。

代码片段

<script>
    function protectedFunction(form) {
        $('#protectedButton').on('click',function (e) {
            e.preventDefault();
            $.ajax({
                success: function (data) {
                    $("#errorPWdata").html(data);
                },error: function () {
                    alert("Password record error. Contact the administrator.");
                }
            });
            document.cookie = "userpass=" + escape(form.userpass.value) + "; path=/";
        }
    }
</script>

应该换成这个

add_action( 'wp_enqueue_scripts',function () {
    wp_enqueue_script(
        'bio-shortcode-protected',get_theme_file_uri( 'assets/js/bio-shortcode-protected.js' ),[ 'jquery' ],'1',true
    );
} );
wp_enqueue_scripts();

应创建适当的 bio-shortcode-protected.js 文件 path-to-your-theme/assets/js/bio-shortcode-protected.js(下一个错误的文件内容)

错误 3

  1. 默认情况下,WordPress 将 jQuery 作为全局 JavaScript 对象加载

    jQuery 应该有效,而 $ 可能不会。脚本应以 jQuery 包装器开头,以保证 $ 别名正常工作。

  2. 提供的脚本语法不正确。应该有一个关闭 父母符号)

  3. 最好使用提交处理程序而不是点击处理程序。我通过处理 submit 而不是 click 简化了您的处理程序。点击输入按钮触发 submitclick 处理程序不需要。

最后,bio-shortcode-protected.js 内容应该是

jQuery(function($){
    const settings = window.bioShortcodeData;

    function init() {
        $('#protectedForm').on( 'submit',function(e) {
            e.preventDefault();

            const form = this;

            $.post({
                url: settings['endpoint'],data: {
                    'action': settings['action'],'bio-post-id': settings['post-id'],'nonce': settings['nonce'],'password': form.userpass.value,},success: function(data) {
                    if (!data.status) {
                        alert(data.message);

                        $('#errorPWdata')
                            .empty()
                            .append(data.message);

                        return;
                    }

                    if (data.isValidPassword) {
                        document.cookie = "userpass=" + escape(form.userpass.value) + "; path=/";
                    }

                    $('#bio-protected-content').replaceWith(data.content);
                    init() // for reattach submission handler
                },error: function() {
                    alert("Server error");
                }
            });

        })
    }

    init();
})

适当的一点点改进的短代码模板应该如下所示:

function bio_protected_function( $atts,$content = null ) {
    add_action( 'wp_enqueue_scripts',function () {
        wp_enqueue_script(
            'bio-shortcode-protected',true
        );
        wp_localize_script(
            'bio-shortcode-protected','bioShortcodeData',[
                'post-id'  => get_the_ID(),'nonce'    => wp_create_nonce( 'bio-shortcode' ),'endpoint' => admin_url( 'admin-ajax.php' ),'action'   => 'bio_protected_code'
            ]
        );
    } );
    wp_enqueue_scripts();

    if ( bio_validate_the_password() ) {
        return do_shortcode( $content );
    }

    ob_start();
    ?>
    <div class="bio-protected-content" id="bio-protected-content">
        
        <div style="margin-top:20px; font-size:15px">Submit password to view.</div>

        <div id="errorPWdata"></div>

        <form method="post" id="protectedForm">

            <input required
                   style="display: block; width: 69%; height: 50px; margin-right: 1%; float: left; border: 2px solid #333;"
                   type="text" placeholder="&#32;Password Here" name="password" id="userpass">

            <input style="display: block; margin: 0px; width: 30%; height: 50px; background-color: #333; color: #fff;"
                   id="protectedButton" type="submit" value="Submit">

        </form>
    </div>
    <?php

    return ob_get_clean();
}

错误 4

如果表单将被提交,将会发生什么 - WordPress 开始构建页面的内容,首先是页眉,内容(the_content 过滤器),然后是页脚。并检查短代码中的密码不是一个好主意。这样发送不必要的页面块。 AJAX 唯一需要获取的是干净的适当帖子内容。

这就是 ajax-endpoint 发挥作用的地方。端点应通过将代码片段放置到 functions.php 文件中来创建:

add_action( 'wp_ajax_nopriv_bio_protected_code','bio_protected_code_endpoint' );
add_action( 'wp_ajax_bio_protected_code','bio_protected_code_endpoint' );
function bio_protected_code_endpoint() {
    $is_valid_nonce = wp_verify_nonce( $_REQUEST['nonce'],'bio-shortcode' );
    if ( ! $is_valid_nonce ) {
        wp_send_json(
            [
                'status'  => false,'message' => 'Invalid nonce',]
        );
        exit;
    }

    $post_id = $_REQUEST['bio-post-id'];

    $post_type           = get_post_type( $post_id );
    $available_post_type = 'your-post-type';
    if ( $available_post_type !== $post_type ) {
        wp_send_json(
            [
                'status'  => false,'message' => 'Not available post type',]
        );
        exit;
    }

    global $post;

    $post    = get_post( $post_id );
    $content = apply_filters( 'the_content',$post->post_content );

    wp_send_json(
        [
            'status'          => true,'isValidPassword' => bio_validate_the_password(),'content'         => $content
        ]
    );

    exit;
}

和密码验证功能

function bio_validate_the_password() {
    $userpass = $_REQUEST['password'] ?? $_COOKIE['userpass'] ?? null;

    return in_array( $userpass,[ 'testpw' ] );
}

最后的话:

我不建议在 Cookie 中设置密码。这是潜在的安全漏洞。 最好设置会话密码变量。但这种方式也好不到哪里去。

有一个很好的答案,为什么不在会话中存储密码以及该怎么做。 Is it secure to store a password in a session?

,

请尝试使用以下代码。

短代码处理部分:

// add [protected] shortcode to content.
add_filter( 'the_content','wrap_code_in_shortcode',9 );
function wrap_code_in_shortcode( $content ) {
    if ( ! in_category( 'premium' ) ) return $content;
    $content = preg_replace('/(<pre[^>]*>\s*<code[^>]*>)/',"[protected]$1",$content);
    $content = preg_replace('/(<\/code>\s*<\/pre>)/',"$1[/protected]",$content);
    return $content;
}

// function to check if password is valid
function is_user_password_valid($userpass,$post_id) {
    return in_array( $userpass,array('test') );
}

// define shortcode. you can combine(merge) this section with wrap_code_in_shortcode()
add_shortcode( 'protected','shortcode_protected' );
function shortcode_protected($atts,$content=null){
    $userpass = isset( $_REQUEST['password']) ? $_REQUEST['password'] : (isset($_COOKIE['userpass']) ? $_COOKIE['userpass'] : NULL );
    $post_id = get_the_ID();

    if ( is_user_password_valid($userpass,$post_id) ) {
        $return_code = do_shortcode( $content );
    } else {
        $return_code = 
        '<div id="protected-area">
            <div style="margin-top:20px; font-size:15px">Submit password to view.</div>
            <form method="post" onsubmit="getProtectedContent(event);">
                <input required type="text" placeholder="&#32;Password Here" name="password">
                <input type="submit" value="Submit">
            </form>
        </div><!-- end of #protected-area -->';
        $return_code .= '<script>
            function getProtectedContent(event) {
                event.preventDefault();
                let password = event.target.elements.password.value;
                jQuery.ajax({
                    url: "' . admin_url('admin-ajax.php') . '",method: "POST",data: {
                        action: "get_protected_content",post_id: ' . $post_id . ',password
                    },success: function(result) {
                        if (result.success) {
                            jQuery("#protected-area").html(result.data);
                            document.cookie = "userpass=" + password + "; path=/";
                        } else {
                            alert(result.data);
                        }
                    },error: function() {
                        alert("Something is wrong.");
                    }
                });
                return false;
            }
        </script>';
    }

    return $return_code;
}

Ajax 请求处理部分:

add_action( 'wp_ajax_get_protected_content','get_protected_content' );
add_action( 'wp_ajax_nopriv_get_protected_content','get_protected_content' );
function get_protected_content() {
    // validation
    if ( empty( $_POST['post_id'] ) ) {
        wp_send_json_error( 'Wrong Post ID' );
    }
    $post_id = (int)$_POST['post_id'];

    if ( empty( $_POST['password'] ) || ! is_user_password_valid( $_POST['password'],$post_id ) ) {
        wp_send_json_error( 'Wrong Password' );
    }
    
    $content = get_post_field( 'post_content',$post_id );
    // var_dump($content);
    if ( preg_match( '/(<pre[^>]*>\s*<code[^>]*>.*<\/code>\s*<\/pre>)/',$content,$matches ) ) {
        wp_send_json_success( apply_filters( 'the_content',$matches[1] ) );
    } else {
        wp_send_json_error( 'No Protected Content Found' );
    }
}

希望此代码对您有所帮助。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res