You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用PHP cURL生成Twitter API 1.1签名?认证错误排查

原生PHP实现Twitter(X) API OAuth签名认证失败排查(错误码32)

我尝试仅使用PHP和cURL为Twitter(X)API生成签名,不借助任何库或包,完全原生实现。已仔细阅读API文档并按步骤操作,但仍遇到认证错误,错误信息如下:

{"errors":[{"code":32,"message":"Could not authenticate you."}]}

我的主代码:

<?php

date_default_timezone_set('UTC');

$keys = array(
   "consumer_key" => "", // 替换为你的consumer key
   "consumer_secret" => "", // 替换为你的consumer secret
   "bearer_token" => "",
   "token_identifier" => "", // 替换为你的access token
   "token_secret" => "" // 替换为你的access token secret
);

$method = "POST";

$status = "Hello World!";

$endpoint = "https://api.twitter.com/1.1/statuses/update.json";

$nounce = bin2hex(random_bytes(16));

$T = time(); // 补全时间戳变量

$params = [
   "status" => $status,
   "include_entities" => "true",
   "oauth_consumer_key" => $keys['consumer_key'],
   "oauth_nonce" => $nounce,
   "oauth_signature_method" => "HMAC-SHA1",
   "oauth_timestamp" => $T,
   "oauth_token" => $keys['token_identifier'],
   "oauth_version" => "1.0",
];

// 直接调用全局签名函数,而非$API->signature
$signature = signature($method, $endpoint, $params, $keys['consumer_secret'], $keys['token_secret']);

echo $signature . '<br><br>';

$authHeader = 'OAuth ';

$authParams = array(
   "oauth_consumer_key" => $keys['consumer_key'],
   "oauth_nonce" => $nounce,
   "oauth_signature" => $signature,
   "oauth_signature_method" => "HMAC-SHA1",
   "oauth_timestamp" => $T,
   "oauth_token" => $keys['token_identifier'],
   "oauth_version" => "1.0",
);

$headerParts = [];

foreach ($authParams as $key => $value) {
   if (strpos($key, 'oauth_') === 0) {
      // 替换HTML转义引号为直接双引号
      $headerParts[] = $key . '="' . rawurlencode($value) . '"';
   }
}

$authHeader .= implode(', ', $headerParts);

echo $authHeader . '<br><br>';

$curl = curl_init();

curl_setopt_array($curl, [
   CURLOPT_URL => $endpoint,
   CURLOPT_RETURNTRANSFER => true,
   CURLOPT_POST => true,
   CURLOPT_POSTFIELDS => http_build_query(['status' => $status]),
   CURLOPT_HTTPHEADER => [
      'Authorization: ' . $authHeader,
      'Content-Type: application/x-www-form-urlencoded',
   ],
]);

$response = curl_exec($curl);

echo curl_errno($curl) ? 'Curl error: ' . curl_error($curl) : 'Response: ' . $response . '<br><br>';

curl_close($curl);

?>

我的签名函数:

function signature($method, $endpoint, $params, $consumerSecret, $tokenSecret = ''){

  $encodedParams = [];
  // 对参数的键和值都进行RFC3986编码
  foreach($params as $key => $value){
     $encodedParams[rawurlencode($key)] = rawurlencode($value);
  }

  ksort($encodedParams);

  $paramString = http_build_query($encodedParams, '', '&', PHP_QUERY_RFC3986);

  $encodedUrl = rawurlencode($endpoint);
  $encodedParamString = rawurlencode($paramString);
  $signatureBaseString = strtoupper($method) . "&" . $encodedUrl . "&" . $encodedParamString;

  $encodedConsumerSecret = rawurlencode($consumerSecret);
  $encodedTokenSecret = rawurlencode($tokenSecret);
  $signingKey = $encodedConsumerSecret . "&" . $encodedTokenSecret;

  $hash = hash_hmac('sha1', $signatureBaseString, $signingKey, true);

  $signature = base64_encode($hash);

  return $signature;

}

错误原因及修正说明

  • 未定义时间戳变量:原代码中$T未赋值,OAuth要求oauth_timestamp必须是当前UTC时间的Unix秒数,需添加$T = time();。
  • 参数编码不完整:签名函数未对参数的键和值做RFC3986编码,OAuth规范要求所有参与签名的参数都要先编码再排序拼接,修正了$encodedParams的赋值逻辑。
  • OAuth头部格式错误:原代码使用HTML转义的&quot;,应直接使用双引号,确保头部符合OAuth格式要求。
  • 无效的curl重复调用:curl_close()后再操作curl资源会触发错误,移除了这部分冗余代码。
  • 函数调用方式错误:原代码使用$API->signature(),但签名函数是全局函数,需直接调用signature()。

内容的提问来源于stack exchange,提问作者FarrisFahad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 02:43:13