3月 2010のアーカイブ
Kohana で作る twitter ツール「つどったー」作る編
前回でサイトの準備が整いました!
今回は具体的にプログラムを作っていきます。追加したのは controller 2ファイル。model 1ファイル。view 3ファイルです。
では、/controllers/welcome.php から!
1. welcome.php
<?
class welcome_Controller extends Controller {
public $IN_PRODUCTION = False;
public function __construct()
{
parent::__construct();
$this->twitter = new Twitter;
$this->twitter->check_login();
$this->page = new View('template');
}
public function index()
{
if($this->twitter->check_login())
{
$url = "http://api.twitter.com/1/{$this->twitter->user->username}/lists.json";
$list = json_decode($this->twitter->oAuthRequest($url));
$this->tsudotter = new Tsudotter_Model;
$regist_list = $this->tsudotter->get($this->twitter->user->username);
if(!is_null($regist_list))
{
foreach($regist_list as $row)
$new_regist_list[] = "/{$this->twitter->user->username}/$row";
}
else
{
$new_regist_list = null;
}
$message = $this->twitter->sess->get('user_message');
$this->page->content = new View('logged_in',array('twitter'=>$this->twitter,'limits'=>$limits,'lists'=>$list,'regist_list'=>$new_regist_list,'message'=>$message));
}
else
{
$this->twitter->getRequestTokens();
$url = $this->twitter->getAuthorizeUrl();
$this->page->content = new View('not_logged_in',array('url'=>$url));
}
$this->page->render(True);
}
public function completed()
{
if($this->twitter->check_login() == False)
{
$this->twitter->sessionRequestTokens();
$this->twitter->tradeRequestForAccess();
if($this->twitter->storeTokens())
{
url::redirect('');
}
else
{
echo "help - a wierd error occured somewhere. Check your installation again";
}
}
else
{
url::redirect('');
}
}
public function logout()
{
if($this->twitter->check_login() != False)
{
$this->twitter->revokeSession(True);
}
url::redirect('');
}
}
welcome.php はデフォルトコントローラーになっており、http://tsudotter.com/ にアクセスすると welcome.php の index が対応します。 wellcome.php には、この他にログアウト( logout ) および、twitter で指定した callback URL( completed ) の3つが存在しています。
index では、$this->twitter->check_login() によりログイン状態をチェックされログインされていない場合は、twitter ログイン用URLを取得し view の not_logged_in.php を表示します。一方、ログインされていた場合は Twitter API によりログインユーザーのリスト一覧を取得。さらに、Tsudotter_Model を用いて登録済みのリストを取得しています(ビューにて、登録済みのリストには×を表示したいからです!)
では、ビューはどのようになっているのでしょうか!
2. /views/not_logged_in.php /views/logged_in.php /views/template.php
not_logged_in.php
<p style="padding: 3px;">
「つどったー」は Twitter で作成したリストへの登録をオープンにする為のサイトです。まずは、以下のリンクからログインし「リストに集う」許可をください!!<br />
</p>
<p style="padding: 3px; text-align: center;">
<?=html::anchor($url, html::image('Sign-in-with-Twitter-darker.png'));?>
</p>
このファイルで必要なのは html::anchor() だけですね。welcome.php コントローラーファイルの 41行目で取得した $url をここでは出力しています。
logged_in.php
<p style="padding: 3px;">
<?=$twitter->user->username;?> さん、お手伝いできることはありますか?
</p>
<? if($message !== false): ?>
<p style="padding: 3px; font-weight: bold; color: #cc0000;">
<?=$message; ?>
</p>
<? endif; ?>
<p style="padding: 3px; text-align: right;">
<?=html::anchor('logout','[ ログアウト ]');?>
</p>
<? if (count($lists->lists) > 0): ?>
<p style="padding: 3px;">
<?=$twitter->user->username;?> さんの管理されているリストが<?=count($lists->lists);?>件見つかりました。<br />
登録をオープンにするリストを選択ください。
</p>
<?
print form::open('list/open');
?>
<table style="margin: 5px auto 5px auto; width: 490px; border: 1px #E3E3E3 solid; border-collapse: collapse; border-spacing: 0;">
<tr>
<th style="padding: 5px; border: #E3E3E3 solid; border-width: 0 0 1px 1px; background: #F5F5F5; font-weight: bold; line-height: 120%; text-align: center;"> </th>
<th style="padding: 5px; border: #E3E3E3 solid; border-width: 0 0 1px 1px; background: #F5F5F5; font-weight: bold; line-height: 120%; text-align: center;">リスト名</th>
<th style="padding: 5px; border: #E3E3E3 solid; border-width: 0 0 1px 1px; background: #F5F5F5; font-weight: bold; line-height: 120%; text-align: center;">リンク</th>
</tr>
<? foreach($lists->lists as $value): ?>
<tr>
<td style="padding: 5px; border: 1px #E3E3E3 solid; border-width: 0 0 1px 1px; background: #FFFFFF; text-align: center;">
<? if(is_array($regist_list) && in_array($value->uri, $regist_list)): ?>
<span style="color: #cc0000;">×</span>
<? else: ?>
<? print form::radio('chk_list', $value->uri); ?>
<? endif; ?>
</td>
<td style="padding: 5px; border: 1px #E3E3E3 solid; border-width: 0 0 1px 1px; background: #FFFFFF;"><?=$value->name;?></td>
<td style="padding: 5px; border: 1px #E3E3E3 solid; border-width: 0 0 1px 1px; background: #FFFFFF;"><a href="http://twitter.com<?=$value->uri;?>"><?=$value->full_name;?></a>)</td>
</tr>
<? endforeach; ?>
</table>
<?
print form::submit('submit', '登録');
?>
<?
ああ…。 css は外部ファイルにまとめるべきでした…。
ページ上部側から、ログアウト、リスト、入力画面と並んでいます。
実際に出力されると以下のようになります。
さて、もうひとつの template.php はどんな役割を果たしているのでしょうか。
実はコンテンツ部分を除いたヘッダーやフッターなど、統一部分が記述されています。
つどったーでは、ヘッダーとフッターのほかに右部のコンテンツについても template.php に含めています。
自身のリストを公開するフォームと、他のユーザーのリストに登録するフォームはどちらも /controllers/list.php で処理を行います。
3. list.php
<?
class List_Controller extends Controller {
public function __construct()
{
parent::__construct();
$this->twitter = new Twitter;
$this->twitter->check_login();
$this->tsudotter = new Tsudotter_Model;
$this->twitter_user = new Twitter_user_Model;
}
public function open()
{
if($this->twitter->check_login() != False)
{
list($dummy, $nickname, $list_name) = explode("/", $this->input->post('chk_list'));
if($this->twitter->user->username == $nickname)
{
$inArray = array(
'nickname' => $nickname,
'list_name'=> $list_name
);
$this->tsudotter->insert_list($inArray);
}
}
url::redirect('');
}
public function add()
{
if($this->twitter->check_login() != False)
{
$screen_name = $this->input->post('screen_name');
$list_name = $this->input->post('list_name');
$user_list = $this->tsudotter->get($screen_name);
if(in_array($list_name, $user_list))
{
$user = $this->twitter_user->get_key($screen_name);
if(is_object($user))
{
$this->list_owner = new Twitter;
$this->list_owner->user = new Twitter_user_Model;
$this->list_owner->user->set_keys($user->access_key, $user->secret_key);
$url = "http://api.twitter.com/1/{$screen_name}/{$list_name}/members.json";
$args = array(
"id" => $this->twitter->user->username
);
$this->list_owner->oAuthRequest($url, $args, "POST");
$this->twitter->sess->set_flash('user_message', '登録を行いました!');
}
else
{
$this->twitter->sess->set_flash('user_message', '希望されたリストは登録許可がありません。残念!');
}
}
else
{
$this->twitter->sess->set_flash('user_message', '希望されたリストは登録許可がありません。残念!');
}
}
url::redirect('');
}
}
リストの公開は open。リストへの登録は add で。KTwitter ではログインをするとユーザーの access key および secret key がデータベースに保存されますので、それらの情報を用いて登録希望のユーザー名(screen name)を、Twitter リストAPI により登録します。
最後にモデルですが、KTwitter に含まれる twitter_user.php はそのまま利用し tsudotter_model として1つだけ追加しています。
4.tsudotter.php
<?php
class Tsudotter_model extends Model {
public function __construct()
{
parent::__construct();
}
public function insert_list($data)
{
$this->db->insert('tsudotter', $data);
}
public function get($nickname)
{
$this->db->where('nickname', $nickname);
$r = $this->db->get('tsudotter');
if($r->count() > 0)
{
foreach($r as $row)
$all_array[] = $row->list_name;
return $all_array;
}
else
{
return null;
}
}
}
公開するリスト情報を登録する insert_list() と、登録されているリスト情報を取得する get() の2つだけのファイルです。
Kohana で作る twitter ツール「つどったー」準備編
先日の予告通り、Kohana で作った twitter ツール「つどったー」の中身をご紹介しちゃいます。
まずは材料。
1. KohanaPHP (http://www.kohanaphp.com/)
2. KTwitter (http://www.errant.me.uk/ktwitter)
それぞれをダウンロードし展開します。
展開したKTwitter のディレクトリを Kohana のディレクトリと統合しました。
ここでは、展開したディレクトリ名を kt に変換し application に存在していて kt に存在していない cahe や helpers、hooks、logs を作りました。
そして、application から kt にディレクトリ指定を変更する必要がありますので tsudotter 直下にある index.php の以下のラインを編集します。
/** * Website application directory. This directory should contain your application * configuration, controllers, models, views, and other resources. * * This path can be absolute or relative to this file. */ $kohana_application = 'kt';
$kohana_application を kt に変更します。
データベースを用意します。
次に、KTwitter で指示されている通りのテーブルを作成します。
CREATE TABLE `twitter_users` ( `user` VARCHAR( 50 ) NOT NULL , `access_key` TEXT NOT NULL , `secret_key` TEXT NOT NULL , PRIMARY KEY ( `user` ) );
さらに、つどったーでは自由に登録できるリストをユーザーに登録してもらいますので、リスト情報を保存するテーブルもあわせて作成します。
CREATE TABLE `tsudotter` ( `id` int(11) NOT NULL AUTO_INCREMENT, `nickname` varchar(100) NOT NULL, `list_name` varchar(200) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `nickname` (`nickname`,`list_name`) );
/kt/config/ に database.php を作成し、データベースと接続するための設定を保存します。
<?php $config['default'] = array ( 'benchmark' => TRUE, 'persistent' => FALSE, 'connection' => array ( 'type' => 'mysql', 'user' => 'ユーザー名', 'pass' => 'パスワード', 'host' => 'localhost', 'port' => FALSE, 'socket' => FALSE, 'database' => 'データベース名' ), 'character_set' => 'utf8', 'table_prefix' => '', 'object' => TRUE, 'cache' => FALSE, 'escape' => TRUE );
Twitter に application の登録をしましょう!
twitter にログインし「Applications Using Twitter」にアクセスします。「Register a new application」をクリックしアイコンやアプリケーション名などを登録します。
つどったー では以下の通り登録を行いました!
-
Application Name: list tsudotter
-
Application Website: http://tsudotter.com/
-
Application Type: Browser
-
Callback URL: http://tsudotter.com/welcome/completed
-
Default Access type: Read & Write
-
Use Twitter for login: チェックを入れる!
登録が完了すると、Consumer key および Consumer secret が得られます。これらの情報を /kt/config/twitter.php に設定します。
// To get consumer key/secret you need to visit http://www.twitter.com/oauth_clients and create an app // Consumer key from twitter $config['consumer_key'] = ''; // Consumer Secret from twitter $config['consumer_secret'] = '';
これで準備が完了です!
少し長くなりましたので、続きは後ほど!
Kohana で作る twitter ツール「つどったー」
以前に「twitter で tsudoる – つどったー 作ったよ!」という事で土曜日の昼になんとなく作った twitter ツールでしたが、その後、やれ LIST機能が本家に付くわ、OAuth なんてものが出現してくるわで、長い間放置していた「つどったー」に手を入れることにしました!
そして、今回は「Kohana」をフレームワークに選び、Kohana に対応した Twitter ライブラリ「Kohana Twitter Library (with Oauth support)」を使ってみました!
この「つどったー」は、あなたが管理しているリストをサイトを通じて自由に登録してもらうことができるようにする事ができます。
ログインすると、twitter の認証後画面が切り替わり、あなたが管理しているリストが表示されます。リストを選択し「登録」ボタンをクリックすると「つどったー」にリスト情報が登録され、他のユーザーからの登録が可能になります。
「Kohana Twitter Library (with Oauth support)」のサンプルをちょこちょこっと書き換えただけで、作られておりますので、そのうちソースコードを恥を忍んで晒します!
サイトはこちら!
→ つどったー
Codeigniter で超簡易的なモバイルページ出力をする
モバイルページ作ってますかー!
私は「いや、これモバイルっていうか…」というほどのページしか作ってこなかったので「簡易」となっております。どこがどう簡易なのか、というと「絵文字対応してない」「セッションとか使わない」という超がつくほど簡易的なものです。
やっている事は
- ビューの読み込みを切り替える
- 文字コードを変換する
- 全角文字を半角文字に変換する
といった程度のものです。
私は、これらを実現するために フック(フック – フレームワークコアの拡張) を使っています。
簡易的なものなので、ちゃっちゃと行きましょう。
まずは application/config/hook.php に設定。
$hook['post_controller_constructor'][] = array(
'class' => 'Mobile',
'function' => 'view_set',
'filename' => 'Mobile.php',
'filepath' => 'hooks'
);
$hook['display_override'][] = array(
'class' => 'Mobile',
'function' => 'display',
'filename' => 'Mobile.php',
'filepath' => 'hooks'
);
hook に追加しているのは、2点。 post_controller_constructor というポイントでは、 view の読込先ディレクトリを書き換え、 display_override では文字コードの変換などを行っています。
呼びだされる、 Mobile.php は /application/hooks/ に保存します。
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Mobile {
function Mobile()
{
$this->ci =& get_instance();
$this->ci->load->library('user_agent');
}
function view_set()
{
if ($this->ci->agent->is_mobile())
{
$this->ci->load->_ci_view_path .= 'mobile/';
}
}
function display()
{
if ($this->ci->agent->is_mobile())
{
$buffer = $this->ci->output->get_output();
$buffer = preg_replace("/\n/", '', $buffer);
$buffer = mb_convert_kana($buffer, 'aks', "UTF-8");
$buffer = mb_convert_encoding($buffer, 'SJIS', $this->ci->config->item('charset'));
header("Content-type: text/html; charset=Shift_JIS;");
echo $buffer;
}
else
{
echo $this->ci->output->get_output();
}
}
}
ユーザエージェントクラスを呼び、パソコンからのアクセスか、モバイルからのアクセスかの判断を行っています。モバイルからのアクセスと判断されると、既存の view ディレクトリに mobile という指定を付け加えます。コントローラーで以下のように「home」を指定した場合、
$this->load->view("home");
- パソコンの場合:
- /application/views/home.php
- モバイルの場合:
- /application/views/mobile/home.php
それぞれ読み込まれるようになります。
さらに、出力には以下の通り変換を行っています。
$buffer = preg_replace("/\n/", '', $buffer);
$buffer = mb_convert_kana($buffer, 'aks', "UTF-8");
$buffer = mb_convert_encoding($buffer, 'SJIS', $this->ci->config->item('charset'));
改行をなくし、全角の英数字・カタカナを半角に変換、文字コードを Shift-JIS に変換し出力しています。
徐々に機能的にも増強していきたいなあ、と思っております m(_._)m
Google Maps API(v3) で住所から地図にマーカーを置く!
今後また使うかもしれないので、メモメモ。
google Maps API(v3)では APIキーが不要なので、テスト環境でのテストや本番に移行した際にAPIキーを取り直したりといったようなわずらわしさが無いのでお気に入りです(ただのものぐさです…)
サンプルを設置しました! → SAMPLE
早速、まずは javascript の読み込みを設定します!
<script type='text/javascript' src='http://www.google.com/jsapi'></script>
<script type='text/javascript'>google.load('jquery', '1.3.2');</script>
<script type='text/javascript' src='http://maps.google.com/maps/api/js?sensor=false&language=ja' charset='UTF-8'></script>
次に、住所を入力するinputフィールドと地図を表示するための HTML を用意しました。
<label class='label'>住所</label> <input type='text' name='address' id='address' value='' /> <label class='label'>地図表示位置</label> 緯度: <input type='text' name='lat' id='lat' value='35.6585873' /> 経度: <input type='text' name='lng' id='lng' value='139.7454247' /> <button id='getad'>住所から取得</button> <div id='map_canvas'></div>
住所を adress のボックスに入力し「住所から取得」をクリックすると、マップの中心とマーカーが住所で入力された位置に移動し、緯度および軽度のボックスに入力されるものです。
$(document).ready(function() {
var mapdiv = document.getElementById('map_canvas');
var geocoder = new google.maps.Geocoder();
var org_lat = $('#lat').val();
var org_lng = $('#lng').val();
var point = new google.maps.LatLng(org_lat, org_lng);
var myOptions = {
zoom: 16,
center: point,
mapTypeId: google.maps.MapTypeId.ROADMAP,
scaleControl: true
};
var map = new google.maps.Map(mapdiv, myOptions);
var marker = new google.maps.Marker({
position: point,
map: map,
draggable: true
});
google.maps.event.addListener(marker, 'dragend', function() {
var p = marker.position;
$('#lat').val(p.lat());
$('#lng').val(p.lng());
});
$('#getad').click(function() {
var sad = $('#address').val();
var geocoder = new google.maps.Geocoder();
geocoder.geocode({ 'address': sad}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
map.setCenter(results[0].geometry.location);
marker.setPosition(results[0].geometry.location);
var p = marker.position;
$('#lat').val(p.lat());
$('#lng').val(p.lng());
} else {
alert('住所から場所を特定できませんでした。最初にビル名などを省略し、番地までの検索などでお試しください。');
}
});
return false;
});
});
javascript の 2行目から26行目までは、ページを開いた際に表示する地図の設定です。
4行目と5行目で、HTMLにあらかじめ記述されている緯度経度(この例では東京タワーです)を読み込み、10行目で地図の中央に設定。さらに、マーカーを作成し17行目で位置に設定させています。
19行目では、地図上でマーカーをドラッグ&ドロップできるように設定し、22行目から26行目でドラッグ&ドロップが行われた場合にドロップ先の緯度経度を HTMLの緯度、軽度のinputボックスに上書きしています。
これは、住所から検索される位置が思った通りの位置になってくれない場合があり(ほら、ビルの名前をマーカーで隠して欲しくない、とか)微調整を行うことが出来るような措置です。
そして28行目から49行目にて「住所から取得」ボタンをクリックした際の処理が書かれています。
AjaxZip 2.0 を使って、郵便番号から住所を取得し、住所から地図。さらに、地図の位置から 駅データさんの「座標から最寄駅 API」を使うとアクセス情報の必要なデータは全てそろってしまうのではないでしょうか。




