2010-09-11

【WebAPI】WebAPI処理クラス

前にホテル検索サイトをじゃらんのAPIで作ったときのメモ。

以前からWebAPIのXMLデータをパースするのがめんどくさくてしょうがなかったんだよね。
で、何とか簡単にパーサを組めないかと思って作ってみたのが「API抽象クラス」。
特にオブジェクト指向とか勉強したわけじゃないので、ぐっちゃりしたコードになってるけどご勘弁を。

仕組み的には抽象クラスにして「XMLパラメータとパーサをくくりだした」だけのものなんだけど、実際に抽象クラスから派生させたクラスにはパラメータ定義とパースのプログラムを書くだけになった。
一つ一つのクラスは小さく見通しの良い物にしようとしてるけど、結局は自分で使うものなのでテキトーな感じになってしまうのは仕方ないね。

抽象クラスの下にあるコードは実際にじゃらんのAPIをパースするクラス。例としてのせておきますね。

◆WebAPI抽象クラス

<?
  /*
  *  APIクラス処理クラス(親クラス)
  *    DATE : 2008/10/17
  */
  // MySQL接続クラス
  include_once( dirname( __FILE__ ) . '/MySQL.php' );
 
  abstract class WebApi
  {
    protected    $params;       // リクエストパラメータ(連想配列)
    protected    $url;          // パラメータが付与されたURL
    protected    $xml;          // 取得XML
    protected    $data;         // パースされたデータ
    protected    $max_count;    // データの最大件数
   
    public function __construct(){}
   
    /**
      リクエストパラメータ配列初期化処理
      このメソッドの中でparamsの連想キーを設定する。
    */
    abstract protected function init_params();
   
    /**
      APIのURL(パラメータ無し)を返す
    */
    abstract public function get_url();
   
    /**
      XMLをパースする(抽象メソッド)
    */
    abstract protected function parse_xml();
   
   
    /**
      リクエストパラメータが存在するか
    */
    public function is_param( $param_name )
    {
      if( isSet( $this->params[ $param_name ] ) ) {
        return true;
      } else {
        return false;
      }
    }
   
    /**
      リクエストパラメータ取得
    */
    public function get_param( $param_name )
    {
      if( $this->is_param( $param_name ) ) {
        return $this->params[ $param_name ];
      } else {
        return false;
      }
    }
   
    /**
      リクエストパラメータ設定
    */
    public function set_param( $param_name, $value )
    {
      if( $this->is_param( $param_name ) ) {
        $this->params[ $param_name ] = $value;
        return true;
      } else {
        return false;
      }
    }
   
    /**
      XMLデータ取得
      $uri : APIのURI。(終端に記号('?' or '&')を入れないこと。
      パース結果を返す。
    */
    public function get_xml( $uri )
    {
      // URL編集
      $temp = array();
      foreach( $this->params AS $key => $param ) {
        if( $param != "" ) {
          $temp[] = sprintf( '%s=%s', $key, $param );
        }
      }
     
      // $uriがすでにパラメータ指定がされているかどうか。
      if( substr_count( $uri, '?' ) > 0 ) {
        $this->url = sprintf( '%s&%s', $uri, implode( '&', $temp ) );
      } else {
        $this->url = sprintf( '%s?%s', $uri, implode( '&', $temp ) );
      }
     
      $strSql  = "SELECT * FROM web_api_result ";
      $strSql .= sprintf( "WHERE md5 = '%s' ", md5( $this->url ) );
      $con = new DataBaseConnect();
      $rec = new ResultSet( $con->executeQuery( $strSql ) );
     
      if( $rec->getRowCount() > 0 ) {
        $temp = unserialize( $rec->getField( "serial" ) );
        $this->max_count = $temp[ 'max_count' ];
        $this->data = $temp[ 'data' ];
      } else {
        $this->xml = $this->exec_method();
        $this->parse_xml();
        $this->store_xml();
      }
     
      return $this->data;
    }
   
    /**
      ページタグの取得
    */
    public function get_page_tag( $file_name, $current_page, $max_page, $param )
    {
      if( $current_page == 1 ) {
        if( $max_page > 1 ) {
          $page_tag = sprintf( '←|%s / %s|<a href="/%s?%s&p=%s">→</a>', $current_page, $max_page, $file_name, $param, ($current_page + 1) );
        } else {
          $page_tag = sprintf( '←|1 / 1|→' );
        }
      } else {
        if( $current_page >= $max_page ) {
          $page_tag = sprintf( '<a href="/%s?%s&p=%s">←</a>|%s / %s|→', $file_name, $param, ($current_page - 1), $current_page, $max_page );
        } else {
          $page_tag = sprintf( '<a href="/%s?%s&p=%s">←</a>|%s / %s|<a href="/%s?%s&p=%s">→</a>', $file_name, $param, ($current_page - 1), $current_page, $max_page, $file_name, $param, ($current_page + 1) );
        }
      }
      return $page_tag;
    }
   
    /**
      データベースにXMLを保存
    */
    protected function store_xml()
    {
      // md5用SQL
      $sql_md5  = "SELECT * FROM web_api_result ";
      $sql_md5 .= sprintf( "WHERE md5 = '%s' ", md5( $this->url ) );
     
      $strSql  = "INSERT INTO web_api_result (md5, md5_sql, regist, api_url, xml, serial) VALUES(";
      $strSql .= sprintf( "'%s', ", md5( $this->url ) );
      $strSql .= sprintf( "'%s', ", md5( $sql_md5 ) );
      $strSql .= sprintf( "'%s', ", date( 'Y-m-d' ) );
      $strSql .= sprintf( "'%s', ", $this->url );
      $strSql .= sprintf( "'%s', ", mysql_real_escape_string( $this->xml ) );
      $strSql .= sprintf( "'%s') ", mysql_real_escape_string( serialize( array( 'max_count' => $this->max_count, 'data' => $this->data ) ) ) );
      $con = new DataBaseConnect();
      $con->execute( $strSql );
    }
   
    // URLを確認してPOST or GETを選び実行する
    private function exec_method()
    {
      return $this->get();
    }
   
    // パラメータの桁数が256Byte以下の場合はGetメソッドで取得する
    private function get()
    {
      mb_regex_encoding( 'SJIS' );
      $temp = mb_convert_encoding( @file_get_contents( $this->url ), 'SJIS', 'UTF-8' );
      $temp = mb_ereg_replace( "[■□◆◇●○▲▼△▽☆★♪]+", '', $temp );
      return $temp;
    }
  }
?>
-------------------------------------------------------------------------------------

◆宿データAPI処理クラス

<?
  /*
  *  じゃらん宿データAPI処理クラス
  *    DATE : 2008/10/18
  */
  include_once( dirname( dirname( __FILE__ ) ) . '/config.php' );
  include_once( LIB_JARAN_HOTEL );
 
  class JaranHotelAdvance extends WebApi
  {
    const URI       = 'http://jws.jalan.net/APIAdvance/HotelSearch/V1/?key=[アクセスキー]';
    const PAGE_PAR_COUNT = 10;
   
    private    $response_fields;    // レスポンスフィールド定義。
   
    public function __construct()
    {
      $this->init_params();
    }
   
    public function get_url()
    {
      return self::URI;
    }
   
    public function get_page_par_count()
    {
      return self::PAGE_PAR_COUNT;
    }
   
    public function get_max_count()
    {
      return $this->max_count;
    }
   
    protected function init_params()
    {
      // リクエストパラメータ設定
      $this->params[ 'pref' ]      = '';    // 都道府県コード
      $this->params[ 'l_area' ]    = '';    // 大エリアコード(都道府県内を分けたコード)
      $this->params[ 's_area' ]    = '';    // 小エリアコード(大エリアをさらに分けたコード)
      $this->params[ 'h_id' ]      = '';    // 宿コード(これを指定すると他すべて無視)
      $this->params[ 'h_name' ]    = '';    // 宿名
      $this->params[ 'h_type' ]    = '';    // 宿タイプ(パラメータは仕様書参照)
      $this->params[ 'o_id' ]      = '';    // 温泉ID
      $this->params[ 'x' ]         = '';    // 経度
      $this->params[ 'y' ]         = '';    // 緯度
      $this->params[ 'range' ]     = '';    // 緯度経度から半径rangeKMの範囲を探す。
      $this->params[ 'o_pool' ]    = '';    // 屋外プール(0:なしdefault 1:あり)
      $this->params[ 'parking' ]   = '';    // 無料駐車場(0:なしdefault 1:あり)
      $this->params[ 'pub_bath' ]  = '';    // 内湯・大浴場(0:なしdefault 1:あり)
      $this->params[ 'onsen' ]     = '';    // 温泉(0:なしdefault 1:あり)
      $this->params[ 'prv_bath' ]  = '';    // 貸切風呂(0:なしdefault 1:あり)
      $this->params[ 'sauna' ]     = '';    // サウナ(0:なしdefault 1:あり)
      $this->params[ 'jacz' ]      = '';    // ジャグジー(0:なしdefault 1:あり)
      $this->params[ 'mssg' ]      = '';    // マッサージ(0:なしdefault 1:あり)
      $this->params[ 'r_ski' ]     = '';    // 貸しスキー(0:なしdefault 1:あり)
      $this->params[ 'r_brd' ]     = '';    // 貸しスノーボード(0:なしdefault 1:あり)
      $this->params[ 'pet' ]       = '';    // ペットOK(0:なしdefault 1:あり)
      $this->params[ 'esthe' ]     = '';    // エステ(0:なしdefault 1:あり)
      $this->params[ 'p_pong' ]    = '';    // 卓球(0:なしdefault 1:あり)
      $this->params[ 'limo' ]      = '';    // 送迎(0:なしdefault 1:あり)
      $this->params[ 'late_out' ]  = '';    // チェックアウト11時以降(0:なしdefault 1:あり)
      $this->params[ 'pict_size' ] = '1';    // 画像サイズ(詳細は仕様書)
      $this->params[ 'order' ]     = '';    // 並び順(0:宿コード順 1:50音順)
      $this->params[ 'start' ]     = '';    // 何件目から表示するか
      $this->params[ 'count' ]     = self::PAGE_PAR_COUNT;    // 1ページに何件表示するか
      $this->params[ 'xml_ptn' ]   = '1';
     
      // レスポンスフィールド設定
      $this->response_fields[] = 'hotelid';
      $this->response_fields[] = 'hotelname';
      $this->response_fields[] = 'postcode';
      $this->response_fields[] = 'hoteladdress';
      $this->response_fields[] = 'region';
      $this->response_fields[] = 'prefecture';
      $this->response_fields[] = 'largearea';
      $this->response_fields[] = 'smallarea';
      $this->response_fields[] = 'hoteltype';
      $this->response_fields[] = 'hoteldetailurl';
      $this->response_fields[] = 'hotelcatchcopy';
      $this->response_fields[] = 'hotelcaption';
      $this->response_fields[] = 'pictureurl';
      $this->response_fields[] = 'picturecaption';
      $this->response_fields[] = 'accessinfomation';
      $this->response_fields[] = 'checkintime';
      $this->response_fields[] = 'checkouttime';
      $this->response_fields[] = 'x';
      $this->response_fields[] = 'y';
      $this->response_fields[] = 'sampleratefrom';
      $this->response_fields[] = 'hotelnamekana';
      $this->response_fields[] = 'onsenname';
      $this->response_fields[] = 'numberofratings';
    }
   
    protected function parse_xml()
    {
      $this->xml = preg_replace( "/\s+/", " ", $this->xml );
      $this->data = array();
     
      $ret = preg_match( "@<numberofresults>([0-9]+)</numberofresults>@i", $this->xml, $max_count );
      $this->max_count = (int)$max_count[ 1 ];
     
      $ret = preg_match_all( '@<hotel>(.*?)</hotel>@i', $this->xml, $hotels );
      foreach( $hotels[ 1 ] AS $hotel ) {
        $temp = array();
       
        // レスポンスフィールド設定による読み出し。
        foreach( $this->response_fields AS $field ) {
          $pattern = sprintf( '@<%s>(.*?)</%s>@i', $field, $field );
          $ret = preg_match( $pattern, $hotel, $result );
          $temp[ $field ] = $result[ 1 ];
        }
       
        // フィールド設定では取れない取得物
        // フィールド設定では取れない取得物
        $ret = preg_match_all( '@<accessinformation name="(.*?)">(.*?)</accessinformation>@i', $hotel, $accesses );
        $temp2 = array();
        for( $i = 0 ; $i < count( $accesses[ 1 ] ) ; $i += 1 ) {
          $temp2[ $i ] = array( $accesses[ 1 ][ $i ] => $accesses[ 2 ][ $i ] );
        }
        $temp[ 'accesses' ] = $temp2;
       
        $ret = preg_match( '@<creditcard[^>]+>(.*?)</creditcard>@i', $hotel, $credit );
        $temp[ 'creditcard' ] = explode( ',', $credit[ 1 ] );
       
        $ret = preg_match( '@<lastupdate day="([0-9]+)" month="([0-9]+)" year="([0-9]+)"/>@i', $hotel, $updates );
        $temp[ 'lastupdate' ] = sprintf( '%s-%s-%s', $updates[ 3 ], $updates[ 2 ], $updates[ 1 ] );
       
        $this->data[] = $temp;
        unset( $temp );
      }
    }
   
  }
?>

ZenBack

WebMoney ぷちカンパ