CodeIgniterの学習 55 - ヤフーの画像検索apiと形態素解析apiを組み合わせてお遊びアプリを作る-その1(現在のコード完成度15%)

前回wikiの移植が面倒くさくなって放り出したので、代わりに
CodeIgniterでヤフーの画像検索api形態素解析apiを組み合わせてお遊びアプリを作ることにした。

暇を見て一日少しずつ書いていくことにする。


今日からのエントリーは、作ったコードを少しずつ貼っていく形態にする。
週2回、全7回くらいを予定。

(昔1枚スクリプトで作って放置していたものをCodeIgniterに起こし直している。)


あまり説明はしない、コメントを見てね。
まだ枠組みしか作っていない。
だんだん成長していくところを見守ってください。



動作環境

他のヘルパー、ライブラリーには極力依存しないようにする。(どうしても必要になるときは別記する)

動作環境

  • CodeIgniterのVersion1.7以降限定
  • mb_系が有効で
  • mysqlが動く
  • linux環境
  • fopenで外部URLのデータを取得できるかcurlが使える。すなわちスクレイピング出来る環境(レンサバだと出来ないかもね)
  • $config['rewrite_short_tags'] = TRUE;であること(<?=$hoge ?>が使える。)


ちなみにrewrite_short_tagsが有効だと、
php.iniのshort_open_tagが無効でも擬似的にshort_open_tagが有効になる。文末の;はいらない。

(system/libraries/Loader.phpの671行目付近で内部的に変換している)


目的

  • 遊び。俺が欲しいから。
  • CodeIgniterの学習を兼ねる。
  • 俺俺ライブラリの拡張。別の事でも使えるように。
  • お気に入りのサイト限定の画像検索の自作。
  • 俺俺エロ画像検索をCodeIgniterで作る。いや別にエロじゃなくてもいいけど、モチベーション的にね。


ライセンス

この程度のしょぼい練習用のサンプルアプリなので気にしないが、
BSDライセンスにするつもり。


作る機能

  1. キーワードを入れて検索すると、api経由で取得した画像を表示する。
  2. 検索した画像の説明を形態素解析apiに噛まして、関連キーワードを抽出する。
  3. 関連キーワードのリンクを検索ボックスの下段部分に表示する。
  4. 検索履歴を表示する。検索履歴はユーザー毎ではなく、全員と共有。
  5. 関連キーワードのリンクを押すと、そのキーワードで再検索する。
  6. 1-5の繰り返し。
  7. 画像サムネイルをクリックすると、参照元を別ウィンドウ(別タブ)に開く。
  8. 画像上のサムネイルにマウスオーバーすると、説明をtips表示する。
  9. 検索キーワード・結果の保存(キャッシュ)と表示機能(mysql使用)
  10. 一定期間はキャッシュデータを返す。(API側の問い合わせ回数上限があるため)
  11. apiへの同時問い合わせはapi側の規約により不可なので、同時の問い合わせを避けるため適切にウエイトを入れる。
  12. configファイルに可変の設定値部分を切り出しておく。
  13. (飽きなければ)インストーラーも作る。(テーブル作成、設定値書き換え)
  14. 形態素解析の抽出対象外のキーワードを設定可能にする。
  15. 画像一覧の表示対象外のURL/ドメインを設定可能にする。
  16. 検索不可の文言を設定可能にする。
  17. 検索履歴と接続ログを保存する。
  18. 検索回数のカウンターを設置する。
  19. 検索件数表示のナビゲーションを設置する。
  20. 気に入った画像を投票(poll)出来るようにする。
  21. pollの上位一覧画面を作る。
  22. 気に入った画像をまとめて、zipでクレが出来るようにする。
  23. 俺自身は興味はないが、関連商品の自動検索・アフィリエイトを出来るようにする。
  24. ロボットが勝手にカウンターを回さないように、ロボット避けをする。


全部入れたいが、全部入れるかは未定。とりあえず現在希望するもの。


画面

今こんなかんじ。道のりは長い。
値を入れてpostしてバリデーションが走って、さあapiに接続しましょうかね
というところまで。


コード

まだ動かないよ。枠だけ。
このあとDBに接続したり、apiに問い合わせたりしないといけない。

エントリーを更新する度に全部貼っていく。


1:コントローラ… application/controllers/yaimg.php

Version1.7から追加された、form_validationライブラリをバリデーションで使うことにする。

<?php if ( !defined( 'BASEPATH' ) ) exit( 'No direct script access allowed' );
/**
 * Yahooの画像検索APIを使ってみるテスト
 */
/*
* @author: dix3
* @link:http://d.hatena.ne.jp/dix3/
*/
class Yaimg extends Controller {
    // コンストラクタ
    function Yaimg()
    {
        parent :: Controller();//親のコンストラクタを呼ぶ
        //$this -> load -> helper( array('form', 'html', 'text', 'string') );//ヘルパのロード
        $this -> load -> helper( array( 'url','form', 'html', 'text', 'string','date' ) ); //ヘルパのロード
        //ライブラリのロード
        $this -> load -> library( 'form_validation');
        $this -> load -> library( 'lib_yaimg' );
        $this -> load -> model( 'Mod_yaimg' );//モデルのロード
    } 
    // デフォルトインデックス
    function index()
    {
        $data = array();
        $data = $this->Mod_yaimg->set_init_data();//画面に固定値のデータをセット
        
        //バリデーションのルール設定
        $this -> form_validation -> set_rules( 'keyword',$this->Mod_yaimg->get('input_keyword_value'), 'trim|required|min_length[2]|max_length[64]|xss_clean' );

        //バリデーション処理の実行
        if(TRUE === $this -> form_validation -> run()){
            //apiに接続して結果を取得する
            $this->Mod_yaimg->query_api(array('keyword'=>$this->input->post('keyword',true)));
            
            $data['result_area']='';
        }else{
            $data['result_area']='';
        }

        $this -> load -> view( 'yaimg_index', $data );//ビューにデータを渡す
    }

}

/**
 * End of file yaimg.php
 */
/**
 * Location: ./application/controllers/yaimg.php
 */

 ?>



2:ビュー… application/views/yaimg_index.php

タグを直接書くのではなく、フォームヘルパを使ってみた。

set_value('keyword',$default_keyword)で、第二引数にデフォルト値を設定できる(たしかVersion1.7から)。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja">
<head>
<title><?= $svs_title ?></title>
    <?= meta('Content-Type','text/html; charset=utf-8','http-equiv') ?>
    <?= meta('Content-language',$header_lang,'http-equiv') ?>
    <?= meta('Pragma','no-cache','http-equiv') ?>
    <?= meta('Cache-Control','no-cache','http-equiv') ?>
    <?= meta('Expires','Thu, 01 Dec 1994 23:59:59 GMT','http-equiv') ?>
    <?= meta('Distribution','Global') ?>
    <?= meta('Author','dix3') ?>
    <?= meta('Robots','index,nofollow') ?>
    <?= $header_js ?>
    <?= $header_css ?>
</head>
<body>
    <div>
        <?= heading($svs_description,3) ?>
        <?= form_open('yaimg') ?>
            <?= form_input(array('name'=>'keyword','style'=>'width:250px;','onclick'=>"javascript:this.value='';"),set_value('keyword',$default_keyword)) ?>
            <?= form_submit('submit',$submit_button_value) ?>
            <?= validation_errors('<div class="error">','</div>'); ?>
        <?= form_close() ?>
    </div>
    <hr>
    <div class='result_area'>
        <?= $result_area ?>
    </div>
</body>
</html>



3:モデル… application/models/mod_yaimg.php

てきとう。この後ここにいろいろ追加する。

<?php if ( !defined( 'BASEPATH' ) ) exit( 'No direct script access allowed' );
/*
* @author: dix3
* @link:http://d.hatena.ne.jp/dix3/
*/

class Mod_yaimg extends Model {
    var $mod_config;
    // コンストラクタ
    function Mod_yaimg()
    {
        parent :: Model();
        $this->load->helper('html');
        $this->load->helper('yaimg');

        $this->_init();//初期化
    }
    //初期化
    function _init(){
        $this->load->config('yaimg_config',true);
        $this->mod_config = $this->config->item('yaimg_config');
    }

    //画面に固定値のデータをセット
    function set_init_data(){
        $arr = array( 'svs_title' ,
            'svs_description' ,
            'header_lang' ,
            'header_js' ,
            'header_css' ,
            'input_keyword_value',
            'default_keyword' ,
            'submit_button_value' ,
            );
        $data = array();
        foreach( $arr as $v ) {
            $data[$v] = $this -> get( $v );
        }
        return $data;
    }
    //設定値取得
    function get($v){
        if('header_js' === $v){
            //yaimgヘルパのheader_jsタグ
            return header_js($this->get_mod_config($v));
        }elseif('header_css' === $v){
            //htmlヘルパのlink_tag
            return link_tag($this->get_mod_config($v));
        }else{
            return $this->get_mod_config($v);
        }
    }
    //configファイルから設定値を読みとる
    function get_mod_config($v)
    {
        $v = strtoupper($v);
        return isset($this->mod_config[$v]) ? $this->mod_config[$v] : '';
    }

    //apiに接続して結果を取得する
    function query_api($params=array())
    {
        $keyword = isset($params['keyword']) ? $this->input->xss_clean(strip_tags($params['keyword'])) : '';
        $sentence = urlencode(mb_substr(  $keyword  , 0, 1016 ));
        $appid = $this->get('appid');
        $url = $this->get('api_url');
        $url = str_replace('%appid%',$appid,$url);
        $url = str_replace('%sentence%',$sentence,$url);
        //var_dump($url);
        usleep( 5000 );
    }

} //endofclass
/**
 * End of file mod_yaimg.php
 */
/**
 * Location: ./application/models/mod_yaimg.php
 */

 ?>



4:ライブラリ… application/libraries/lib_yaimg.php

まだ何もない。

<?php if ( !defined( 'BASEPATH' ) ) exit( 'No direct script access allowed' );
/*
* @author: dix3
* @link:http://d.hatena.ne.jp/dix3/
*/
class Lib_yaimg {
    function Lib_yaimg()
    {
    }
} //endofclass
/**
 * End of file lib_yaimg.php
 */
/**
 * Location: ./application/libraries/lib_yaimg.php
 */
 ?>



5:ヘルパー… application/helpers/yaimg_helper.php

ヘッダのjavascriptを読みこむ用

<?php if ( !defined( 'BASEPATH' ) ) exit( 'No direct script access allowed' );
/*
* @author: dix3
* @link:http://d.hatena.ne.jp/dix3/
*/
if ( ! function_exists( 'header_js' ) ) {
    // scriptの読み込みタグ生成
    // 例: header_js('/js/hogehoge.js');で
    // <script src="/js/hogehoge.js" type="text/javascript"></script>
    // を作る
    function header_js( $src_str = '', $charset = '' )
    {
        $ret = '';
        if ( $src_str ) {
            if ( $charset ) {
                $cstr = ' charset="' . $charset . '" ' ;
            }else {
                $cstr = '' ;
            }
            $ret .= '<script language="javascript" type="text/javascript" src="' . $src_str . '"' . $cstr . "></script>\n";
        }
        return $ret;
    }
}

/* End of file yaimg_helper.php */
/* Location: ./application/helpers/yaimg_helper.php */

 ?>



6:設定ファイル… application/config/yaimg.php

可変の設定値部分を外部に切り出した。

<?php if ( ! defined( 'BASEPATH' ) ) exit( 'No direct script access allowed' );
/*
* @author: dix3
* @link:http://d.hatena.ne.jp/dix3/
*/

$config['SVS_TITLE'] =  "ヤフー画像検索 WEBAPIテスト";//タイトル
$config['SVS_NAME'] = "yaimg_search";//サービス名
$config['SVS_DESCRIPTION'] =  "ヤフー画像検索と形態素解析の実験";//ページタイトル
$config['HEADER_LANG'] =  "ja";//Content-language
$config['HEADER_JS'] =  "/js/yaimg.js";//javascriptの相対パス
$config['HEADER_CSS'] =  "/css/yaimg.css";//javascriptの相対パス
$config['INPUT_KEYWORD_VALUE'] =  "キーワード";//キーワード欄の名称
$config['SUBMIT_BUTTON_VALUE'] =  "ぽちっとな!画像検索";//サブミットボタン名
$config['DEFAULT_KEYWORD'] =  "なんかいれて";//キーワード欄のデフォルト値

$config['APPID'] = ""; //yahooのappid(自分でとる)
#$config['API_URL'] = "http://api.jlp.yahoo.co.jp/MAService/V1/parse?appid=%appid%&results=uniq&uniq_filter=9&sentence=%sentence%"; //yahooのapiのURL
$config['API_URL'] = "http://jlp.yahooapis.jp/MAService/V1/parse?appid=%appid%&results=uniq&uniq_filter=9&sentence=%sentence%"; //yahooのapiのURL


$config['UACCT_NO'] = "";//google-analyticsのurchinのタグ

$config['SITE_LOCK'] = "";//画像検索を特定のサイト内に限定するときに指定
//$config['SITE_LOCK'] = "hatena.ne.jp";//画像検索を特定のサイト内に限定するときに指定


/* End of file yaimg.php */
/* Location: ./application/config/yaimg.php */

 ?>

apiを使うためのAPPIDは、yahooで取得できる。(今は解説しない。自力で調べてね)
UACCT_NOは、あとでgoogle-analyticsを仕込むための予備。



7:javascriptファイル… ドキュメントルート/js/yaimg.js

まだ何もない。あとで追加していく。
このエントリーの本筋から外れるので、ajax等複雑なjavascriptを使う予定はない。

//@author: dix3
//@url: http://d.hatena.ne.jp/dix3

var hoge=function(){
  try{
    window.alert('hoge');
  }catch(e){
    window.alert(e);
  }
}



8:cssファイル… ドキュメントルート/css/yaimg.css

あとで追加していく。

body{ 
 color:#fff;
 background:#111;
}
hr { 
 color:#eeeeee;
 height:1px; 
}
h1,h2,h3{
 font-size:1em;
}
.error{
 background:#ff0000;
 color:#fff;
 padding:3px;
 font-weight:bold;
 display:inline;
}
.result_area{
  margin:20px 0 0 0;
  padding:5px;
}

img{
 border:2px solid #111;
}
img:hover{
 border:2px solid #ffd700;
}



ちょっとやる気でてきた。ネットの膨大なエロ画像が俺を呼んでるぜぃ。

目標は週2回更新。つづく。





(08/12/27一部ヘルパとライブラリのロード部分ソース記述訂正)
誤)

$this->load->helper('hoge','fuga','moga');


正)

$this->load->helper(array('hoge','fuga','moga'));


誤)

$this->load->library('aaa','bbb');


正)

$this->load->library('aaa');
$this->load->library('bbb');

に訂正

(訂正終わり)


09/02/22 一部修正

  • ヘルパのロードに 'url','date'を追加(autoloadで読みこんでいたため)
  • cssに img , img : hover 追加