tech.kayac.com

映画「ソーシャルネットワーク」を見て創作意欲が湧き、コードが書きたくなったwatanabeです。

今年はFacebook元年と言われており、Facebookを利用した販促や広告、キャンペーンなどが増えてくるでしょう。
その中でよく使われそうな「アルバムへの投稿」をピックアップして、実装してみました。

今回はFacebookのPHPのSDKを利用します。
https://github.com/facebook/php-sdk/

SDKならソーシャルグラフAPIを使うと便利です。
Graph API Reference

折角なので、FQLも使ってみましょう。
http://developers.facebook.com/docs/reference/fql/

早速、日曜大工的にコードを書いてみたので、見てみましょう。  

クラス

<?php

include('lib/facebook.php');

class MyPhotoAlbumFacebook
{
    const APP_ID = '000000';

    const SECRET = 'xxxxxx';

    var $facebook;

    public function __construct()
    {
        $this->facebook = new Facebook(
                array(
                    'appId'  => self::APP_ID,
                    'secret' => self::SECRET,
                    'cookie' => true,
                    )
                );
    }

    public function login()
    {
        if (!$this->facebook->getSession()) {
            $loginParameters = array(
                    'canvas'    => 1,
                    'fbconnect' => 0,
                    'req_perms' => 'status_update, publish_stream, user_photo_video_tags, friends_photo_video_tags, user_photos, friends_photos'
                    );
            $url = $this->facebook->getLoginUrl($loginParameters);
            echo "<script type='text/javascript'>top.location.href = '$url';</script>"; 
            exit;
        }
        return true;
    }

    public function getFacebook()
    {
        return $this->facebook;
    }

    public function getMe()
    {
        return $this->facebook->api('/me');
    }

    public function postPhoto($source, $message = null, $tags = array())
    {
        $source = '@' . realpath($source);
        try {
            $requestParameters = array(
                    'access_token' => $this->facebook->getAccessToken(),
                    'message'      => $message,
                    'source'       => $source,
                    );
            if ($tags) {
                $requestParameters['tags'] = array($tags);
            }
            $this->facebook->setFileUploadSupport(true);
            $response = $this->facebook->api('me/photos', 'POST', $requestParameters);
        } catch (FacebookApiException $e) {
            throw $e;
        }
        return $response;
    }

    public function getProfilePhoto($uid)
    {
        // use FQL. (http://developers.facebook.com/docs/reference/fql/)
        $fql = 'SELECT pic_big FROM profile WHERE id = ' . $uid;
        $url = 'https://api.facebook.com/method/fql.query?query=' . urlencode($fql);
        $xml = simplexml_load_file($url);
        if (!$xml || !$xml->profile) {
            return false;
        }
        $source = (string)$xml->profile->pic_big;

        // create local file.
        $file = file_get_contents($source);
        $tmpfname = tempnam('/tmp', 'source');
        $handle = fopen($tmpfname, "w");
        fwrite($handle, $file);
        fclose($handle);
        return $tmpfname;
    }
}

コード

こちらのMyPhotoAdbumFacebookクラスを使い、下記のようにコードを書くだけで、
Facebookのアルバムに自分のプロフィールの写真を登録し、自分のタグをつけることができます。

$fb = new MyPhotoAlbumFacebook();
$fb->login();
$me = $fb->getMe();
$source = $fb->getProfilePhoto($me['id']);
$message = 'photo comment.';
$tags = array(
   'tag_text' => $me['name'],
   'tag_uid'  => $me['id'],
   'x'        => 50,
   'y'        => 25,
);
$response = $fb->postPhoto($source, $message, $tags);
print_r($response);

補足

$tags = array( 'tag_text' => $me['name'], 'tag_uid' => $me['id'], 'x' => 50, 'y' => 25, );

XとYはその方向の軸の割合の位置です。
横はセンタリング、縦は4分の1の位置を設定をしています。
もし人の写真だった場合、顔認識技術により自動的に位置が補正されるようです。(ドキュメント未確認)

$source = '@' . realpath($source);

SDKのファイルアップロード機能では、リモートのファイルをアルバムに投稿できないようです。
@をつけたローカルファイルの絶対パスを指定することにより、POSTすることができるようです。

'req_perms' => 'status_update, publish_stream, user_photo_video_tags, friends_photo_video_tags, user_photos, friends_photos'

アプリケーションの認証の際に必要な権限を掲示しますが、そのスコープになります。
今回のケースでは、友達の写真やタグ付けを扱っていないので、friends_photo_video_tagsfriends_photosは不要になります。
下記のドキュメントを確認して、適切なスコープを選択してください。
http://developers.facebook.com/docs/authentication/permissions

サンプル

Manga BusinessCard Maker
http://apps.facebook.com/manga-card-maker/

カヤックのお年賀コンテンツの一つとして、Facebookアプリを作ってみました。
Facebookのプロフィール写真からカンタンに漫画風名刺をつくることができるジェネレーターです。
名刺デザインは、熱血風やお姫様風、KAYACのサービスキャラクターをつかったものなど多数用意しています。
あけましておめでとうございます(遅)

次回予告

次回はFBMLやDialogについて触れようと思います。
若干クセがあるので現状だと使いにくく、慣れが必要かもしれません。
・・・ということで、慣れたらご紹介したいと思います。

 カヤックでは思い立ったらすぐコードが書ける技術者も募集しています!

今回カヤックでは2012年新卒のプログラマーを対象とした説明会を開催いたします。

カヤックの社員や雰囲気に触れてみたい方はもちろんのことプログラミングを主とする職に就きたい方や、iPhoneアプリやAndroidアプリに興味がある方など、みなさまふるってご参加ください!

----☆彡---------------------------------------------------
プログラミング経験者限定!
面白法人カヤックCEOCTO・若手技術者と語る少人数説明会【今回限り】
----------------------------------☆彡---------------------

当日はCEO(代表)CTO(技術部門のトップ)とお話ししていただく他、希望者には若手のプログラマーとの座談会も実施します。


【日時】
12/22(水)15:30から18:00頃まで
 ※終了時間は多少前後する場合があります

【会場】
面白法人カヤックが鎌倉本社の1階で運営するカフェ
DONBURI CAFE DINING「bowls」Google Map)にて

詳細はリクナビの会社説明会ページをご覧ください。


今回は2012年新卒のプログラマー限定の説明会となっておりますが、その他の職種に関しても随時更新していく開催していく予定です。

お楽しみにお待ちください!

JavaScript Advent Calendar 20105日目のago@kyo_ago)です。

jQueryのソースを眺めててjQuery.stopに引数があることに気づいたので調べてみました。

まず、簡単なスライドダウンメニューを作ってみたいと思います。

jQuery.stop 1 - jsdo.it - share JavaScript, HTML5 and CSS

JS部分は以下の通りです。

$(function () {
    $('div').hover(function () {
        $(this).find('ul').slideDown();
    }, function () {
        $(this).find('ul').slideUp();
    });
});

少し触ると分かると思いますが、マウスがmenuから外れた後も何度も.slideDown、.slideUpが実行されるため非常に操作性が悪いです。

jQueryはアニメーションが複数同時に呼ばれた場合、先に呼ばれたアニメーションが終了するまで次のアニメーションが呼び出されないように実装されており、このためユーザの操作で呼び出されるアニメーションをそのまま実装するとこういった動作になってしまいます。

こういった問題を解決するためにjQueryには.stopというメソッドが用意されており、このメソッドを呼び出すとその時点で実行されているアニメーションを停止させることが出来ます。

jQuery.stop 2 - jsdo.it - share JavaScript, HTML5 and CSS

JS部分は以下の通りです。

$(function () {
    $('div').hover(function () {
        $(this).find('ul').stop().slideDown();
    }, function () {
        $(this).find('ul').stop().slideUp();
    });
});

.stop無しのものにあった「マウスがmenuから外れた後も何度も.slideDown、.slideUpが実行される」問題は解決しています。

ただこのコードでも速い速度でmenu1?menu3のあいだを何度もマウスが往復しているとだんだんsub1?sub3の高さが減っていくと思います。

これは.stopが単純にアニメーションを停止させるだけなので、.slideDownの途中で呼び出された場合、その時点のheightが次回以降のheightとして認識されることが原因です。
(「.slideDownの途中で.stop」->「.stopが呼び出された時点のheightがその要素のheightとして設定されたままになる」->「次の.slideDownも前回のheightまでしか高さが変化しない」)

jQueryはこれに関しても対応が用意されており、.stopの第2引数(jumpToEnd)にtrueを渡してやると、アニメーションを停止した上で停止されたアニメーションの終了時点の表示まで処理を飛ばしてくれます。

jQuery.stop 3 - jsdo.it - share JavaScript, HTML5 and CSS

JS部分は以下の通りです。

$(function () {
    $('div').hover(function () {
        $(this).find('ul').stop(true, true).slideDown();
    }, function () {
        $(this).find('ul').stop(true, true).slideUp();
    });
});

どうでしょうか?最初のコードに対して.stop(true, true)を追加しただけですが、これだけで普通に使えるスライドダウンメニューになったのではないかと思います。

ちなみに第1引数(clearQueue)はその時点で実行待ちになっているアニメーションを全て停止させる指定ですが念のためtrueを指定しています。
(こういったユーザ動作で発生するアニメーションの場合、同時に実行されることは無いと思います)

個人的には非常に便利だと思うんですが、現状日本語のリファレンスサイトには解説されていないため、ドキュメントを確認したい場合本家APIの.stopを確認してください。

カヤックではAdvent Calendar好きな技術者も募集しています!