はじめに
Twitter APIを使用してTwitter botを作成していたのですが、APIの仕様変更により、2023年6月頃のツイートを最後に実行されなくなってしまいました。
bot復活までの対処についてまとめます。
botは次のような仕組みで実装していました。
- GAS(Google Apps Script)をトリガーにPHPのスクリプトをキック
- PHPからTwitterOAuthというライブラリを使用してTwitter APIを操作
- ツイートのポストやファボ、ツイートを取得する
サーバー環境は次のとおりです。
- 開発環境:VirtualBoxのCentOS7.5(Vagrant:bento/centos-7.5)
- 本番環境:さくらのレンタルサーバ - ライトプラン
改修前のアプリのバージョンです。
- PHP:7系
- TwitterOAuth:0.7.2(おそらく)
- Twitter API:v1.1
改修後のアプリのバージョンです。
- PHP:8系
- TwitterOAuth:6.6.6
- Twitter API:v1.1とv2の併用
2017年に作成したきりほとんど改修もしていなかったためTwitter API以外の改修範囲も多く、また、開発環境と本番環境で手順が異なり戸惑ったりと、bot復活までにかなり苦労しました。
結局はTwitter APIの無料プランでは使用できるエンドポイント(Twitter APIにアクセスするためのアドレス)がかなり限定されており、完全に復活させることはできませんでした。
おおまかな手順
bot復活までのおおまかな手順です。
原因の究明
ログの確認
スクリプト実行時のログを確認したところ、次のメッセージが出ていました。
object(stdClass)#17 (1) { ["errors"]=> array(1) { [0]=> object(stdClass)#11 (2) { ["code"]=> int(32) ["message"]=> string(27) "Could not authenticate you." } } }
「あなたを認証できませんでした」とのことです。
認証情報の確認
Twitterのデベロッパーサイトで認証情報を確認しました。
The v1.1 APIs have been deprecated and your app is no longer able to access those v1.1 APIs. Please create a new application using one of our v2 Free, Basic or Pro plans today!
「v1.1のAPIは廃止されアクセスできなくなりました。今すぐv2の無料プラン、ベーシックプラン、プロプランのいずれかを使用して新しいアプリケーションを作成してください!」とのことです。
対処
Twitter APIのバージョン変更
まずはTwitter APIのバージョンをv1.1からv2に変更します。
-
Twitter DevelopersのTwitter API v2のページから無料プランへのダウングレードのボタンをクリックする
バージョン変更後、スクリプトを実行したところ、エラーログが出ました。
object(stdClass)#8 (1) { ["errors"]=> array(1) { [0]=> object(stdClass)#3 (2) { ["message"]=> string(272) "You currently have access to a subset of Twitter API v2 endpoints and limited v1.1 endpoints (e.g. media post, oauth) only. If you need access to this endpoint, you may need a different access level. You can learn more here: https://developer.twitter.com/en/portal/product" ["code"]=> int(453) } } }
「Twitter APIのエンドポイントへアクセスするには、別のアクセスレベルが必要です。詳しくはこちらをご覧ください」とのことです。
詳しくをこちらのURLへアクセスし、v2エンドポイントの詳細を確認します。
In order to use v2 endpoints, you will need the following things:
A developer account
A developer App created within a Project
Keys and tokens from that Project’s developer App
「v2エンドポイントを使用するには、次のものが必要」とのことです。
- 開発者アカウント
- プロジェクト内に作成された開発者アプリ
- プロジェクトの開発者アプリのキーとトークン
If you would like to start using v2 endpoints, you will need to attach an App to a Project and use the credentials from that App when making requests to v2 endpoints.
また、「v2エンドポイントの使用を開始する場合は、Appをプロジェクトにアタッチし、v2エンドポイントへのリクエスト時にそのAppの認証情報を使用する必要があります」とのことです。
プロジェクトとアプリの設定
Twitter API v2を利用するにはプロジェクトが必要とのことなので、プロジェクトを作成し、アプリをひもづけます。
-
Twitter DevelopersのDashboardページから「Create Project」をクリックする
PHPのライブラリ「TwitterOAuth」の最新化
Twitter APIを操作するためのライブラリ「TwitterOAuth」がTwitter APIのv1.1にしか対応していなさそうだったので、最新版をインストールします。
インストールには、PHPのパッケージライブラリ管理ツールである「Composer」が必要です。
公式サイトのIntroduction - Composerのローカルインストールの手順にしたがってまずは「Composer」をインストールします。
Composerのインストール
-
Composerのサイトから、phpではじまる4行のスクリプトをコピーし、インストールしたいパスでコマンドを実行する
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" php -r "if (hash_file('sha384', 'composer-setup.php') === 'e21205b207c3ff031906575712edab6f13eb0b361f2085f1f1237b7126d785e826a450292b6cfd1d64d92e6563bbde02') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" php composer-setup.php php -r "unlink('composer-setup.php');"
※サイトに記載されているスクリプトは更新されるようなので、サイトから最新のスクリプトをコピーしてください
コマンドを実行した階層に「composer.phar」が作成されていればインストールは完了です。
TwitterOAuthのインストール
「Composer」と同じ階層に「TwitterOAuth」をインストールします。
-
カレントディレクトリはそのままで、次のコマンドを実行します。
php composer.phar require abraham/twitteroauth
-
もし「The zip extension and unzip/7z commands are both missing, skipping.」エラーが出た場合は、zipコマンドをインストールする
sudo yum install php-zip sudo yum install -y zip unzip
-
Apacheを再起動して、再度twitteroauthをインストールする
sudo service httpd restart php composer.phar require abraham/twitteroauth
「composer.json」「composer.lock」ファイルと、「vendor」フォルダーの中にabraham/twitteroauthのファイル群が作成されていればインストールは完了です。
PHPライブラリ読み込みパスの変更
指定したパスにvendor\abraham\twitteroauth
フォルダーが作成されました。
既存のフォルダー構成と異なってしまったので、パスを指定している箇所を変更します。
-
変更前
require "twitteroauth/autoload.php"; require "twitteroauth/src/TwitterOAuth.php"; use Abraham\TwitterOAuth\TwitterOAuth;
-
変更後
require "vendor/autoload.php"; use Abraham\TwitterOAuth\TwitterOAuth;
「TwitterOAuth.php」は読み込まなくてもよくなったようです。
自分はこれを読み込んでいたせいで、なぜか開発環境では実行できるのに本番環境では500エラーになる現象がおき、3日間理由がわからず苦しみました…。
変更後、スクリプトを実行したところ、エラーログが出ました。
Composer detected issues in your platform:
Your Composer dependencies require a PHP version ">= 8.0.0". You are running 7.1.33.
どうやら最新の「TwitterOAuth」はPHP8にしか対応していないそうです。
調べるとPHP7のサポートは終了しているようで、PHP8を利用したほうがよさそうでした。
PHPのバージョンを8に変更
開発環境
Vagrantで構築した仮想環境のCentOS7.5にPHP8をインストールします。
-
現在のPHPのバージョンを確認する
php -v
実行結果
PHP 7.1.33 (cli) (built: Nov 15 2021 10:04:41) ( NTS ) Copyright (c) 1997-2018 The PHP Group Zend Engine v3.1.0, Copyright (c) 1998-2018 Zend Technologies with Xdebug v2.9.8, Copyright (c) 2002-2020, by Derick Rethans
-
インストール済みのPHP関連パッケージを確認する(念のためメモしておく)
yum list installed php*
実行結果
Loaded plugins: fastestmirror Repodata is over 2 weeks old. Install yum-cron? Or run: yum makecache fast Loading mirror speeds from cached hostfile * base: ftp.riken.jp * epel: ftp.riken.jp * extras: ftp.riken.jp * remi-safe: ftp.riken.jp * updates: ftp.riken.jp Installed Packages php.x86_64 7.1.33-19.el7.remi @remi-php71 php-cli.x86_64 7.1.33-19.el7.remi @remi-php71 php-common.x86_64 7.1.33-19.el7.remi @remi-php71 php-devel.x86_64 7.1.33-19.el7.remi @remi-php71 php-gd.x86_64 7.1.33-19.el7.remi @remi-php71 php-json.x86_64 7.1.33-19.el7.remi @remi-php71 php-mbstring.x86_64 7.1.33-19.el7.remi @remi-php71 php-pdo.x86_64 7.1.33-19.el7.remi @remi-php71 php-pecl-xdebug.x86_64 2.9.8-1.el7.remi.7.1 @remi-php71 php-xml.x86_64 7.1.33-19.el7.remi @remi-php71
-
PHPを削除する
sudo yum remove "php*"
-
epel-releaseのアップデートをする
sudo yum update epel-release
-
remiのリポジトリを検索し、remi-php81.repoがあるか確認する
ll /etc/yum.repos.d/ | grep remi-
ない場合は、次のコマンドでリポジトリをインストールする
yum install http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
-
PHP8.1をインストールする
sudo yum -y install --enablerepo=remi,remi-php81 php php-cli php-common php-devel php-mbstring php-pdo php-gd php-xml php-mcrypts php-pecl-xdebug
-
PHPのバージョンを確認し、PHP8.1になっていれば完了
php -v
-
Apacheを再起動する
sudo service httpd restart
本番環境
本番環境である「さくらのレンタルサーバ」のPHPのバージョンを変更します。
こちらの手順を参考にPHP8.1.20へ変更しました。
PHPのバージョンを変更したい | さくらのサポート情報
PHPのスクリプトの改修
PHPのバージョンを8.1にしてもスクリプトは実行されず、調べるとTwitter API v2になったことにより使えなくなったエンドポイントあるようです。
PHPのスクリプトをTwitter API v2用に書き換える必要がありました。
エンドポイントの移行表はこちらにまとめられています。
Twitter API endpoint map | Docs | Twitter Developer Platform
ざっくり次のようにPHPを書き換えました。
文字のみのツイート
-
変更前
//引数で渡したメッセージを呟く function tweet($message){ // ツイッターにアクセスする $connection = new TwitterOAuth( CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN, ACCESS_TOKEN_SECRET ); //つぶやく $result = $connection->post("statuses/update", array("status" => $message)); //返ってきた内容を確認してみる return var_dump($result); }
-
変更後
//引数で渡したメッセージを呟く function tweet($message){ // ツイッターにアクセスする $connection = new TwitterOAuth( CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN, ACCESS_TOKEN_SECRET ); //v2の動作にする $connection->setApiVersion('2'); //つぶやく $result = $connection->post("tweets", ["text" => $message], true); //返ってきた内容を確認してみる return var_dump($result); }
v1.1ではpostはできなくなってしまったようです。
なので、明示的にAPIのバージョン2
を指定してあげて、postをv2の書き方に変えてあげる必要がありました。
画像付きのツイート
-
変更前
//引数で渡した画像とメッセージを呟く function tweetMedia($message, $mediaURL){ // ツイッターにアクセスする $connection = new TwitterOAuth( CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN, ACCESS_TOKEN_SECRET ); //画像をアップロードし、画像のIDを取得する $imageId = $connection->upload("media/upload", array("media" => "$mediaURL")); //つぶやく $result = $connection->post("statuses/update", array("status" => $message, 'media_ids' => implode(',', [$imageId->media_id_string]))); //返ってきた内容を確認してみる return var_dump($result); }
-
変更後
//引数で渡した画像とメッセージを呟く function tweetMedia($message, $mediaURL){ // ツイッターにアクセスする $connection = new TwitterOAuth( CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN, ACCESS_TOKEN_SECRET ); //v1.1の動作にする(Twitter API v2は画像のアップロードがまだ未対応のため) $connection->setApiVersion('1.1'); //URLから画像コンテンツを取得する $contents = file_get_contents($mediaURL); //MIME_TYPEを取得する $finfo = finfo_open(FILEINFO_MIME_TYPE); $mime_type = finfo_buffer($finfo, $contents); finfo_close($finfo); //拡張子を設定する if(substr($mime_type,0,6) == 'image/'){ $extension = substr($mime_type,6); }else{ //画像じゃない場合は文字のみツイートする tweet($message); Exit; } //画像を保存するパスを指定する $mediaPath = dirname(__FILE__) . "/image/TMP_image." . $extension; print var_dump($mediaPath); //画像をサーバーに保存する(上書き保存) file_put_contents($mediaPath, $contents); //画像をアップロードし、画像のIDを取得する $imageId = $connection->upload("media/upload", ["media" => $mediaPath]); //これ以降はv2の動作にする $connection->setApiVersion('2'); $parameters = [ 'text' => $message, 'media' => [ 'media_ids' => [$imageId->media_id_string], ] ]; //つぶやく $result = $connection->post('tweets', $parameters, true); //返ってきた内容を確認してみる return var_dump($result); }
こちらはちょっとややこしいです。
画像のuploadはv2ではまだ未実装のため、upload処理はv1.1で行い、ツイートのpostはv2で行います。
さらにこのスクリプトでは、画像はファイルそのものをuploadするのではなく、Google Driveに格納している画像のURLを指定しています。
昔はURLの指定でuploadできたのですが、最新版ではファイルパスを指定しないとuploadできなくなっていました。
そのため一度サーバーに画像ファイルを保存してからuploadしています。ファイルを保存するときに拡張子を判定しています。
いいね、リプライなど
こちらについては、Twitter API v2の無料プランでは実行できなくなりました。
無料プランで使用できるエンドポイントは、次の3種類だけです。
- POST /2/tweets(ツイートのポスト)
- DELETE /2/tweets/:id(ツイートの削除)
- GET /2/users/me(自分のユーザー情報の取得)
プランによって使用できるエンドポイントは、Twitter DevelopersのTwitter API v2のページに記載されています。
Docsに現在掲載されているアクセスレベル(プラン)についてのドキュメントは古いものも混在していそうです。
こちら「Essential」「Elevated」…といったアクセスレベルは、申し込みページに遷移してもページが存在せず廃止された情報と思われます。
What's new with Twitter API v2 | Docs | Twitter Developer Platform
おそらく最新の情報はこちらです。
Twitter API Documentation | Docs | Twitter Developer Platform
情報がいろいろと混在していますが、2023/08/03現在では、Twitter APIのアクセスレベルとエンドポイントについてはこのページの情報が正しそうです。
Getting Started with the Twitter API | Docs | Twitter Developer Platform
このページによると、無料プランで使用できるエンドポイントは次のとおりです。
- Twitter API v2:Tweet作成のみ
- Twitter API v1.1:メディアのuploadなど限定されたもののみ
よって、v2でツイートの検索ができないからといって、かわりにv1.1で行うこともできないようです。
さいごに
ここ数か月でのTwitter(正しくはXですね…)の動きは目まぐるしく、最新の情報を探し出すのがかなり大変でした。
botを復活させるのに結局5日ほどかかってしまい、めちゃ大変でした。