代码之家  ›  专栏  ›  技术社区  ›  Brian Bruman

regex(preg_match_all)从隐藏的登录表单中检索真实性令牌

  •  1
  • Brian Bruman  · 技术社区  · 8 年前

    简而言之,我正在尝试使用curl登录电子商务平台bonanza,以便我可以自动打印新订单。

    我搜索了GITHUB并找到了一个Twitter的自动登录脚本 here 看起来和博南扎的运作方式极为相似。

    我试图首先执行curl请求的登录页面位于 here

    它包含一个表单,该表单发布以下变量以登录

    utf8: ✓
    authenticity_token: 0tMPrfH0+Tt7z05jxu61pN10RveVp6o0dsfgf=4cS6g7kyeMsztpDmWj2P1ZYasfdf3QjNl/og==
    username: myusername
    password: mypassword
    commit: Log in
    

    查看窗体的源可以看到 name="authenticity_token" value= 我需要找回的代币。

     <form class="user_session_form"
     action="https://www.bonanza.com/sessions" accept-charset="UTF-8"
     method="post"><input name="utf8" type="hidden" value="&#x2713;"
     /><input type="hidden" name="authenticity_token" value="siKgYUtSqTs8DHCXmj8gbV6Gp3L7gaQ9C/B0rLM9/V94+FnSxTb+x6vXADSFROCxxMLB3RAqOMeL/IJQADq6dk8A=="
     />
    

    如前所述,这似乎与twitter登录脚本的工作方式非常相似,因为它找到了身份验证令牌,并向 https://twitter.com/sessions 以及传递给成功登录的变量。

    Twitter脚本使用此PrgGyMatCHyALL函数获取验证令牌。

    function ara($ilk, $son, $text) {
        @preg_match_all('/' . preg_quote($ilk, '/') .
        '(.*?)'. preg_quote($son, '/').'/i', $text, $m);
        return @$m[1];
    }
    

    下面是如何使用该函数获取身份验证令牌…

    $baslik = ara("<input type=\"hidden\" value=", "\" name=\"authenticity_token\">", $html);
    

    注释(注释) $html )是登录页的curl exec。

    再次总结一下, https://www.bonanza.com/home/login 采取以下措施 formdata 登录:

    utf8=%e2%9c%93&真实性令牌=sfrh%2fvfx7%2bh%2fa3kmq2fewz2342albtp3bft%2faxqw7cwlgeuz5bbtmgtu7ehb%2bqytnxs1tc30h64mt98mva%3d%3d&username=myusername&password=mypassword&commit=log+登录

    使用这些变量生成一个post https://www.bonanza.com/sessions 才能成功登录。

    我正在尽我所能修改twitter脚本,以下是我目前所拥有的:

    $username = "example@stackoverflow.com";
    $password = "password"; 
    
    $ch = curl_init();
    $rand = rand(1,99999);
    $cookie =  $_SERVER['DOCUMENT_ROOT'] . "/cookie-$rand.txt";
    $sTarget = "https://www.bonanza.com/home/login";
    curl_setopt($ch, CURLOPT_URL, $sTarget);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
    curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie);
    curl_setopt($ch, CURLOPT_REFERER, "https://www.bonanza.com/home/login");
    $html = curl_exec($ch);
    preg_match_all('/' . preg_quote("<input type=\"hidden\" value=", '/') .
    '(.*?)'. preg_quote("\" name=\"authenticity_token\">", '/').'/i', $html, $m);
    

    //不工作..需要检索 $authtoken 在里面 $m preg_match_all 阵列输出

    $sPost = "utf8=%E2%9C%93&authenticity_token=$authtoken&username=$username&password=$password&commit=Log+in";
    $sTarget = "https://www.bonanza.com/sessions";
    curl_setopt($ch, CURLOPT_URL, $sTarget);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $sPost);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, false);
    curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-type: application/x-www-form-urlencoded"));
    curl_exec($ch);
    

    我试过调试,看看是否有 百万美元 预赛 调用,但输出为空数组

    Array
    (
        [0] => Array
            (
            )
    
        [1] => Array
            (
            )
    
    )
    

    如何修改preg_match_all调用(或其他方法)以检索 authenticity token 一个成功的表单登录提交所必需的,还有什么我应该知道的,以这种方式通过curl编程登录吗?

    3 回复  |  直到 8 年前
        1
  •  2
  •   user557597    8 年前

    您可以使用这个regex来获取真实性令牌。
    它出现在第四组。

    属性值的顺序无关紧要,这会得到它们
    有效期内的任何地方 输入标签 .

    (?s)<input(?=\s)(?=(?:[^>"']|"[^"]*"|'[^']*')*?\stype\s*=\s*(?:(['"])\s*hidden\s*\1))(?=(?:[^>"']|"[^"]*"|'[^']*')*?\sname\s*=\s*(?:(['"])\s*authenticity_token\s*\2))(?=(?:[^>"']|"[^"]*"|'[^']*')*?\svalue\s*=\s*(?:(['"])\s*(.*?)\s*\3))\s+(?:"[\S\s]*?"|'[\S\s]*?'|[^>]*?)+>

    https://regex101.com/r/NCjFxc/1

    引用

    单个,颚化符作为regex分隔符:
    '~(?s)<input(?=\s)(?=(?:[^>"\']|"[^"]*"|\'[^\']*\')*?\stype\s*=\s*(?:([\'"])\s*hidden\s*\1))(?=(?:[^>"\']|"[^"]*"|\'[^\']*\')*?\sname\s*=\s*(?:([\'"])\s*authenticity_token\s*\2))(?=(?:[^>"\']|"[^"]*"|\'[^\']*\')*?\svalue\s*=\s*(?:([\'"])\s*(.*?)\s*\3))\s+(?:"[\S\s]*?"|\'[\S\s]*?\'|[^>]*?)+>~'

    double,颚化符作为regex分隔符:
    "~(?s)<input(?=\\s)(?=(?:[^>\"']|\"[^\"]*\"|'[^']*')*?\\stype\\s*=\\s*(?:(['\"])\\s*hidden\\s*\\1))(?=(?:[^>\"']|\"[^\"]*\"|'[^']*')*?\\sname\\s*=\\s*(?:(['\"])\\s*authenticity_token\\s*\\2))(?=(?:[^>\"']|\"[^\"]*\"|'[^']*')*?\\svalue\\s*=\\s*(?:(['\"])\\s*(.*?)\\s*\\3))\\s+(?:\"[\\S\\s]*?\"|'[\\S\\s]*?'|[^>]*?)+>~"

    可读版本

     (?s)
    
     # Begin Input tag
     < input                # input tag
    
     (?= \s )
     (?=                    # Type Hidden (a pseudo atomic group)
          (?: [^>"'] | " [^"]* " | ' [^']* ' )*?
          \s type \s* = \s*      # Type
          (?:
               ( ['"] )               # (1), Quote
               \s* hidden \s*         # Hidden
               \1 
          )
     )
     (?=                    # Name authenticity_token
          (?: [^>"'] | " [^"]* " | ' [^']* ' )*?
          \s name \s* = \s*      # Name
          (?:
               ( ['"] )               # (2), Quote
               \s* authenticity_token \s*   # "Authenticity Token"
               \2 
          )
     )
     (?=                    # Value of authenticity_token
          (?: [^>"'] | " [^"]* " | ' [^']* ' )*?
          \s value \s* = \s*     # Value
          (?:
               ( ['"] )               # (3), Quote
               \s* 
               ( .*? )                # (4), Authenticity Token Value 
               \s* 
               \3 
          )
     )
     # Have the Authenticity Token, just match the rest of tag
     \s+ 
     (?: " [\S\s]*? " | ' [\S\s]*? ' | [^>]*? )+
    
     >                      # End tag
    
        2
  •  4
  •   jstur    8 年前

    我尽量不使用regex,而是使用php的标准从dom中提取它。 DOMDocument XML manipulation library :

    $doc = new DOMDocument();
    $doc->loadHTML($html);
    $xpath = new DOMXPath($doc);
    $query = '//form[contains(@class, "user_session_form")]/input[contains(@name, "authenticity_token")]';
    $inputs= $xpath->query($query);
    foreach($inputs as $input) {
        echo $input->getAttribute('value');
    }
    

    这个 $query 变量是 xpath query .

        3
  •  2
  •   Impact    8 年前

    你在试着匹配

    <input type="hidden" name="authenticity_token" value="{$token}"/>

    你的模式是:

    "/<input type=\"hidden\" value=(.*?)\" name=\"authenticity_token\">/i"

    你看到了吗?

    应该是: "<input type=\"hidden\" name=\"authenticity_token\" value=\"([^"]+)\"\/>"

    编辑 如果能够在不受特定属性顺序约束的情况下进行匹配是很重要的:

    <input (?:(?:type=\"hidden\"|name=\"authenticity_token\"|value=\"([^"]+)\"|(?!(?:name|type|value))[^=]+=\"[^"]+\")\s*)+
    

    将不捕获,任何属性和它的值,它不被称为“类型”或“名称”,它需要作为 type="hidden" name="authenticity_token" ,如果遇到属性“value”,则将在捕获组1中捕获其值。

    编辑2 :preg_match()和preg_replace()等将需要在模式的开头和开头使用分隔符: http://php.net/manual/en/regexp.reference.delimiters.php

    所以你可以简单地封装表达式如下: "/<expression>/" "~<expression>~" 哪里 <expression> 是你的正则表达式。