ええやんブログ

ええやないかのええやんブログ

phpMyAdminのサイドバーで#1142エラーが出る

あるデータベースへの操作権限を与えたユーザーを作成し、そのユーザーでログインしたところ、下記のエラーがphpMyAdminのサイドバーに表示されてしまいました。

#1142 - SELECT command denied to user '********'@'localhost' for table 'pma_recent'

どうやらphpMyAdminが最近使用したテーブルを取得しようとしてエラーとなっているようです。
で、解決方法は以下の二つあります。

最近使用したテーブルは無視する

phpMyAdminのトップから「設定」->「ナビゲーションフレーム」->「最近使用したテーブル」の設定を0にします。
こうすると、そもそもそんなSELECTは走らないのでエラーになりません。

最近使用したテーブルへの操作権限を与える

最近使用したテーブル(pma_recent)はphpmyadminというデータベース内に存在するので、該当ユーザーがphpmyadminのデータベースも操作できるよう特権を付与します。
こっちのほうがなんか正しいやり方にみえますね。

GRANT
    SELECT,
    INSERT,
    UPDATE,
    DELETE
 ON
    `phpmyadmin`.* TO '********'@'localhost';

なんとか6月は記事を書けたぜ…よかった…

Codeigniterでcontrollerをディレクトリ分けする(その2)

どうもー。
今回は前回に引き続き、Codeigniterのcontrollerをディレクトリ分けする方法についてです。

さて、controllerをこんな風にディレクトリの下にサブディレクトリを作成しようとすると、Codeigniterはデフォルトではuserまで(第1階層)しか認識しません。

controller
  └ user
    └ pc
    └ smartphone
      └ foo.php

http://example.com/user/pc/foo/indexにアクセスすると、config/route.phpにどう記述しても、そのままではpcコントローラーのfooメソッドにアクセスしてしまいます。

というわけで、第2階層まで認識させるには、こちらを参考にして、下記の手順で変更すればOKです。

MY_Routerを作成

/application/coreの直下にMY_Router.phpを作成して、次のコードをコピペします。

<?php

/*
 * Custom router function v 0.1
 *
 * Add functionality : read into more than one sub-folder
 *
 */
Class MY_Router extends CI_Router
{

    /**
     * Validates the supplied segments.  Attempts to determine the path to
     * the controller.
     *
     * @access private
     * @param  array
     * @return array
     */
    function _validate_request($segments)
    {
        if (count($segments) == 0)
        {
            return $segments;
        }

        // Does the requested controller exist in the root folder?
        if (file_exists(APPPATH.'controllers/'.$segments[0].'.php'))
        {
            return $segments;
        }

        // Is the controller in a sub-folder?
        if (is_dir(APPPATH.'controllers/'.$segments[0]))
        {
            // Set the directory and remove it from the segment array
            $this->set_directory($segments[0]);
            $segments = array_slice($segments, 1);

            /* ----------- ADDED CODE ------------ */

            while(count($segments) > 0 && is_dir(APPPATH.'controllers/'.$this->directory.$segments[0]))
            {
                // Set the directory and remove it from the segment array
                $this->set_directory($this->directory . $segments[0]);
                $segments = array_slice($segments, 1);
            }

            /* ----------- END ------------ */

            if (count($segments) > 0)
            {
                // Does the requested controller exist in the sub-folder?
                if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$segments[0].'.php'))
                {
                    if ( ! empty($this->routes['404_override']))
                    {
                        $x = explode('/', $this->routes['404_override']);

                        $this->set_directory('');
                        $this->set_class($x[0]);
                        $this->set_method(isset($x[1]) ? $x[1] : 'index');

                        return $x;
                    }
                    else
                    {
                        show_404($this->fetch_directory().$segments[0]);
                    }
                }
            }
            else
            {
                // Is the method being specified in the route?
                if (strpos($this->default_controller, '/') !== FALSE)
                {
                    $x = explode('/', $this->default_controller);

                    $this->set_class($x[0]);
                    $this->set_method($x[1]);
                }
                else
                {
                    $this->set_class($this->default_controller);
                    $this->set_method('index');
                }

                // Does the default controller exist in the sub-folder?
                if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$this->default_controller.'.php'))
                {
                    $this->directory = '';
                    return array();
                }

            }

            return $segments;
        }


        // If we've gotten this far it means that the URI does not correlate to a valid
        // controller class.  We will now see if there is an override
        if ( ! empty($this->routes['404_override']))
        {
            $x = explode('/', $this->routes['404_override']);

            $this->set_class($x[0]);
            $this->set_method(isset($x[1]) ? $x[1] : 'index');

            return $x;
        }


        // Nothing else to do at this point but show a 404
        show_404($segments[0]);
    }

    // --------------------------------------------------------------------

    /**
     *  Set the directory name
     *
     * @access public
     * @param  string
     * @return void
     */
    function set_directory($dir)
    {
        /* ----------- CHANGED CODE ------------ */
        // $this->directory = str_replace(array('/', '.'), '', $dir).'/';
        $this->directory = str_replace(array('.'), '', $dir).'/';
    }

}

_validate_requestメソッドの引数で渡される$segmentsには、route.phpに書かれたパス情報がdirectory・controller・functionの順で配列に格納されています。
なので、directoryが格納されている$segments[0]をスライスして、$this->directoryに "/" 区切りで設定するように変更します。
注意点としては、set_directoryメソッドもオーバーライドしておかないと、せっかく設定したディレクトリから "/" を削除してしまいます。

ルーティングを設定

あとはconfig/route.phpにルーティングさせたいディレクトリを書けば、そこに飛ばしてくれます。

$route['pc/(:any)'] = "user/pc/$1";

http://example.com/user/pc/foo/indexにアクセスすると、ちゃんとfooコントローラーのindexメソッドを呼び出してくれます。

ディレクトリ分けをしておかないと、ちょっと大きな案件になった場合にすぐcontrollerだらけになってしまいますよね。
ぜひ参考にして下さい。

Codeigniterでcontrollerをディレクトリ分けする(その1)

どうもeeyanaikaやでー!

今日はCodeigniterのcontrollerをディレクトリ分けするためのURIルーティングについてです。
基本的なルーティングについてはユーザーガイドに書いてあるのですが、ディレクトリに分ける具体例がないので、改めて書いてみたいと思います。

ディレクトリ分け その1

まず管理画面側のcontrollerを下記のように別ディレクトリに分けたい、という場面です。

controller
  └ foo.php
  └ bar.php
  └ admin
    └ baz.php

これは簡単で、config/routes.php

$route['admin/(:any)'] = "admin/$1";

と書けばOKです。
こうすると、URL中に「admin/」があれば、自動的にadminディレクトリ以下のcontrollerを探しにいきます。

ディレクトリ分け その2

つぎに、ユーザー側と管理画面側のcontrollerを下記のように別ディレクトリに分けたい、という場面です。

controller
  └ user
    └ foo.php
    └ bar.php
  └ admin
    └ baz.php

これも簡単で、config/routes.php

$route['admin/(:any)'] = "admin/$1";
$route['user/(:any)'] = "user/$1";

と書けばOKです。そのまんまですね。
こうすると、URL中に「admin/」があれば、adminディレクトリ以下を、「user/」があればuserディレクトリ以下のcontrollerを探しにいきます。

ディレクトリ分け その3

つぎに、ユーザー側と管理画面側のcontrollerを下記のように別ディレクトリに分けて、かつユーザー側へのアクセスURLに「user/」はつけたくない、という場面です。

controller
  └ user
    └ foo.php
    └ bar.php
  └ admin
    └ baz.php

この場合は、config/routes.php

$route['admin/(:any)'] = "admin/$1";
$route['(:any)'] = "user/$1";

と書けばOKです。
こうすると、URL中に「admin/」があれば、adminディレクトリ以下を、それ以外はuserディレクトリ以下のcontrollerを探しにいきます。

今回はここまでやでー。
次は、さらにサブディレクトリをつくってみます。

アプリ内課金(In-App Purchase)でnewNullResponseエラー

今日はiPhoneアプリのアプリ内課金を実装した時に、サーバーサイドで発生したエラーについてのメモです。

サンドボックスで、サーバプロダクトモデルでのレシートの有効性確認のテストを実施していたときに、以下のエラーが発生。
Your request produced an error. [newNullResponse]
レシートにはテストで適当な数字を設定していたのですが、それでも「21002 receipt-dataプロパティのデータは形式が不正です。」が返却されるのを期待していたんですが…

さっそくドキュメントを確認すると、レシートデータはbase64エンコードしないといけないとのこと。
なるほど、base64エンコードしていないと空が返ってくるのかぁ。

というわけで、下のサンプルのような形でレシートの有効性を確認するように修正しました。

<?php

class Iphone_payment {

    /**
     * AppStoreでレシートの有効性を確認する
     *
     * @param $receipt
     * @return レシート確認結果を返す
     */
    public function confirm_receipt($receipt) {

        // Apple Storeに送信するデータを作成
        $data = array(
            'receipt-data' => base64_encode($receipt),
        );

        // 送信データをJSONに
        $send_json = json_encode($data);

        $curl = curl_init("https://sandbox.itunes.apple.com/verifyReceipt");

        // オプションの設定
        curl_setopt($curl, CURLOPT_POST, true);             // POST送信
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);   // 出力結果を加工しない
        curl_setopt($curl, CURLOPT_POSTFIELDS, $send_json); // ポストデータ
        curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-type: application/json; charset=UTF-8')); // HTTPヘッダー

        $result = curl_exec($curl);

        curl_close($curl);

        $result = json_decode($result, true);

        return $result;

    }

}

うおー前途多難だぜ―

imagickがインストールできない(PHP5.4編)

お疲れ様です。eeyanaikaです。

今回はPHPを5.3から5.4にアップグレードした際に、imagickをインストールしたのですが、めちゃめちゃハマりました。
なのでメモとして残しておこうと思います。ちなみにOSはCentOS 5.x系の64bitです。

ImageMagickをインストール

まずはImageMagickを入れてみる。
wgetで最新のソースをダウンロードしてインストール。

cd /usr/local/src/
wget http://www.imagemagick.org/download/ImageMagick-6.8.4-3.tar.gz
tar zxvf ImageMagick-6.8.4-3.tar.gz
cd ImageMagick-6.8.4-3
./configure
make
make install

とりあえず成功みたい。

imagickをインストール

次にimagickを入れてみる。ふむふむ、imagickはbeta版を入れたらいいのかー
こちらもwgetで最新のbeta版のソースをダウンロードしてmake installしてみる。

wget http://pecl.php.net/get/imagick-3.1.0RC2.tgz
tar zxvf imagick-3.1.0RC2.tgz
cd imagick-3.1.0RC2
phpize
./configure
~略~
checking for MagickWand.h header file... configure: error: Cannot locate header file MagickWand.h

うん。エラーや。

MagickWand.hが存在しないっ!

なるほど、PKG_CONFIG_PATHを設定しないといけないのかー

./configure PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
~略~
checking for MagickWand.h header file... configure: error: Cannot locate header file MagickWand.h

うん。エラーや。

まだまだMagickWand.hが存在しないっ!

なるほど、これと同じ現象で、ヘッダーファイルの見に行く先が違うのかー
ImageMagickディレクトリをリネームで退避させておいて、シンボリックリンクを作成してみる。

cd /usr/local/include/
mv -f ImageMagick _ImageMagick
ln -s /usr/local/include/ImageMagick-6 /usr/local/include/ImageMagick
cd /usr/local/src/ImageMagick-6.8.4-3/
./configure
make
make install

うまくいきました。
以前インストールされていたImageMagickのバージョンが悪さをしていたみたいですね。

でもこのあとPHPは5.3にダウングレードされましたとさ。ちぇっ。

Facebookアプリでログイン後にリダイレクトループする

うっす。eeyanaikaです。

Facebookアプリのログイン処理後に、通常はredirect_uriで設定しているURLに遷移するはずなんですが、「このウェブページにはリダイレクトループが含まれています。」とか「Internet Explorer ではこのページを表示できません」となってしまう現象に遭遇してしまいました。

FacebookのiFrame内に表示しているならこれとかこれみたいにCookieの値が取れないのが原因なんだろうけど、今回はFacebook上で表示するものでもないしなー。
$_REQUEST['signed_request'] が取得できていないのが原因だというところまでは分かったのですが、無理や!ということで一晩寝かしてみました。

翌日調べてみるとstackoverflowでこんな記事が。 なるほど、https://example.com/からhttps://www.example.com/へリダイレクトしたりすると、別ページ扱いになってsigned_requestが取得できないんですね。
僕の場合は.htaccessでRewriteRuleを使ってURLを変えていたのがまずかったみたいです。

てか、どんだけFacebookアプリでつまづいてるねん。

はてなブログのキーワードリンクがなんかいや

どうもー。eeyanaikaです。

はてなブログを使っていて思うのが、キーワードリンクのせいでブログの見た目がリンクだらけになって、なんかいやなんですよね。
でも、それがはてなのアイデンティティでいいじゃない、「pointer-events:none;」は使いたくないし!とも思ったりします。

というわけで、今使っているデザインテーマは「Report」なので、それをベースにデザイン変更をしたいと思います。
まずは、はてなブログのダッシュボードにある[デザイン]->[カスタマイズ]->[{} デザインCSS]を選択します。

CSSを記入するテキストエリアがあるので、下記の内容を記入します。
内容的にはマウスオーバー時にアンダーラインを出して、リンクということを訪問者に示して、それ以外の場合はただのテキストと同じようにふるまうようにしています。

a.keyword {
  border-bottom: none;
  text-decoration: none;
}
a.keyword:hover {
  text-decoration: underline;
}
a.keyword:visited {
  color: #000000;
}

どうですかね?
このページ、あんまりキーワードリンクになってないからよく分かんないですよね。
あたまいたい。