カテゴリー: PHP

  • Composer WordPress Development Kit 3.0.2 をリリースしました。

    Composer WordPress Development Kit という、Composer と PHP のビルトインサーバーを使って、WordPress 環境をサクッと立ち上げるものを以前作ったんですが、バージョンアップしました!

    Composer で WordPress 環境をさくっと立ち上げるやつを作りました。

    使ってみていろいろ気になったところなどが出てきたのでかなり大幅に変更しました。

    変更点などなど

    ドキュメントルートをディレクトリ直下に変更しました。なので、サーバー上 で WordPress を立ち上げるときも同じコードをそのまま使えるようになりました。Git の Webhook を使って、レポジトリが変更されるたびに、自動デプロイ出来るようになったりしてます。デプロイ自動化などは、第2回 Gitリポジトリからテスト環境への自動デプロイ – CPIエバンジェリストコラム 等を参考にすれば良いんじゃ無いかなと。

    WordPress を丸ごと composer で管理出来るといろいろ便利ですね。

    そのほかコマンド追加など

    $ composer import-theme-unit-test

    で、テーマユニットテストがコマンド一発でインポートできるようにしてあったりしてます。

    $ composer provision

    でWordPressのインストールをするように変更したり、

    $ bash ./bin/server.sh
    

    でビルトインサーバーの起動をするように変更しました。

    そのほか、サーバ上で運用するために、config.php ファイルというのも新しく作ったり、config.json を local-config.json って名前に変えたりしてます。

    詳しい使い方はドキュメントを参照してください。

    気づいたこと

    以前、WordPress Packagist を使うと、WordPress のプラグインも Composer で管理出来ることは知っていたのですが、プラグイン側の composer.json に、

    "type": "wordpress-plugin"

    と書いておいて、Packagist に登録しておくと、ちゃんと WordPress のプラグインとしてインストール出来るようです。
    https://github.com/Automattic/jetpack とかもちゃんと書いてありますね。

    使うには、composer.json にディレクトリの指定を書いたりする必要があります。こんなかんじ。ベータ版などを試すときとか地味に便利そうです。

    WordPress でも PHP のエコシステムをうまいこと使っていければ、かなり便利に開発を進めていけそうですね。

    レポジトリ

    何かあれば issue とかプルリクとかくださいー。

     

  • PHPのIf文的なものまとめ

    某OSSのソースコードを見てたら、if文の代わりに使っているいろんな記述がありました。知ってないと読めないモノもいろいろあったのでちょっとまとめてみます。

    普通にif文

    if( $condition ) {
        hello();
    }

    とりあえずごくごく普通のやつ。

    if( $condition ) hello();

    括弧を省略すると、if文の次の式が実行される。

    三項演算子

    ( $condition ) ? hello() : null;

    条件を反転するともう少し短くかけます。

    ( !$condition ) ?: hello();

    PHP5.3以降からtrueの時の動作を省略できるようになったようです。

    switch文

    switch文を使ってもif文と同じことが出来ます。

    switch (true) {
        case $condition:
            hello();
            break;
    }

    正直switch文を使うべきケースがよくわかってません。if~elseifで十分だと思う。

    and演算子

    論理演算子の&&や、andを使ってもif文みたいなコトは出来ます。論理積演算子の場合左から順に処理され、falseyな値が出た時点で処理を終了するので、こんな書き方が出来ます。

    $condition && hello();
    $condition and hello();

    まとめ

    普通にif文使えよ!って思いました。可読性を大事にしましょう。

  • ComposerをOSにインストールして、いつでもどこでもさくっとComposerできるようにする

    Composer 便利ですね。Rubyのbundleみたいな。初めて名前を聞いたときは、ComposerってHTMLエディタかよって思った人もたぶん多いはず。

    ただ、毎回毎回

    curl -s https://getcomposer.org/installer | php	
    

    とか、

     php composer.phar update          
    

    ってやるのがかったるいなぁって思ってました。

    composer update  
    

    とはならんのかと。

    http://getcomposer.org/doc/00-intro.md#globally-on-osx-via-homebrew-
    ComposerをOSにインストールする方法が書いてありました。ドキュメントって読むもんですね。

    homebrewでインストール

    $ brew tap josegonzalez/homebrew-php
    

    でリポジトリを追加して、

    $ brew install josegonzalez/php/composer
    

    したらインストール完了!と思っていたのですが、

    composer: Missing PHP53, PHP54 or PHP55 from homebrew-php. Please install one of them before continuing

    と怒られました。

    Note: If you receive an error saying PHP53 or higher is missing use this command to install php brew install php53-intl

    と公式にもあるので、これを追加。ただしPHP5.4にしたいので、

    $ brew install php54-intl
    

    を実行。すると、

    Error: No available formula for zlib
    Please tap it and then try again: brew tap homebrew/dupes
    Searching taps…

    だそうなので、

    brew tap homebrew/dupes
    

    してから、改めて実行。これを実行すると、homebrewからphp5.4も一緒にインストールされるので結構時間がかかります。
    また、PHPのバージョンがApacheとターミナルとで違うと面倒くさいので、/etc/apache2/httpd.confで、LoadModule php5_moduleの行を

    LoadModule php5_module /usr/local/opt/php54/libexec/apache2/libphp5.so
    

    に書き換え、Apacheを再起動します。php.iniの場所も変わるのでタイムゾーンやらの設定をしてあげましょう。

    そして、

    $ brew install josegonzalez/php/composer
    

    を実行すると、ようやく無事にインストールできました。意外に結構かかりました。

    Windowsの場合

    http://getcomposer.org/doc/00-intro.md#installation-windows
    書いてあります。Composer-Setup.exeを落としてインストールを実行するだけでいいみたいですね。

    楽そうですね。

    これでようやく、bundle気分で、composerが使えそうです。

  • phpで日本の祝日や振替休日を出力する。

    いまさらですが、あけましておめでとうございます。HTML5KARUTAに参加させていただいたり、引っ越しがあったりでブログがろくに書けませんでした。今年もよろしくお願いします。

    そして、今回の内容ですが、元ネタは Google Calendar API から日本の祝日データを取得 | memo.dogmap.jpです。

    function get_holidays_this_month($month){
    
        $holidays_url = sprintf(
                'http://www.google.com/calendar/feeds/%s/public/full-noattendees?start-min=%s&start-max=%s&max-results=%d&alt=json' ,
                '[email protected]' ,
                '2013-'.$month.'-01' ,  // 取得開始日
                '2013-'.$month.'-31' ,  // 取得終了日
                31            // 最大取得数
                );
        if ( $results = file_get_contents($holidays_url) ) {
                $results = json_decode($results, true);
                $holidays = array();
                foreach ($results['feed']['entry'] as $val ) {
                        $date  = $val['gd$when'][0]['startTime'];
                        $week = date('w',strtotime($date));
                        $title = $val['title']['$t'];
                        $holidays[$date] = $title;
    
                        if( $week == 0) {
                            $nextday = date('Y-m-d',strtotime('+1 day', strtotime($date)));
                            $holidays[$nextday] = '振替休日';
                        }
    
                        $before_yesterday = date('Y-m-d',strtotime('-2 day', strtotime($date)));
    
                        if(isset($holidays[$before_yesterday])){
                            $yesterday = date('Y-m-d',strtotime('-1 day', strtotime($date)));
                            $holidays[$yesterday] = '国民の休日';
                        }
    
                }
                ksort($holidays);
        }
        return $holidays;
    }

    とりあえず1か月分の祝日を取得します。ついでに振替休日やら、国民の休日にも対応してみました。国民の休日なんてめったにあるもんじゃないんですけど、2015年にまたあるようなので、とりあえず実装してみました。イベントスケジュールとかを作るときに結構便利です。

    追記:http://memo.dogmap.jp/2013/01/25/re-google-calendar-japanese-holidays/

    確かに・・・・

  • 地味に便利:自動的にリンクにclass=”current”を付加するPHP書きました。

    静的サイトを作るときに、ヘッダーとかグローバルナビゲーションとかを共通化して、読み込むとコードも見やすいし、修正とかのメンテナンスも楽ですよね。

    そんなときに、便利な関数です。

    [php]
    <?php

    function is_current( $uri = "" ) {
    $uri = trim( $uri, "/" );
    $request_uri = $_SERVER[‘REQUEST_URI’];

    if( $uri && strpos($request_uri."/", "/".$uri."/", 0) !== FALSE ) {
    return true;
    }
    $request_uri = trim(str_replace( "/index.php", "", $request_uri ), ‘/’);
    if( !$uri && !$request_uri ) {
    return true;
    }
    return false;
    }

    function echo_current( $uri = "" ) {
    if(is_current( $uri )) {
    echo ‘current’;
    };
    }
    ?>
    [/php]

    こんな感じで使います。引数が空の場合は、トップページのときにcurrentを吐きます。

    [php]
    <li class="nav1 <?php echo_current();?>"><a href="/">ホーム</a></li>
    <li class="nav2 <?php echo_current("news");?>"><a href="/news">ニュース</a></li>
    [/php]

    静的サイトを作るときにrequire_once $_SERVER[‘DOCUMENT_ROOT’].”/inc/functions.inc”;
    とかしてやると色々捗ります。

  • 「チュートリアルで作成したブログにタグ機能を実装するチュートリアル」をcakePHP2.0でやってみた。

    元ネタはこれ。チュートリアルで作成したブログにタグ機能を実装するチュートリアル – 「最果て」の支部

    cakePHPを最近触りだしたのですが、巷にcakePHP1系の情報があふれているのでなかなか大変な今日この頃です。

    とりあえず、cakePHP2.0のブログチュートリアルにタグ機能を実装してみました。

    やっていることは元ネタと変わらないので、そちらを読みつつやっていければと思います。

    テーブルの作成

    タグ機能みたいな、複数の値と複数の値を関連づけるような機能(この場合だと複数の記事が一つのタグに所属する&複数のタグが一つの記事に所属する)は、一筋縄ではいかないようです。投稿を管理するテーブルにタグを管理するフィールドを作って、タグのテーブルにもその逆を作って、そこにカンマ区切りとかjsonとかで・・・・とか、どう考えても無茶が過ぎるし、SQLで対処できなくなりますよね。

    なので、タグと投稿を関連づけるための別のテーブルを用意します。WordPressだと、term_relationshipsっていうテーブルが有るのですが、それと同じ事をやろうというわけ。

    それをcakePHPではhasAndBelongsToMany通称HABTMと言う機能で実装できるようです。

    なので、まずその二つのテーブルを作成します。

    [sql]
    CREATE TABLE `tags` (
    `id` int(10) unsigned NOT NULL auto_increment,
    `tag` varchar(100) default NULL,
    PRIMARY KEY (`id`)
    )
    [/sql]

    [sql]
    CREATE TABLE `posts_tags` (
    `post_id` int(10) unsigned NOT NULL default ‘0’,
    `tag_id` int(10) unsigned NOT NULL default ‘0’,
    PRIMARY KEY (`post_id`,`tag_id`)
    )
    [/sql]

    HABTMのテーブル名は、関連づけるテーブル1_テーブル2、フィールド名も、テーブル1の単数形_idで作成するようにと規約にあるようなので、その方がベターだと思われます。

    モデルの作成

    Tag.phpをModelディレクトリ内に作成します。
    この中にタグの追加、編集などを行うメソッド(parseTags)を定義します。これをコントローラーで呼ぶ訳ですね。

    [php]
    <?php
    class Tag extends AppModel {
    public $name = ‘Tag’;

    public $hasAndBelongsToMany = array(
    ‘Post’ => array(
    ‘className’ => ‘Post’,
    ‘joinTable’ => ‘posts_tags’,
    ‘foreignKey’ => ‘tag_id’,
    ‘associationForeignKey’ => ‘post_id’
    )
    );

    public function parseTags($tagString) {
    $ids = array();

    $tags = explode(‘,’,trim($tagString));

    foreach ($tags as $tag):
    if(!empty($tag)){
    //DBからタグに対応する列を取得
    $tag = trim($tag);
    $this->unbindModel(array(‘hasAndBelongsToMany’ => array(‘Post’)));
    $tagRow = $this->findByTag($tag);

    if(is_array($tagRow)){
    //タグが登録済の処理
    if(in_array($tagRow[‘Tag’][‘id’], $ids)){
    continue;
    }
    $ids[] = $tagRow[‘Tag’][‘id’];
    }else {
    $newTag[‘Tag’][‘tag’] = $tag;
    $newTag[‘Tag’][‘id’] = "";
    $this->save($newTag);
    $ids[] = $this->getLastInsertID();
    }
    }

    endforeach;

    return $ids;
    }
    }

    [/php]

    $hasAndBelongsToMany繋ぐテーブルを定義します。
    結合とかはこれだけで勝手にやってくれる模様。

    次いで、Post.php。
    $hasAndBelongsToManyを定義するのは一緒。
    Tag.phpでは書いてあった、’foreignKey’と’associationForeignKey’が書いてません。ただ、デフォルト値でforeignKeyは現在のモデル名_id,associationForteignKeyは外部モデル名_idになるようですので問題ないようです。
    ここで、findAllByTagsというデータベースからあるタグがついた記事のデータを持ってくるメソッドと、それの数を数えるfindCountByTagsというメソッドの二つを用意します。

    [php]
    class Post extends AppModel {
    public $name = ‘Post’;

    public $validate = array(
    ‘title’ => array(
    ‘rule’ => ‘notEmpty’
    ),
    ‘body’ => array(
    ‘rule’ => ‘notEmpty’
    )
    );

    public $hasAndBelongsToMany = array(
    ‘Tag’ => array(
    ‘className’ => ‘Tag’,
    ‘order’ => ‘tag’
    )
    );

    public function findCountByTags($tags = array(), $criteria = null) {
    if(count($tags) <= 0){
    return 0;
    }
    if(!empty($criteria)) {
    $criteria = ‘AND’.$criteria;
    }

    $prefix = $this->tablePrefix;
    $count = $this->query(
    "SELECT COUNT(‘Post.id’) AS count FROM
    (SELECT Post.id, COUNT(DISTINCT tags.tag) AS uniques
    FROM {$prefix}posts Post, {$prefix}posts_tags posts_tags, {$prefix}tags tags
    WHERE Post.id = posts_tags.Post_id
    AND tags.id = posts_tags.tag_id
    AND tags.tag IN (‘".implode("’, ‘", $tags)."’) $criteria
    GROUP BY posts_tags.Post_id
    HAVING uniques = ".count($tags).") x" );

    return $count[0][0][‘count’];
    }

    public function findAllByTags($tags = array(), $limit = 50, $page = 1, $criteria = null){
    if(count($tags) <= 0){
    return 0;
    }
    if(!empty($criteria)) {
    $criteria = ‘AND’.$criteria;
    }

    $prefix = $this->tablePrefix;
    $offset = $limit * ($page-1);
    $posts = $this->query(
    "SELECT
    Post.id,
    Post.title,
    Post.created,
    COUNT(DISTINCT tags.tag) AS uniques
    FROM
    {$prefix}posts Post,
    {$prefix}posts_tags posts_tags,
    {$prefix}tags tags
    WHERE Post.id = posts_tags.Post_id
    AND tags.id = posts_tags.tag_id
    AND tags.tag IN (‘".implode("’, ‘", $tags)."’) $criteria
    GROUP BY posts_tags.Post_id
    HAVING uniques = ‘".count($tags)."’
    ORDER BY Post.created DESC
    LIMIT $offset, $limit"
    );

    return $posts;
    }
    }
    [/php]

    コントローラーの作成、編集

    PostController.phpでは、
    まず、add,editにタグを追加、編集する機能を追加。元記事では、$this->dataとなっていますが、cakePHP2.0の場合は$this->request->dataとしないとエラーになります。なりました。

    そして、tagアクションの追加。ここで、先ほどPostモデルで作ったメソッドが使われるわけですね。

    [php]
    <?php
    class PostsController extends AppController {
    public $name = ‘Posts’;
    public $uses = array(‘Post’,’Tag’);
    public $helper = array(‘Html’,’Form’);
    public $components = array(‘Session’);

    public function index() {
    //全てのデータの読み出し
    $posts = $this->Post->find(‘all’);
    $this->set(‘posts’,$posts);
    }

    public function view($id = null) {
    //単一投稿の表示
    $this->Post->id = $id;
    $post = $this->Post->read();
    $this->set(‘post’,$post);
    }

    public function add() {
    if($this->request->is(‘post’)){//$_POSTの判定

    //タグのパース
    if(!empty($this->request->data[‘Post’][‘Tags’])){
    $this->request->data[‘Tag’][‘Tag’] = $this->Post->Tag->parseTags($this->data[‘Post’][‘Tags’]);
    }

    if($this->Post->save($this->request->data)){
    $this->Session->setFlash(‘投稿が保存されました’);
    $this->redirect(array(‘action’=>’index’));//indexへリダイレクト
    }
    else {
    $this->Session->setFlash(‘投稿が保存できませんでした’);
    }
    }
    }

    public function edit($id = null) {
    $this->Post->id = $id;
    if($this->request->is(‘get’)){
    //読み出し
    $this->request->data = $this->Post->read();//データの取得

    //タグの取得
    if(count($this->request->data[‘Tag’])){
    $tags = ”;
    foreach ($this->request->data[‘Tag’] as $tag) {//一行ずつ取り出す
    $tags .= $tag[‘tag’].",";
    }
    $this->request->data[‘Post’][‘Tags’] = substr($tags, 0 ,-1);//最後のカンマを取り除いてViewにデータを投げる
    }
    }
    else {

    if(!empty($this->data[‘Post’][‘Tags’])){
    $this->request->data[‘Tag’][‘Tag’] = $this->Post->Tag->parseTags($this->data[‘Post’][‘Tags’]);
    }

    if($this->Post->save($this->request->data)){
    $this->Session->setFlash(‘投稿を更新しました’);
    $this->redirect(array(‘action’=> ‘index’));
    }else{
    $this->Session->setFlash(‘更新できませんでした’);
    }
    }
    }

    public function delete($id) {
    if($this->request->is(‘get’)){
    //GETならエラー
    throw new MethodNotAllowedException();
    }

    if($this->Post->delete($id)){
    $this->Session->setFlash(‘ID:’.$id.’の投稿を削除しました’);
    $this->redirect(array(‘action’=>’index’));
    }
    }

    public function tag($tag = null) {
    $tags = array();
    App::uses(‘Sanitize’, ‘Utility’);
    $this->Sanitize = new Sanitize;

    if(isset($this->params[‘pass’])){

    foreach($this->params[‘pass’] as $tag):
    $this->Sanitize->paranoid($tag, array(‘ ‘));
    $tags[] = $tag;
    endforeach;

    }
    $paging[‘url’] = ‘/posts/tag’. implode(‘/’, $tags);
    $paging[‘total’] = $this->Post->findCountByTags($tags);
    if($paging[‘total’] > 0){
    $posts = $this->Post->findAllByTags($tags);
    $this->set(‘posts’,$this->Post->findAllByTags($tags));
    $this->render(‘index’);
    }
    else {
    //タグの記事が無い場合の処理。記事が見つかりませんでしたみたいな。
    //exit;
    }
    }

    }

    [/php]

    Viewの編集

    とりあえず、add.ctpとedit.ctpにタグ用のテキストボックスを追加。
    [php]
    echo $this->Form->input(‘Tags’, array(‘size’ => ’40’));
    [/php]

    edit.ctpはこんな感じ。add.ctpは省略。
    [php]
    <h1>Edit Post</h1>
    <?php
    echo $this->Form->create(‘Post’, array(‘action’ => ‘edit’));
    echo $this->Form->input(‘title’);
    echo $this->Form->input(‘body’, array(‘rows’ => ‘3’));
    echo $this->Form->input(‘Tags’, array(‘size’ => ’40’));
    echo $this->Form->input(‘id’, array(‘type’ => ‘hidden’));
    echo $this->Form->end(‘Save Post’);
    ?>
    [/php]

    ここまででちゃんと動くはず!

    タグクラウドの作成

    ここではタグクラウドをTagsController.phpに作成です。タグクラウド(゚⊿゚)イラネって人は別に作らないでいいと思います。
    [php]

    class TagsController extends AppController {

    public $name = "Tags";

    public function tagcloudbox(){
    $prefix = $this->Tag->tablePrefix;
    $tagsData = $this->Tag->query(
    "SELECT tags. * , count(posts_tags.tag_id) PostCount
    FROM {$prefix}tags tags
    LEFT JOIN {$prefix}posts_tags posts_tags ON tags.id = posts_tags.tag_id
    GROUP BY tags.id
    ORDER BY tags.tag"
    );

    $this->set(‘tags’, $tagsData);

    $PostCounts = array();

    if(is_array($tagsData) && count($tagsData) > 0) {
    foreach($tagsData as $tagDetails):
    $PostCounts[] = $tagDetails[0][‘PostCount’];
    endforeach;
    }
    else {
    $PostCounts[] = 0;
    }

    $maxQuantity = max($PostCounts);
    $minQuantity = min($PostCounts);

    $spread = $maxQuantity – $minQuantity;

    if($spread == 0){
    $spread = 1;
    }

    $this->set(‘spread’, $spread);
    $this->set(‘minQuantity’, $minQuantity);
    $this->set(‘browsing’, ‘Tags’);

    }
    }
    [/php]

    んで、View/Tags/tagcloudbox.ctpを作成
    [php]
    <div id="sidecontent">
    <h2>Tag</h2>
    <?php
    $step = (30-10) /$spread;

    foreach($tags as $tag):
    $fontSize = 10 + ($tag[0][‘PostCount’] – $minQuantity) * $step;
    endforeach;

    echo $this->Html->Link($tag[‘tags’][‘tag’], array(‘action’ => ‘tag’,’controller’ => ‘posts’,$tag[‘tags’][‘tag’]), array(‘title’ => $tag[0][‘PostCount’].’Photos’,’rel’ => ‘tag’, ‘style’ => ‘font-size:’.$fontSize.’px’)).’ ‘;

    ?>
    </div>
    [/php]

    ここでは普通にViewにしてありますが、エレメントにしてあげて、他のViewから呼んであげるとかの使い方が良さそうです。

    とりあえず何とかcakePHP2.0で実装できました。
    ちょっとできる人になった気分!笑
    まぁ、タグって結構需要はあると思うので、こんな感じで実装できました!ってだけのエントリーなんですけどね。

    posts/tag/tag1/tag2/tag3
    みたいな絞り込みもできるようです。

    ただ、この元ネタのcheesecake-photoblogのライセンスはGPLv2ですので、当然このエントリーのコードもGPLv2です。使う際はご注意下さい。

  • リンクに activeとかcurrentとかを簡単につける関数

    静的サイトの構築などで地味ですが有ると便利な関数です。

    [php]
    <a <?php print_href(‘/permalink/’);?>>
    [/php]

    とすると、/permalink/にアクセスしているときに

    [html]
    <a href="/permalink/" class="current">
    [/html]

    となります。地味ですが・・・・・

    [php]
    <?php
    $url = $_SERVER["REQUEST_URI"];
    $url = str_replace(‘/index.php’, ”, $url);

    function print_href($href){
    global $url;
    echo ‘href="’.$href.’"’;

    //home用の処理
    if($href == "/"){
    if($url == $href or !$url ){
    echo ‘ class="current"’;
    }
    return;
    }

    if(strstr($url.’/’,$href)){
    echo ‘ class="current"’;
    }
    }
    ?>
    [/php]

  • Topsyから特定のURLに関するつぶやきをWordPressっぽく取得できるClassを書いてみた。

    このサイトのリニューアルこの間リニューアルしたときに作りました。晒そうと思ってすっかり忘れてました。このブログの個別記事の下の方のTwitterタイムラインがそれです。
    Topsyで特定のURLに関するつぶやきや、そのユーザーなどを取得します。

    functions.phpにでも貼っておくと良いと思います。いちおうPHP5用。PHP4系で使いたい場合は__cunstructをGet_Topsy_Trackbackに変えてあげて下さい。

    コード

    [php]
    class Get_Topsy_Trackback {
    private $counter = 0;
    public $response;
    public $trackback;

    function __construct($permalink){
    $topsy = json_decode(file_get_contents("http://otter.topsy.com/trackbacks.json?url=".$permalink));
    $this->response = $topsy->response;
    }

    function get_all_topsy(){
    return count($this->response->list);
    }

    function have_topsy(){
    if(isset($this->response->list[$this->counter])){
    return true;
    }else{
    return false;
    }
    }

    function the_topsy(){
    $this->trackback = $this->response->list[$this->counter];
    $this->counter ++;
    }

    function get_topsy(){
    return $this->trackback;
    }

    function get_the_content(){
    $content = $this->trackback->content;
    return preg_replace(‘/(https?:\/\/[a-zA-Z0-9\.\/:%,!#~*@&_-]+)/’,'<a href="\0" title="\0">\0</a>’,$content);
    }
    function the_content(){
    echo "<p>".$this->get_the_content()."</p>";
    }

    function get_the_author(){
    return $this->trackback->author;
    }

    function get_the_author_nick(){
    return $this->get_the_author()->nick;
    }
    function the_author_nick(){
    echo $this->get_the_author_nick();
    }

    function get_the_author_link(){
    return $this->get_the_author()->url;
    }
    function the_author_link(){
    echo $this->get_the_author_link();
    }

    function the_author(){
    echo ‘<a href="’.$this->get_the_author_link().’" class="author">’.$this->get_the_author_nick().'</a>’;
    }

    function get_the_author_avator(){
    return $this->get_the_author()->photo_url;
    }
    function the_author_avator( $size = 48 ){
    echo ‘<img src="’.$this->get_the_author_avator().’" alt="’.$this->get_the_author_nick().’" width="’.$size.’" height="’.$size.’" />’;
    }

    function get_the_time( $format = "Y-m-d" ){
    return date($format,$this->trackback->date);
    }
    function the_time( $format = "Y-m-d" ){
    echo $this->get_the_time( $format );
    }

    function get_the_permalink(){
    return $this->trackback->permalink_url;
    }
    function the_permalink(){
    echo $this->get_the_permalink();
    }
    }
    [/php]

    基本的にgetから始まるメソッドはreturnで返し、theから始まるメソッドはechoします。実にWordPressっぽいですよね?

    使い方

    こんな感じで使います。
    [php]
    <?php
    $topsy = new Get_Topsy_Trackback($URL);
    if($topsy->have_topsy()):?>
    <p><?php echo $topsy->get_all_topsy();?>回つぶやかれました。</p>
    <ul>
    <?php while($topsy->have_topsy()):$topsy->the_topsy(); ?>
    <li>
    <a href="<?php $topsy->the_author_link();?>"><?php $topsy->the_author_avator()?></a>
    <div class="content"><?php $topsy->the_author();?><?php $topsy->the_content();?></div>
    <div class="meta">Post:<a href="<?php $topsy->the_permalink();?>"><?php $topsy->the_time("Y-m-d");?></a></div>
    </li>
    <?php endwhile; ?>
    </ul>
    <?php else:?>
    <p>まだだれもつぶやいていない様子です。</p>
    <?php endif;?>
    [/php]

    インスタンス化するときに、URLを引数に入れてあげましょう。WordPressで使うのならばget_permalink(get_the_ID())とかですね。
    あとはWordPressっぽいループタグを書いて、WordPressっぽいテンプレートタグを書いてあげればオーケーです。

    需要があるかどうか解らないけれど結構便利だと思うので、Topsy使ってみたいけど・・・って人は使ってみて下さい!

  • hetemlでCakePHPをインストールするときは、PHP5.3で動かすべし。

    hetemlでcakePHPを使おうと思って色々一日試行錯誤していたのですが、ちゃんとインストールできていると、

    http://example.org/cake_dir/

    が、

    という画面になるらしいんですが、CSSの効いていない画面で、“Missing Controller”

    また、アプリケーション自体にはアクセスできるのですが、アプリケーションのアクションにはアクセスできない。つまり、

    http://example.org/cake_dir/appname/にはアクセスできるけど、http://example.org/cake_dir/appname/actionnameや、http://example.org/cake_dir/appname/indexにはアクセスできないといった症状が見られた場合、PHP5.3で動作させるようにすると解決するようです。

    PHP5.3で動作させるには、動作させたい、ディレクトリのか、その親の階層の.htaccessに、

    [plain]
    AddHandler php5.3-script .php
    [/plain]

    に記述すれば動作します。

    あんまり日本語の情報が無いようですが、頑張っていきたいです。

  • jQuery.uploadを使った、画像のサムネイルを表示するフォームのデモを作りました。

    以前、jQuery.uploadでアップロード画像のサムネイルの作成というエントリーを書いたので、それの実装を作ってみました。アップロードする画像を選択すると、アップロードされ、それのサムネイルが表示されます。

    また、ページを離れるときに画像をJavascriptで削除していますが、実際に使うときは使わない場面も多いと思いますので、その部分は適当に削除するなり、なんなりして下さい。

    デモ:http://demo.torounit.com/jquery.upload/

    script.js(ajaxでのアップロード等々)

    [js]
    jQuery(function($){
    //送信ボタンの非表示
    $(‘#submit’).hide();

    //フォームの内容が変更されたとき
    $(‘#img’).change(function() {
    var preview = $(‘#preview’);

    //現在表示されているものを消す。
    preview.find("img").fadeOut(300);

    //アップロード
    $(this).upload(
    ‘upload.php’,
    $("form").serialize(),
    function(html){
    //サムネイルの表示
    preview.html(html).animate({"height":preview.find("img").height()+"px"},300,function(){
    preview.find("img").hide().fadeIn(300);
    });
    },’html’);
    });

    //離れるときに画像を削除
    $(window).bind("beforeunload",function(){
    var unlinkFile = $("#postPhotoName").val();
    $.ajax({
    async: false,
    cache: false,
    type: "POST",
    url: "upload.php",
    data: "postPhotoName="+unlinkFile

    });

    });

    });
    [/js]

    upload.php(アップロードしたファイルを加工するスクリプト)

    [php]
    <?php

    //前にアップロードされた写真のファイル名
    $postPhotoName = $_POST["postPhotoName"];

    //古いファイルの削除
    if($postPhotoName){

    unlink("./img/".$postPhotoName);
    unlink("./img/thumb-".$postPhotoName);
    }

    $result = false;

    if($_FILES[‘img’][‘name’] == "") {
    die("ファイルがないぜよ。");

    }else{
    //アップロードされたファイルの情報を取得
    $fileName = basename(date("U")."-".$_FILES[‘img’][‘name’]);
    $fileType = $_FILES[‘img’][‘type’];
    $fileTmpName = $_FILES[‘img’][‘tmp_name’];

    if(!preg_match("/jpeg/",$fileType)){

    unlink($fileTmpName);
    die( "jpegじゃないぜよ。");

    }else{
    //ファイルの保存
    if (!move_uploaded_file($fileTmpName, ‘./img/’ . $fileName)) {

    die(‘保存にしっぱいしたぜよ。’);

    } else {

    //サムネイル作成
    include(‘class.image.php’);
    list($width, $height, $type, $attr) = getimagesize(‘img/’.$fileName);

    $thumb = new Image(‘img/’.$fileName);
    $thumb->name(‘thumb-‘.basename($fileName,".jpg"));

    if($width>$height){
    if($width > 500) $thumb->width(500);
    }else{
    if($height > 500) $thumb->height(500);
    }

    $thumb->save();
    $result = true;
    }

    }

    }

    if($result == true){
    ?>

    <img src="<?php echo ‘./img/thumb-‘.$fileName;?>">
    <input type="hidden" value="<?php echo $fileName?>" name="postPhotoName" id="postPhotoName">
    <?php
    }

    [/php]

    HTML

    [html]
    <form method="post" enctype="multipart/form-data" action="upload.php">
    <input type="file" value="" id="img" name="img" size="50" />
    <input type="submit" id="submit" />
    <div id="preview"><div>ここにプレビューが表示されます</div></div>
    </form>
    [/html]

    このままつかうのはちょっとあれかもですけど、アイデア次第で色々使い道がありそうです。

  • PEARのCache_Liteを使ってみた

    軽量キャッシュライブラリのCache_Liteの使い方です。

    [php]

    //ライブラリの読み込み
    include_once(‘Cache/Lite.php’);

    //設定
    define("CACHE_DIR","./tmp/");
    define("CACHE_TIME",300);//5分

    //キャッシュのID
    $id = ‘hoge’;
    $options = array(
    ‘cacheDir’ => CACHE_DIR,
    ‘lifeTime’ => CACHE_TIME
    );

    //インスタンス化
    $Cache_Lite = new Cache_Lite($options);

    if ($data = $Cache_Lite->get($id)) {
    //キャッシュが有効なときの処理
    //$dataに取得すべきデータが格納されている。

    } else {
    //キャッシュが無効、存在しないとき
    $url = "http://search.twitter.com/search.json?q=" . urlencode("ぬこ") . "&rpp=100&lang=ja";
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    $search = curl_exec($ch);
    curl_close($ch);

    $Cache_Lite->save($search,$id);//キャッシュを保存
    }
    }
    [/php]

    キャッシュを手動で消すには、キャッシュの保存されているディレクトリ、(この場合./tmp/)の中身を消すだけで大丈夫です。
    TwitterAPIとか回数制限も多いので、使いどころはたくさんあると思います。

  • ユーザーエージェントでブラウザの判別をするPHPとかjQueryを書いてみた。

    自分でコピペできるように、browser判別のTipsを貼っておきます。

    PHPで判別

    [php]
    function browser_class(){
    $classes = "";
    $agent = getenv( "HTTP_USER_AGENT" );

    if(strstr($agent,"MSIE")){
    $classes .= "msie ";
    if(strstr($agent,"MSIE 6.0")) $classes .= "ie6 lt7 lt8 lt9";
    if(strstr($agent,"MSIE 7.0")) $classes .= "gt6 ie7 lt8 lt9";
    if(strstr($agent,"MSIE 8.0")) $classes .= "gt6 gt7 ie8 lt9";
    if(strstr($agent,"MSIE 9.0")) $classes .= "gt6 gt7 gt8 ie9";
    }
    else {
    $classes .= "noie ";
    if( strstr($agent,"Firefox")) {
    $classes .= "firefox gecko";
    }
    elseif( strstr($agent,"Safari")) {
    $classes .= "safari webkit";
    }
    elseif( strstr($agent,"Chrome")) {
    $classes .= "Chrome webkit";
    }
    elseif( strstr($agent,"Opera")) {
    $classes .= "opera presto";
    }
    //ここからは気休め。
    //AppleWebKit/534.30 (KHTML, like Gecko) なので先に記述
    elseif( stristr($agent,"WebKit")) {
    $classes .= "webkit";
    }
    //AppleWebKit/534.30 (KHTML, like Gecko) なので先に記述
    elseif( stristr($agent,"KHTML")) {
    $classes .= "khtml";
    }
    elseif(stristr($agent,"Gecko")) {
    $classes .= "gecko";
    }else {
    $classes .= "other";
    }
    }
    return $classes;
    }
    [/php]

    ついでにwordpressのbody_classに追加するなら、
    [php]
    function add_browser_class($classes){
    $classArr = explode(" ",browser_class());
    $return = array_merge($classes,$classArr);
    return $return
    }

    add_filter("body_class","add_browser_class");
    [/php]

    とかやればうまく行ける気がします。

    jQueryで判別

    参考:
    jQuery.supportでのブラウザ判別
    http://w3g.jp/blog/tools/jquery_browser_sniffing

    [js]
    jQuery(function($){

    $html = $("html");

    if(!$.support.checkOn && $.support.checkClone){
    $html.addClass("webkit noie");
    }else if($.support.checkOn && $.support.noCloneEvent && window.globalStorage){
    $html.addClass("firefox noie");
    }else if($.support.checkOn && $.support.noCloneEvente && !window.globalStorage){
    $html.addClass("opera noie");
    }else if(!$.support.noCloneEvent && $.support.opacity){
    $html.addClass("gt6 gt7 gt8 ie9 msie");
    }else if(!$.support.opacity){
    if(!$.support.style){
    if (typeof document.documentElement.style.maxHeight != "undefined") {
    $html.addClass("gt6 ie7 lt8 lt9 msie");
    } else {
    $html.addClass("ie6 lt7 lt8 lt9 msie");
    }
    }else{
    $html.addClass("gt6 gt7 ie8 lt9 msie");
    }
    }else{
    $html.addClass("other");
    }
    });
    [/js]