使用cURL、PHP和Twitter而不使用API的逻辑

使用cURL、PHP和Twitter而不使用API的逻辑,php,curl,twitter,Php,Curl,Twitter,我有这个代码,它将cookies保存在.txt文件中,并使用Twitter验证用户 <?php require_once 'class/Cookies.php'; $cookie = []; $username = 'formUser'; $password = 'formPass'; $index_url = 'https://twitter.com'; $token = curl_init(); curl_setopt_array($token, [ CURLOP

我有这个代码,它将
cookies
保存在
.txt
文件中,并使用Twitter验证用户

<?php

require_once 'class/Cookies.php';

$cookie = [];

$username = 'formUser';
$password = 'formPass';

$index_url = 'https://twitter.com';

$token = curl_init();
curl_setopt_array($token, [
      CURLOPT_URL             => $index_url,
      CURLOPT_CUSTOMREQUEST   => 'GET',
      CURLOPT_RETURNTRANSFER  => true,
      CURLOPT_SSL_VERIFYPEER  => false,
      CURLOPT_SSL_VERIFYHOST  => 2,
      CURLOPT_USERAGENT       => $_SERVER['HTTP_USER_AGENT'],
      //CURLOPT_COOKIEFILE      => __DIR__ . DIRECTORY_SEPARATOR . 'cookies' . DIRECTORY_SEPARATOR . $username . '.txt',
      CURLOPT_COOKIEJAR       => __DIR__ . DIRECTORY_SEPARATOR . 'cookies' . DIRECTORY_SEPARATOR . $username . '.txt',
      CURLOPT_COOKIESESSION   => true,
      CURLOPT_REFERER         => $index_url,
      CURLOPT_HEADER          => true,
      CURLOPT_HTTPHEADER      => ['Cookie:' . http_build_query($cookie, '', ';') . ';'],
      CURLOPT_HEADERFUNCTION => function ($curl, $header) use (&$cookie) {
        if (stripos($header, 'Set-Cookie:') === 0) {
          if (preg_match('/Set-Cookie:\s?(.*?)=(.*?);/i', $header, $matches)) {
            $cookie[$matches[1]] = urldecode($matches[2]);
          }
        }
        return strlen($header);
      }
    ]
);    
$access = curl_exec($token);

preg_match('/value="(.*?)" name="authenticity_token"/', $access, $matches);

$authenticity_token = $matches[1];

//var_dump($authenticity_token);

$session_post = "session[username_or_email]=$username&session[password]=$password&return_to_ssl=true&scribe_log=&redirect_after_login=%2F&authenticity_token=$authenticity_token";



$session_url = 'https://twitter.com/sessions';

curl_setopt_array($token, [
      CURLOPT_URL             => $session_url,
      CURLOPT_CUSTOMREQUEST   => 'POST',
      CURLOPT_POSTFIELDS      => $session_post,
      CURLOPT_RETURNTRANSFER  => true,
      CURLOPT_HTTPHEADER      => [
        "Content-type: application/x-www-form-urlencoded",
        'Cookie: '. http_build_query($cookie, '', ';').';'
      ],
      CURLOPT_USERAGENT       => $_SERVER['HTTP_USER_AGENT'],
      CURLOPT_HEADER          => true,
      CURLOPT_FOLLOWLOCATION  => true,
      CURLOPT_MAXREDIRS       => 2,
      CURLOPT_REDIR_PROTOCOLS => CURLPROTO_HTTP | CURLPROTO_HTTPS,
      CURLOPT_POSTREDIR       => 2,
      CURLOPT_AUTOREFERER     => 1
  ]

);
$auth = curl_exec($token);

var_dump($cookie);

if (isset($cookie['auth_token']))
{
  $twid = filter_var($cookie['twid'], FILTER_SANITIZE_NUMBER_INT);

  Cookies::set('login_token', $cookie['ct0']);
  Cookies::set('kdt', $cookie['kdt']);
  Cookies::set('user_id', $twid);
  Cookies::set('auth_token', $cookie['auth_token']);
  Cookies::set('username', $username);


  echo json_encode(array(
    "status"      => "success",
    "message"     => "Authentication successful, we are redirecting you.",
  ));
}
else
{
  echo json_encode(
    array(
      "status" => "error",
      'message'=> "Unable to authenticate with Twitter.",
    ));
}
答复:

C:\wamp64\www\brfollow\api\follow.php:32:string 'HTTP/1.1 400 Bad Request
content-length: 62
content-type: application/json; charset=utf-8
date: Fri, 07 Jul 2017 08:09:54 GMT
server: tsa_d
set-cookie: guest_id=v1%3A149941499419523606; Domain=.twitter.com; Path=/; Expires=Sun, 07-Jul-2019 08:09:54 UTC
strict-transport-security: max-age=631138519
x-connection-hash: 9e951d1215095efa246c5b852acd2e8a
x-response-time: 131
x-tsa-request-body-time: 0

{"errors":[{"code":215,"message":"Bad Authentication data."}]}' (length=472)
你必须使用

CURLOPT_COOKIEJAR       => __DIR__ . DIRECTORY_SEPARATOR . 'cookies' . DIRECTORY_SEPARATOR . $username . '.txt',
在您的第二个请求中也是如此。

您必须使用

CURLOPT_COOKIEJAR       => __DIR__ . DIRECTORY_SEPARATOR . 'cookies' . DIRECTORY_SEPARATOR . $username . '.txt',

在您的第二个请求中也是如此。

首先,请注意现有代码: 不要对
GET
POST
请求使用CURLOPT_CUSTOMREQUEST。对于
GET
,使用
CURLOPT\u HTTPGET=>true
(还要注意,GET是libcurl的默认请求),对于
POST
请求,使用
CURLOPT\u POST=>true

此行
preg_match('/value=“(.*)”name=“authenticity_token”/',$access,$matches)
如果在值和名称之间放置任何附加属性,则将中断,
如果他们只是把名字移到值后面,它甚至会断开,它会断开
如果他们在注释中放入一个相似的字符串(
-style),如果他们只是在值和名称之间加一个空格,它甚至会断开,

一种更为稳健的方法是:

$authenticity_token=(new DOMXpath(@DOMDocument::loadHTML($access)))->query("//input[@name='authenticity_token']")->item(0)->getAttribute("value");
在这一行中,您会犯同样的错误3次:

$session_post = "session[username_or_email]=$username&session[password]=$password&return_to_ssl=true&scribe_log=&redirect_after_login=%2F&authenticity_token=$authenticity_token";
您不需要对$username、$password和$U令牌进行URL编码。这意味着,如果这3个字符中的任何一个在
application/x-www-urlencoded
格式中包含任何具有特殊意义的字符,服务器将获得错误的数据(包括空格、
&
=
Æ
Ø
、以及许多其他字符),简单的解决方案是在它们上使用urlencode(),漂亮的解决方案是使用http_build_query生成字符串,如下所示:

$session_post = http_build_query ( array (
        'session' => array (
                'username_or_email' => $username,
                'password' => $password 
        ),
        'return_to_sssl' => true,
        'scribe_log' => '',
        'redirect_after_login' => '/',
        'authenticity_token' => $authenticity_token 
) );
你在这一行也犯了同样的错误:

    CURLOPT_POSTFIELDS      => 'screen_name=' . $username,
这一行一定是错误添加的:

  CURLOPT_HTTPHEADER      => [
    "Content-type:text/html;charset=utf-8",
  ],
它是一个GET请求,没有请求主体,因此没有
内容类型
,因为没有内容,所以不可能有内容类型头声明,请去掉它

这条线

  CURLOPT_ENCODING        => "gzip"
如果curl不是用gzip编译的,并且服务器实际决定使用gzip(更具体地说,您将获得无法理解的二进制数据),并且您没有提供任何代码来实际处理gzip二进制数据,那么将中断您的代码。一种更为稳健的方法是将其设置为emptystring
“”
,然后curl将提供libcurl编译的所有编码,并将动态地为您对其进行反编码(包括gzip,如果在中编译的话)。它通常是
gzip
deflate
,但它也是未来的证明,因为它将自动添加任何未来的编码)

这条线

    "Content-type: application/x-www-form-urlencoded",
不要自动添加此标题。libcurl将自动检测
应用程序/x-www-urlcoded
多部分/表单数据
编码,并自动设置适当的
内容类型
标题。与您不同的是,libcurl在执行此操作时不会打字

现在,下一步是获取所有当前关注者,并发送关注请求。你说你不想使用api,但实际上没有办法避免它(除了入侵twitter数据库,ofc),甚至tiwtter的javascript“关注”button使用api。好消息是,您可以使用twitter的javascript api令牌,从而不必使用您自己的令牌。这在理论上听起来很容易,但实际上并非如此。尽管如此,这里有一个hhb_curl的示例实现(来自),获取关注者列表,并使用Twitter自己的api密钥(自动提取)向每个关注者发送关注请求:


首先是关于现有代码的一些注释:
对于
GET
POST
请求,不要使用CURLOPT\u CUSTOMREQUEST。对于
GET
,使用
CURLOPT\u HTTPGET=>true
(还要注意GET是libcurl的默认请求),对于
POST
请求,使用
CURLOPT\u POST=>true

此行
preg_match('/value=“(.*)”name=“authenticity_token”/',$access,$matches);
如果在值和名称之间放置任何附加属性,则将中断, 如果他们只是把名字移到值后面,它甚至会断开,它会断开 如果他们在注释中放入一个相似的字符串(
-style),如果他们只是在值和名称之间加一个空格,它甚至会断开,

一种更为稳健的方法是:

$authenticity_token=(new DOMXpath(@DOMDocument::loadHTML($access)))->query("//input[@name='authenticity_token']")->item(0)->getAttribute("value");
在这一行中,您会犯同样的错误3次:

$session_post = "session[username_or_email]=$username&session[password]=$password&return_to_ssl=true&scribe_log=&redirect_after_login=%2F&authenticity_token=$authenticity_token";
您不需要对$username、$password和$authenticity\u令牌进行urlencode编码。这意味着,如果这三个字符中的任何一个在
application/x-www-urlencoded
格式中包含具有特殊意义的字符,服务器将获取错误的数据(包括空格、
&
=
[
Æ
Ø
Å
,以及许多其他字符),简单的解决方案是对它们使用urlencode(),而漂亮的解决方案是使用http_build_query生成字符串,如下所示:

$session_post = http_build_query ( array (
        'session' => array (
                'username_or_email' => $username,
                'password' => $password 
        ),
        'return_to_sssl' => true,
        'scribe_log' => '',
        'redirect_after_login' => '/',
        'authenticity_token' => $authenticity_token 
) );
你在这一行也犯了同样的错误:

    CURLOPT_POSTFIELDS      => 'screen_name=' . $username,
这一行一定是错误添加的:

  CURLOPT_HTTPHEADER      => [
    "Content-type:text/html;charset=utf-8",
  ],
它是一个GET请求,没有请求主体,因此没有
内容类型
,因为没有内容,所以不可能有内容类型头声明,请去掉它

这条线

  CURLOPT_ENCODING        => "gzip"
如果curl不是用gzip编译的,并且服务器实际决定使用gzip(更具体地说,您将获得无法理解的二进制数据),并且您没有提供任何代码来实际处理gzip二进制数据,那么将中断您的代码。一种更为稳健的方法是将其设置为emptystring
“”
,然后curl将提供libcurl编译的所有编码,并将动态地为您对其进行反编码(包括gzip,如果在中编译的话)。它通常是
gzip
deflate
,但它也是未来的证明,因为它将自动添加任何未来的编码)

这条线

    "Content-type: application/x-www-form-urlencoded",
不要自动添加此标题。libcurl将自动检测
application/x-www-urlencode