是否可以在页面上检测表单提交并执行我的操作,然后像往常一样继续表单?

时间:2016-06-19 06:17:55

标签: javascript php jquery forms

我正在为WordPress构建一个登陆页面A / B测试插件。

我的目标是设置一些符合规则的规则,这些规则会记录当前着陆页A / B测试变体的转换。

到目前为止,我有过几个想法......

1)JavaScript事件处理程序

使用JavaScript,检测提交事件并触发AJAX帖子以在事件处理程序中记录我的转换。在AJAX成功回调中,我将继续发布帖子。一种方法是将标志变量设置为false,然后在AJAX成功中将其设置为true。然后它会再次触发表单上的提交,但这次标志var将使其绕过AJAX转换保存,而只是执行正常的表单后期操作。

2)更改FORM Action URL以通过本地服务器路由POST,然后转发到目标

使用JavaScript,在DOM中查找所有匹配的表单,并使用我服务器上的新URL替换post post action URL。新的URL会将表单发布到我的服务器,以便我可以使用PHP检测帖子并记录转换,然后我将原始表单发布数据重新发布到原始URL。

表单操作网址如下:https://www.remote-server.com
会成为 https://www.local-server.com/?record-conversion=yes&id=123&original-url=https://www.remote-server.com

然后在PHP中,我可以从$_POST['original-url']

获取FOrms原始帖子的URL

要将POST转发到原始URL,我遇到了2个PHP函数......

版本1
将表单POST数据打印到HTML页面作为隐藏的表单字段,然后使用JavaScript触发,立即提交表单将数据发布到原始URL。

function redirect_post2($url, array $data)
{
    ?>
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <script type="text/javascript">
            function closethisasap() {
                document.forms["redirectpost"].submit();
            }
        </script>
    </head>
    <body onload="closethisasap();">
    <form name="redirectpost" method="post" action="<?php echo $url; ?>">
        <?php
        if ( !is_null($data) ) {
            foreach ($data as $k => $v) {
                echo '<input type="hidden" name="' . $k . '" value="' . $v . '"> ';
            }
                echo '<input type="hidden" name="test" value="testval"> ';
        }
        ?>
    </form>
    </body>
    </html>
    <?php
    exit;
}

第2版
此版本使用PHP的stream_context_create()stream_get_contents()fopen()将POST数据转发/发布到原始网址。

/**
 * Redirect with POST data.
 *
 * @param string $url URL.
 * @param array $post_data POST data. Example: array('foo' => 'var', 'id' => 123)
 * @param array $headers Optional. Extra headers to send.
 */
function redirect_post($url, array $data, array $headers = null) {
    $params = array(
        'http' => array(
            'method' => 'POST',
            'content' => http_build_query($data)
        )
    );
    if (!is_null($headers)) {
        $params['http']['header'] = '';
        foreach ($headers as $k => $v) {
            $params['http']['header'] .= "$k: $v\n";
        }
    }
    $ctx = stream_context_create($params);
    $fp = @fopen($url, 'rb', false, $ctx);
    if ($fp) {
        echo '<pre>';
        echo @stream_get_contents($fp);
        echo '</pre>';
        die();
    } else {
        // Error
        throw new Exception("Error loading '$url', $php_errormsg");
    }
}

问题/问题/关注

  • 如果我使用JavaScript事件处理程序检测表单帖子并记录我的转换。我不确定当存在同一表单发布/提交的其他事件处理程序时会发生什么。我不确定它是否会让我不能跑?如果我的确运行,而其他人也这样做。其他处理人员可能会提交帖子,然后我的提交可能会导致表格被提交超过1次!?

  • 如果表格使用AJAX提交其帖子。然后我的代码将尝试执行页面重定向帖子并破坏功能!

我的目标是否可能?

所以这让我问这个问题。是否可以插入包含现有表单的页面,并且能够在提交表单时记录我的转换并使表单仍然完全像我试图干扰它一样执行?

2 个答案:

答案 0 :(得分:1)

扩展我的评论......

如果你事先没有关于表格如何运作的知识,你可以近距离接触 - 并覆盖你将在野外看到的绝大多数情况 - 但是在某些情况下你会打破形式。

假设您执行以下所有操作:

  • 检测目标表单
  • 迭代所有元素,记录所有事件处理程序
  • 清除所说的事件处理程序(没有以某种方式破坏验证...)
  • 将自己的事件处理程序添加到表单submit和所有按钮(我们希望通过键入特定值或其他奇怪的内容来提交表单,并且所有按钮实际上都提交了表单)
  • 等待点击
  • 记录按钮/事件
  • 进行AJAX通话
  • 成功(让我们忽略失败时会发生什么)
    • 恢复所有原始事件处理程序
    • 尝试根据从
    • 调用方法的元素“重播”您录制的事件
    • 用手指交叉

这将涵盖很多情况(当然所有“正常”的html表单使用),但是,它会在以下任何情况下中断:

  • 表单提交与时间有关
  • 表单上的按钮完全做了其他事情(比如发出Ajax请求来验证用户名)
  • 事件详细信息的细节用于以某种方式处理表单(例如,按钮点击的位置)
  • 不处理根本没有“点击”提交的情况(当在字段中输入特定值等时...)
  • 不处理从表单外部调用提交的情况
  • 它也会破坏任何验证事件等。

在删除事件时你可能不那么激进,但是你更有可能完全错过提交。

一种稍微好一点的不同方法......

如果您自己的方法足够强大,可以在没有副作用的情况下多次调用,那么您可以放弃执行以下操作:

使用您自己的包装器替换所有形式onsubmit事件处理程序,这些包装器执行类似

的操作
function handleSubmit(form) {
    // Make your ajax call
    $.ajax({
        ...,
        onsuccess: {
            form.submit();
        }
    })
}

那应该处理“股票”案件。然后,为了处理原始表单使用jQuery Ajax的情况,设置一个jQuery.ajaxPrefilter()来执行类似的操作(但在这种情况下,不是提交表单,而是调用原始回调)。

现在你正在处理股票表格和jQuery AJAX。当然,如果他们使用的是react / angular /一个不同的框架,你需要为这些框架添加一个处理程序。

我想你可以全力以赴,尝试替换低级XMLHttpRequest(以及不同浏览器中的相关等价物),但那将是真的脆弱。

在一天结束时,你将报名参加军备竞赛,我不认为这是你能赢的。

答案 1 :(得分:0)

您需要设置 onsubmit attr。在表格上。

HTML

<form onsubmit="Get();" method="post" action="example.php">
<input type="text" name="name" placeholder="name">
<input type="submit" value="Go">
</form>

的javascript

var Get = function(){
//action to do
return true
};
  

100%testing.on chrom dev。

如果你想运行ajax然后如果回答为true,则继续表格,然后你需要将javascript更改为:

var Get = function(){
var xhttp;
if (window.XMLHttpRequest) {
xhttp = new XMLHttpRequest();
} else {
xhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xhttp.onreadystatechange = function() {
if (xhttp.readyState == 4 && xhttp.status == 200) {
if (xhttp.responseText == "true"){
return true;
}else{
alert("There is some error in verfication.");
return false;
break;
}
}else{
alert("Oops error " + xhttp.State + " happends.");
return false;
break;
}
};
xhttp.open("GET" , x, true);
/* add 
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
if using post*/
xhttp.send();
};

而不是xhttp.open()中的x;将文件键入为字符串。

如果缓存不是一个选项,那么将GET更改为POST,它更慢但安全。

  

0%测试