/**
  * マイミクをアプリに招待するためのフォームを生成します。
  * 
  * @param string $callback 招待状送信後にコールバックするパス。
  *   指定可能なパスの書式は {@link Mars_RewriteRouter::buildRequestPath()} メソッドを参照。
  * @param mixed $extra オプション属性。'キー=値;' 形式の文字列、または連想配列での指定が可能。
  *   - recipients: 初期選択状態とするユーザ ID。カンマ区切りの文字列、または配列形式で指定可能。
  *   - message: メッセージ本文。
  *   - image: メッセージに含める画像。{@link communicationFeedForm()} メソッドの 'mediaItem1' 属性を参照。
  *   - filterType: 対象とするユーザの種別。'joined'、'nod_joinded'、'both' のいずれかを指定。既定値は 'joined'。
  *   - appendURI: TRUE が指定された場合、招待状にアプリ起動のための URI を追加します。既定値は FALSE。 
  *   - query: {@link communicationFeedForm()} メソッドの 'query' 属性を参照。
  *       未指定の場合はスタート画面が表示される。
  *   - mobileQuery: {@link communicationFeedForm()} メソッドの 'mobileQuery' 属性を参照。
  *       未指定の場合はスタート画面が表示される。
  *   - targetUsers: 友人の選択画面で表示するユーザのリスト。カンマ区切りの文字列、または配列形式で指定可能。
  *   - description: 友人の選択画面で表示する説明文。
  *   - excludeUsers: 友人の選択画面で非表示にするユーザのリスト。カンマ区切りの文字列、または配列形式で指定可能。
  *   - buttonLabel: 送信ボタンのラベル。
  * @return string 生成したタグを返します。
  * @link http://developer.mixi.co.jp/appli/spec/mob/for_partners/request_api リクエスト API について
  */
 public function inviteForm($callback = NULL, $extra = array())
 {
     $attributes = array();
     $attributes['action'] = Mars_MixiMobileApp::buildCallbackActionPath($callback, 'invite:friends');
     $attributes['method'] = 'post';
     $extra = parent::constructParameters($extra);
     $hiddenBuffer = NULL;
     $recipients = array_find($extra, 'recipients');
     $message = array_find($extra, 'message');
     $image = array_find($extra, 'image');
     $filterType = array_find($extra, 'filterType', 'joined');
     $appendURI = array_find($extra, 'appendURI', FALSE);
     $query = array_find($extra, 'query', array());
     $mobileQuery = array_find($extra, 'mobileQuery', array());
     $targetUsers = array_find($extra, 'targetUsers');
     $description = array_find($extra, 'description');
     $excludeUsers = array_find($extra, 'excludeUsers');
     $buttonLabel = array_find($extra, 'buttonLabel', '送信');
     if ($recipients !== NULL) {
         if (is_array($recipients)) {
             $recipients = implode(',', $recipients);
         }
         $hiddenBuffer .= $this->inputHidden('recipients', array('value' => $recipients));
     }
     if ($message !== NULL) {
         $hiddenBuffer .= $this->inputHidden('message', array('value' => $message));
     }
     if (is_array($image)) {
         $value = sprintf('%s,%s', Mars_HTMLHelper::buildAssetPath($image[0], 'image', array('absolute' => TRUE)), $image[1]);
         $hiddenBuffer .= $this->inputHidden('image', array('value' => $value));
     }
     if ($appendURI) {
         $uri = $this->buildLaunchURI(Mars_MixiApp::AGENT_TYPE_PC, $query);
         $hiddenBuffer .= $this->inputHidden('url', array('value' => $uri));
         $mobileURI = $this->buildLaunchURI(Mars_MixiApp::AGENT_TYPE_MOBILE, $mobileQuery);
         $hiddenBuffer .= $this->inputHidden('mobile_url', array('value' => $mobileURI));
     }
     if ($targetUsers !== NULL) {
         if (is_array($targetUsers)) {
             $targetUsers = implode(',', $targetUsers);
         }
         $hiddenBuffer .= $this->inputHidden('target_users', array('value' => $targetUsers));
     }
     if ($description !== NULL) {
         $hiddenBuffer .= $this->inputHidden('description', array('value' => $description));
     }
     if ($excludeUsers !== NULL) {
         if (is_array($excludeUsers)) {
             $excludeUsers = implode(',', $excludeUsers);
         }
         $hiddenBuffer .= $this->inputHidden('exclude_users', array('value' => $excludeUsers));
     }
     $buffer = sprintf("<form%s>\n%s%s%s%s", parent::buildTagAttribute($attributes, FALSE), $this->inputHidden('filter_type', array('value' => 'joined')), $hiddenBuffer, $this->inputSubmit($buttonLabel), $this->close());
     return $buffer;
 }
 /**
  * RESTful API に対してリクエストを送信します。
  * パフォーマンス上の観点から、PHP の zlib モジュールが有効な場合はデータを gzip 圧縮転送します。
  * 
  * @param array $parameters 送信するパラメータのリスト。
  *   <code>
  *   // 対象フィールドを foo、bar に指定
  *   $parameters = array('fields' => 'foo,bar');
  *   
  *   // フィルタリングの指定
  *   $parameters = array('filterBy' => 'hasApp');
  *   </code>
  * @param string $requestMethod {@link Mars_OAuthProvider::send()} メソッドを参照。
  * @return Mars_HttpResponseParser {@link Mars_OAuthProvider::send()} メソッドを参照。
  * @throws Mars_RequestException mixi からエラーが返された場合に発生。
  *   - {@link Mars_RequestException::getCode()} メソッドでレスポンスコードが取得可能。(コードの意味は mixi のマニュアルを参照)
  *   - OAuth の署名検証などでエラーが起きた場合は {@link http://oauth.pbworks.com/ProblemReporting 具体的な理由} が返される。
  *   - {@link Mars_RequestException::getAttribute() Mars_RequestException::getAttribute('error')} メソッドで返却されたレスポンスページを取得可能。
  * @see Mars_OAuthProvider::send()
  * @link http://developer.mixi.co.jp/appli/spec/mob/for_partners/mobile_api_detail RESTful API 仕様
  * @link http://developer.mixi.co.jp/appli/spec/mob/2-legged-oauth 2-legged OAuth による API アクセス
  */
 public function send($uri, $requestMethod = Mars_HttpRequest::HTTP_GET, $parameters = array(), $files = array())
 {
     $baseFeed = $this->buildEndpointURI($uri);
     $queryData = array();
     if ($requestMethod == Mars_HttpRequest::HTTP_GET || $requestMethod == Mars_HttpRequest::HTTP_DELETE) {
         $queryData = $parameters;
     }
     $queryData['xoauth_requestor_id'] = Mars_MixiMobileApp::getOwnerId();
     $request = OAuthRequest::from_consumer_and_token($this->_consumer, NULL, $requestMethod, $baseFeed, $queryData);
     $request->sign_request(new OAuthSignatureMethod_HMAC_SHA1(), $this->_consumer, NULL);
     // to_header() から返されるヘッダ名 ('Authorization: ') の部分を取り除く
     $authorization = substr($request->to_header(), 15);
     $uri = $baseFeed . '?' . http_build_query($queryData, '', '&');
     if ($requestMethod === Mars_HttpRequest::HTTP_POST) {
         $sender = new Mars_HttpRequestSender($uri);
         $sender->addParameters($parameters);
         $sender->setPostFormat(Mars_HttpRequestSender::FORMAT_JSON);
     } else {
         $sender = new Mars_HttpRequestSender($uri);
     }
     $sender->setRequestMethod($requestMethod);
     $sender->addHeader('Authorization', $authorization);
     // 圧縮転送を有効にする
     if ($this->_hasZlib) {
         $sender->addHeader('Accept-Encoding', 'gzip');
     }
     $parser = $sender->send();
     $status = $parser->getStatus();
     if ($status == 200) {
         return $parser;
     } else {
         $authenticate = $parser->getHeader('WWW-Authenticate');
         // OAuth の承認でエラーが起きた場合は oauth_problem に原因が格納される
         if (preg_match('/oauth_problem="([^"]+)"/', $authenticate, $matches)) {
             $message = sprintf('OAuth authenticate error. [%s]', $matches[1]);
         } else {
             $message = sprintf('mixi returned an error code. [%s]', $status);
         }
         $e = new Mars_RequestException($message, $status);
         $e->setAttribute('error', $parser->getContents());
         throw $e;
     }
 }
 /**
  * 指定したファイルを mixi フォトアルバムにアップロードするためのリンクタグを生成します。
  * ユーザがアンカーを押下した後、mixi から SAP 側 Web サーバにファイルの取得要求が送信されますが、この時 SAP 側では必ず署名の検証を行う必要があります。
  * 署名の検証は {@link Mars_Mixi2LeggedOAuthProvider::isAuthorized() Mars_Mixi2LeggedOAuthProvider::isAuthorized(Mars_Mixi2LeggedOAuthProvider::SIGNATURE_RSA_PHOTO_UPLOAD)} メソッドを使用して下さい。
  * 
  * @param string $path 投稿対象のファイルパス。PNG、JPEG 形式が指定可能。
  *   指定可能なパスの書式は {@link Mars_HTMLHelper::buildAssetPath()} メソッドを参照。
  * @param string $label {@link Mars_HTMLHelper::link()} メソッドを参照。
  * @param string $callback フォトアップロード後にコールバックするパス。 
  *   指定可能なパスの書式は {@link Mars_RewriteRouter::buildRequestPath()} メソッドを参照。
  * @param mixed $attributes タグに追加する属性。{@link Mars_HTMLHelper::link()} メソッドを参照。
  * @return string 生成したリンクタグを返します。
  * @link http://developer.mixi.co.jp/appli/spec/mob/for_partners/photo_upload_api アプリからフォトアップロード機能について
  * @since 1.9.0-p1
  * @author Naomichi Yamakita <*****@*****.**>
  */
 public function upload($path, $label, $callback, $attributes = array())
 {
     $queryData = array();
     $queryData['img_url'] = Mars_HTMLHelper::buildAssetPath($path, 'image', array('absolute' => TRUE));
     $path = Mars_MixiMobileApp::buildCallbackActionPath($callback, 'upload:photo', $queryData);
     $buffer = $this->baseLink($label, $path, $attributes, array());
     return $buffer;
 }
 /**
  * アプリケーションを mixi モバイルアプリモードで開始します。
  * start() メソッドが行う処理は次の通りです。
  * <ol>
  *   <li>{@link Mars_RewriteRouter::setIgnoreAppendGUID()} メソッドの実行。</li>
  *   <li>{@link Mars_ExceptionStackTraceDelegate::invokeFlush()} メソッドの実行</li>
  * </ol>
  * - mixi モバイルアプリを扱うモジュールでは、必ずフィルタ等を介して本メソッドをコールする必要があります。
  * - アプリケーションのエンコーディング形式は {@link Mars_UserAgentAdapter::getEncoding()} メソッドに依存します。
  * - PC 上で DoCoMo 端末をエミュレートした場合、mixi が出力するタグによっては XHTML パースエラーを引き起こす可能性があります。
  * 
  * @author Naomichi Yamakita <*****@*****.**>
  */
 public static function start()
 {
     $container = Mars_DIContainerFactory::getContainer();
     $userAgent = $container->getRequest()->getUserAgent();
     if ($userAgent->isDoCoMo()) {
         self::$_isDoCoMo = TRUE;
     }
     Mars_RewriteRouter::getInstance()->setIgnoreAppendGUID();
     // 直前までに出力されたタグが残ってると携帯で閲覧時に表示が崩れる可能性がある
     Mars_ExceptionStackTraceDelegate::invokeFlush();
 }