Archive for the ‘ruby’ Category

{ 2010.11.9 }

SlideShare APIを使う

    はてなブックマーク - SlideShare APIを使う
    このエントリーをはてなブックマークに追加

    PHP Matsuri が一段落しましたので、ここでrubyの登場です。
    どうも、ヤマモトです。
    MA6も締切りが過ぎてしまいましたね。
    僕も何か応募したいと思いつつ、ありきたりのサービスしか思いつかなく結局なにも応募せず。。。

    MA6には当然入ってないんですが、スライド共有サービスの最大手であるSlideShareも、実はAPIを公開しています。
    今回はそのAPIの、APIキーの発行からキーワード検索までについて紹介したいと思います。

    SlideShare API
    www.slideshare.net/developers

    APIを利用するには、ユーザー登録が必要です。
    すでに登録している方でも、APIキー発行を行なってください。
    Apply for API Key
    から行ないます。
    発行処理を行うと、「APIキー」と「シークレットキー」がメールで届きます。
    これらを使って、APIを利用します。

    APIメソッドには様々な種類がありますが、基本的な「IDに紐づくデータの取得」をやってみます。
    そのメソッドは、「Get Slideshow Information」で、
    URLは、「http://www.slideshare.net/api/2/get_slideshow」
    必要なパラメータは、

    ・api_key
    ・ts
    ・hash
    ・id

    です。
    上3つは、どのメソッドにも必要な認証のためのパラメーターです。

    「api_key」はメールで送られたAPIキー。
    「ts」は「タイムスタンプ」のことで、現在の時刻をUNIXのTimestamp型に変換したものを付与します。
    最後の「hash」が若干手間で、「メールで送られたシークレットキー」+「現在の時刻のUNIX Timestamp」を、「SHA1でハッシュ値化したもの」です。
    「ts」に付与する現在の時刻と、「hash」に使用する現在の時刻は同一でないといけませんが、厳密に現在の時刻でなくてもいいようです。

    さらに、「id」を付与することで、そのIDに紐づくデータがxmlで返却されます。

    ruby(rails)で書いたソースを下に表示します。

    api_key = "API_KEY"
    secret_key = "SECRET_KEY"
    now_time = Time.now.to_i
    hash = Digest::SHA1.hexdigest("#{secret_key}#{now_time}")
    Net::HTTP.start('www.slideshare.net', 80) {|http|
      response = http.get("/api/2/get_slideshow?api_key=#{api_key}&ts=#{now_time}&hash=#{hash}&id=XXX")
      @xml_object = REXML::Document.new response.body
    }
    respond_to do |format|
      format.xml  { render :xml => @xml_object }
    end

    これで該当のIDに関するデータがXMLで表示されます。
    これを応用すれば、他のウェブサービスにも組み込んで、以下のようなキーワードにヒットするデータをサムネイル付きで表示する画面も作れます。

    MA6のAPIリストにSlideShareがもし入っていたら、何らかの面白いサービスができたのかもしれません。

      はてなブックマーク - [Rails] TZInfoで、アクセス元のタイムゾーンに合わせる
      このエントリーをはてなブックマークに追加

      前略、ヤマモトです。

      みなさんはウェブサービスを立ち上げる際、タイムゾーンは意識されているでしょうか。
      日本国内のみのサービスであれば、時間帯は1つなので特に意識する必要はないと思いますが、
      これが全世界で利用して欲しいサービスであれば話が変わります。

      日本時間で「午後1時から午後2時まで限定公開」というプレミアコンテンツを予告し、全世界に公開したとしても、日本時間であると注釈しない限り、ユーザーはその地域の時間だと捉えるでしょう。
      「見てみたらまだ始まってなかった」ならまだいいでしょうが、日本は、全世界でも先の時間を行ってますから、ほとんどの地域の人からしたら「見てみたら終わってた」状態ですね。

      話は逸れますが、アメリカのような複数のタイムゾーンがある国では、ウェブサービスの時間の処理はどう行っているんでしょうか。
      いや、ウェブサービスに限らず、例えばテレビ番組は、ニューヨークでは午後7時から放送でも、サンフランシスコでは午後4時からとなるので、
      この場合の宣伝の仕方はどうしているんでしょうね。
      恐らく時間帯の注釈があるんでしょうが、アメリカに知り合いはいないのでちょっと謎です。
      YouTubeやFacebookといった全世界向けウェブサービスを見てみましたが、
      アメリカのプロキシ経由でアクセスしたり、言語設定を「英語」にしてアクセスしたりしても、とくに時間に変化はなさそうでした。

      かといって、タイムゾーンを考慮しない実装はできません。
      というのは、自社サービスであるZENPREの話ですが、これにはプレゼンテーションの開始時間と終了時間という概念があり、
      その間でしかリアルタイムな配信はされません。
      つまり、その地域に合った時間を表示しないと、世界中の人が見ることはできません。

      1番の解決策は、ユーザーにタイムゾーンを設定してもらうことでしょう。
      初めてアクセスがあった場合、必ずタイムゾーンの設定をしてもらう。
      あとはcookieにでも保存しておいて次回以降は、そのタイムゾーンを使う。
      ですが、その機構を作るための期間が取れず、また、果たしてそれが最適解だろうかというのもあったため、実装を見送りました。

      さて、かなり前置きが長くなってしまいましたが、
      ユーザーのタイムゾーンを取得するにあたって、自動で取得するため「TZInfo」というRubyのライブラリを使用することにしました。

      TZInfo – Ruby Timezone Library

      TZInfoは、国コードから該当するタイムゾーンを表示してくれます。
      例えば日本の場合、

      tz = TZInfo::Country.get("JP")
      tz.zone_identifiers # "Asia/Tokyo"

      となります。
      国コードの取得は

      Locale.get.country

      でできます。
      これを、application_controller.rbあたりで

      Time.zone = tz.zone_identifiers[0]

      とすれば、タイムゾーンが動的に設定できます。
      ※tz.zone_identifiersは配列

      ただし、これがタイムゾーンが複数ある地域になると問題です。

      tz = TZInfo::Country.get("US")
      tz.zone_identifiers
      ⇒America/New_York America/Detroit America/Kentucky/Louisville America/Kentucky/Monticello America/Indiana/Indianapolis ... America/AdakPacific/Honolulu

      となり、候補が複数取得できます。
      ここから、その地域を特定するのは不可能かと思います。
      現状では、「複数取得されたら、1番目のタイムゾーンを選択する」ことにしました。
      さらに、時間表示の部分には全て、現在適用されているタイムゾーンを表示することで、時間誤認のリスクを減らしています。

      現在のタイムゾーンを表示するメソッド

      Time.zone.now.zone"JST"
      ※日本の場合

      以上が、タイムゾーンを自動で取得する方法です。
      Railsは、DBへ時刻を格納するとき、どの地域であろうとも標準時間でセットしてくれるので、
      このようなカスタマイズも容易です。

      ただし、これが最適解ではないので、何からしらの別の方法が見つかればと思います。

      { 2010.9.29 }

      as3cryptoで暗号化

        はてなブックマーク - as3cryptoで暗号化
        このエントリーをはてなブックマークに追加

        こんにちは。
        ユニコーン好きのruby使い、ヤマモトです。

        今回は、ActionScriptで暗号化した文字列を、rubyで複合化して受け取る、というのをやります。

        ActionScriptには as3crypto という便利なライブラリが提供されていて、aesやdesなどのアルゴリズムを使用しての暗号化・複合化が可能です。
        code.google.com/p/as3crypto/

        デモページも用意されていて、コードを書く前にあれこれ試すことができます。
        crypto.hurlant.com/demo/

        SecretKeyからデモが行えますが、簡単な説明としては以下のとおりです。

        Encryption : 暗号アルゴリズム選択(AES,3DESなど)
        Mode : 暗号利用モード選択(CBC,CFBなど)
        Padding : 公開鍵暗号技術規格(PKCS#5)

        KeyFormat に秘密鍵を、
        PlainText に変換したい文字列を入力して Encrypto を押すと暗号化された文字列がCipherTextに表示されます。
        このとき、表示モードをText以外にしないと、バイナリデータとして表示されますので、Hex等でシリアライズするのがいいでしょう。

        で、これの実装方法ですが、
        以下の通り書きました。
        前提として、
        秘密鍵 : “hogehoge”
        暗号化する文字列 : “fugafuga”
        暗号アルゴリズム : AES
        暗号利用モード : ECB
        を使用します。

        as側

        public function encrypt(str:String):ByteArray {
        	var e:ByteArray = new ByteArray();
        	var key:ByteArray = Hex.toArray(Hex.fromString("hogehoge"));
        	var src:ByteArray = Hex.toArray(Hex.fromString(str));
        	var pad:IPad = new PKCS5();
        	var cipher:ICipher = Crypto.getCipher("aes-ecb", key, pad);
        	pad.setBlockSize(cipher.getBlockSize());
        	cipher.encrypt(src);
        	e.writeObject(src);
        	return src;
        }

        これで、

        encrypt_data = encrypt("fugafuga")

        で暗号化の文字列がバイナリで返されます。
        これを、Base64コードに変換してXMLにてrubyに渡し、復号化を行ないます。

        rubyではOpenSSL::Cipherクラスを使用して復号化を行ないますが、
        その前に、受け取るデータのデシリアライズをしなくてはいけません。
        as側で、暗号化文字列をBase64コードに変換していましたので、これを元に戻します。

        require 'base64'
        # encrypt_data = 暗号化された文字列
        encrypt_data_byte = decode64(URI.decode(encrypt_data))

        あとは以下の要領で復号化です。

        def decrypt(data, key)
            c = OpenSSL::Cipher::Cipher.new("aes-128-ecb")
            begin
              c.decrypt
              c.key = "hogehoge"
              c.update(data) + c.final
            rescue Error => e
              logger.error("#{e.message}")
            end
          end
         
        # 復号化された文字列
        decrypt_data = decrypt(encrypt_data_byte)
         
        puts decrypt_data
        ⇒ "fugafuga"

        ロジック中にアルゴリズムや秘密鍵を直接指定していますが、
        そこは定数化などで汎用的にしてください。

        今回は、as・ruby間で行ないましたが、JavaやObjective-Cでも可能です。