PHP CURL: API-интерфейс Twitter с частичной загрузкой 408 на APPEND - PullRequest
0 голосов
/ 11 февраля 2020

У меня есть приложение php 5.6, и мне наконец-то удалось собрать сценарий загрузки в Твиттере, в комплекте с oauth и всем остальным ...

За исключением того, что я делаю Я могу только инициировать частичную загрузку, но не добавлять к ней APPEND, поскольку команда APPEND возвращает статус 408 (в соответствии с им это МОЖЕТ означать CANCELLED_REQUEST, хотя в теории это тайм-аут.) И никакого вывода примерно через 5 минут

Кто-нибудь знает, почему это происходит, или имеет какую-то подсказку?

Код ниже:

<?php

// Twitter limits: 4 images. 1 video, 1 gif.

/////////////////////////////////////////////////////////////////////////////////
$consumer_key = 'XXXXXXXXXXXXXX';
$consumer_secret = 'XXXXXXXXXXXXXXXXx';

$token_secret = 'XXXXXXXXXXXXXX';
$token = 'XXXXXXXXXXXX';
/////////////////////////////////////////////////////////////////////////////////




$settings = [
  "consumer_key" => $consumer_key,
  "consumer_secret" => $consumer_secret,

  "token" => $token,
  "token_secret" => $token_secret
];


function makeOAuth($settings, $method, $request_url, $postfields) {
  $signature_key = rawurlencode($settings['consumer_secret']) . '&' . rawurlencode($settings['token_secret']);

  $oauth = array(
    'oauth_consumer_key' => $settings['consumer_key'],
    //  'oauth_callback' => "http%3A%2F%2Fmyapp.com%3A3005%2Ftwitter%2Fprocess_callback",
    'oauth_nonce' => hash('md5', time()),
    'oauth_signature_method' => 'HMAC-SHA1',
    'oauth_token' => $settings['token'],
    'oauth_timestamp' => time(),
    'oauth_version' => '1.0'
  );

  if (!is_null($postfields)) {
      foreach ($postfields as $key => $value) {
          $oauth[$key] = $value;
      }
  }

  $return = array();
  ksort($oauth);

  foreach($oauth as $key => $value)
  {
      $return[] = rawurlencode($key) . '=' . rawurlencode($value);
  }

  $to_be_signed=  $method . "&" . rawurlencode($request_url) . '&' . rawurlencode(implode('&', $return));


  $signature = base64_encode(hash_hmac('sha1', $to_be_signed, $signature_key, true));

  $oauth['oauth_signature'] = $signature;

  $auth = 'Authorization: OAuth ';
  $values = array();

  foreach($oauth as $key => $value)
  {
      if (in_array($key, array('oauth_consumer_key', 'oauth_nonce', 'oauth_signature',
          'oauth_signature_method', 'oauth_timestamp', 'oauth_token', 'oauth_version'))) {
          $values[] = "$key=\"" . rawurlencode($value) . "\"";
      }
  }

  $auth .= implode(', ', $values);

  return $auth;
}



$upload_url = 'https://upload.twitter.com/1.1/media/upload.json';

$fname = 'new_account_btn.png';

echo 'opening '. realpath('../fotos/grande/' . $fname).'...';

$file = fopen(realpath('../fotos/grande/' . $fname), 'rb');
$size = fstat($file)['size'];
$mime_type = mime_content_type(realpath('../fotos/grande/' . $fname));


$postfields = array(
    "command" => "INIT",
    'media_type' => $mime_type,
  //  'media_category' => 'tweet_video',
    'total_bytes' => $size
);
var_dump($postfields);

// INITIALIZE upload

echo "requesting $upload_url..";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $upload_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST,       true);
curl_setopt($ch, CURLOPT_TIMEOUT, 20);

curl_setopt($ch, CURLOPT_HEADER,false);

curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postfields, '', '&'));
$oauth = makeOAuth($settings,'POST', $upload_url, $postfields);
echo $oauth;
curl_setopt($ch, CURLOPT_HTTPHEADER, [ $oauth, 'Expect: ']);

$result = json_decode(curl_exec($ch), true);


curl_close($ch);

var_dump($result);



$mediaId = $result['media_id_string'];

var_dump($mediaId);

$segmentId = 0;

while (!feof($file)) {
  $chunk = fread($file, 25000);

    echo strlen($chunk);


    $postfields = array(
        "command" => "APPEND",
        "media_id" => $mediaId,
        "segment_index" => $segmentId,

        "media" => $chunk
    );



$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $upload_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST,       true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST,       'POST');#####

curl_setopt($ch, CURLOPT_TIMEOUT, 60*10); # Modified: time out in 10 minutes.
curl_setopt($ch,CURLOPT_CONNECTTIMEOUT, 60*10); ###


$request = '';
$border = '--------------------' . uniqid();
foreach ($postfields as $key => $value) {
  $request .='--' . $border . "\r\n";
  $request.= 'Content-Disposition: form-data; name=' . $key;

  if ($key == "media") {
    $request.= "\r\nContent-Type: application/octet-stream";
  }


  /*    if ($key == "media") {
    //    $request.= '; filename="media"';
      }
*/
  // See codebird's _getMultipartRequestFromParams and  _checkForFiles
  $request .= "\r\n\r\n" . $value . "\r\n";
}

$request.= '--' . $border . "--\r\n";

var_dump($request);

#curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postfields, '', '&'));
#$oauth = makeOAuth($settings,'POST', $upload_url, $postfields);
$oauth = makeOAuth($settings,'POST', $upload_url, []);
echo $oauth;
#curl_setopt($ch, CURLOPT_HTTPHEADER, [ $oauth, 'Expect: ']);

echo 'Content-Length: '. strlen($request);
curl_setopt($ch, CURLOPT_HTTPHEADER, [

  'Content-Length: '. strlen($request),
  'Content-Type: multipart/form-data; boundary=' . $border,
  $oauth,
  'Expect: '
]);



$appendResult= curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);


    echo('chunk: '. $segmentId);

    echo ('status:'. $status);
echo "append result:";
    var_dump($appendResult);

    echo curl_error($ch);

    echo 'curl_errno:'.curl_errno($ch);

    echo "-------------------------------------------------------";
    curl_close($ch);
die();
    $segmentId++;
}

Также да, файл существует!

Редактировать: я изменил свой запрос APPEND на использование media_data (полезная нагрузка base64 вместо двоичного, как описано здесь ), но безрезультатно. Я получаю точно такой же результат.

...