LoginSignup
7
6

More than 5 years have passed since last update.

Rubyでgemを使わずに、twitterにツイート(ポスト)する

Posted at

はじめに

ツイートに際してはユーザー別のアクセストークンとアクセストークンシークレットが必要となります。
取得方法については、以下のページのソースを参考にしてください。

Rubyでgemを使わずに、twitterのアクセストークンを取得

ソースコード

※あくまで動かすようのサンプルです。ステータスチェックはきちんとやってくださいね。
※今回は行ってませんが、投稿の際、文字長のチェックが本来必要です。
※twitterの仕様で連続して同じ内容の投稿はできません。(403が帰ってくるんじゃなかったかな?)

post_tweet.rb

  def post_tweet
    #ユーザー別のアクセストークン
    oauth_token = "194485223--oauth_token --ynck19"
    #ユーザー別のアクセストークンシークレット
    oauth_token_secret = "BopAEWj--oauth_token_secret--DKy2iei"
    res = post_time_line(oauth_token, oauth_token_secret)
  #画面に投稿文が表示される
    render text: res["text"]
  end

  def post_time_line(oauth_token, oauth_token_secret)
    api_key = 'hogehogehogehoge'
    api_secret = 'fugofugofugofugo'
    post_params = {
      ## チルダはエスケープしない方がよいらしい
      ##ERB::Utilは~をエスケープする→RFC3986だとしないのが正しい
      "status" => escape("API_TEST ~+ ちるだプラス入れたろ!").gsub("%7E", "~")
    }
    oauth_params = {
        "oauth_consumer_key" => URI.escape(api_key),
        "oauth_nonce" => URI.escape(SecureRandom.uuid),
        "oauth_signature_method" => URI.escape('HMAC-SHA1'), 
        "oauth_timestamp" => URI.escape(Time.now.to_i.to_s),
        "oauth_token" => oauth_token,
        "oauth_version" => URI.escape('1.0')
    }
    params = post_params.merge(oauth_params)
    signature_key = "#{URI.escape(api_secret)}&#{URI.escape(oauth_token_secret)}"
    method = 'POST'
    request_url = "https://api.twitter.com/1.1/statuses/update.json"
    request_params  = sort_and_concat(params, "&")
    ## チルダはエスケープしない方がよいらしい
    signature_data = "#{URI.escape(method)}&#{escape(request_url)}&#{escape(request_params).gsub("%7E", "~")}"
    hash = OpenSSL::HMAC.digest(OpenSSL::Digest::SHA1.new, signature_key, signature_data)
    signature = escape(Base64.urlsafe_encode64(hash))
    params["oauth_signature"] = signature
    header_params = sort_and_concat(params, ',')
    twitter_uri = URI.parse(request_url)
    https = Net::HTTP.new(twitter_uri.host, twitter_uri.port)
    https.use_ssl = true
    https.verify_mode =  OpenSSL::SSL::VERIFY_NONE
    req = Net::HTTP::Post.new(twitter_uri)
    req["Authorization"] = "OAuth #{header_params}"
    https.set_debug_output $stderr
    res = https.request(req, body = sort_and_concat(post_params, '&'))
    json = JSON.parse(res.body)
    return json
  end

  def sort_and_concat(params, delimiter)
    params = params.sort
    str = params.collect{|k, v| "#{k}=#{v}"}.join(delimiter)
    return str
  end

  def escape(str)
    return ERB::Util.url_encode(str)
  end

はまったこと

投稿する文章によって、エラーが発生する。

当初、投稿内容を

"status" => "API_TEST ~+ ちるだプラス入れたろ!"

こんな感じにしていたところ、

+&=~ を投稿文に入れる
→401エラー
{"errors":[{"code":32,"message":"Could not authenticate you."}]}

% を投稿文に入れる
→:400エラー

といった具合にうまく動かない。


記号周りだからエスケープの問題だろということで

"status" => escape("API_TEST ~+ ちるだプラス入れたろ!").gsub("%7E", "~")

こんな感じにしました。

チルダ(~)以外、問題なく動くが、チルダだけはエラー

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


調べた結果、チルダのエスケープの問題らしく、以下に落ち着く

"status" => escape("API_TEST ~+ ちるだプラス入れたろ!").gsub("%7E", "~")

今回、エスケープはERB::Util.url_encodeを利用したのですが、
この子「a~z、A~Z、0~9、_(アンダースコア) -(ハイフン).(ピリオド)」以外はエスケープするらしい。

RFC3986によると

URIs that differ in the replacement of an unreserved character with
its corresponding percent-encoded US-ASCII octet are equivalent: they
identify the same resource. However, URI comparison implementations
do not always perform normalization prior to comparison (see Section
6). For consistency, percent-encoded octets in the ranges of ALPHA
(%41-%5A and %61-%7A), DIGIT (%30-%39), hyphen (%2D), period (%2E),
underscore (%5F), or tilde (%7E) should not be created by URI
producers and, when found in a URI, should be decoded to their
corresponding unreserved characters by URI normalizers.

どうも「a~z、A~Z、0~9、_(アンダースコア) -(ハイフン).(ピリオド) ~(チルダ)」はエスケープすべきじゃないよと言ってるのかな?

というわけで、上記記述で問題はなさそう。

ここに書いて思ったけど、escapeメソッドに切り出してるんだから、そっちにgsubつけた方がよかったのかな…

7
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
6