NakajiJapan

餓鬼の超弩級日記


brewでphpをインストール

phpもbrewでインストールするときもなんやかんやしないとけません。

以下のサイトを見習ってなんだかんだ叫びました。

藤井隆,KUMI SAITOU,MACHIKO SUGAKI,TOMOKO HADA
アンティノスレコード
発売日:2000-03-08

ごめんちょ。

だれかがつくったFormulaを落としてそれを使用します。

$ brew install https://raw.github.com/adamv/homebrew-alt/master/duplicates/php.rb --with-mysql --with-pgsql --with-apache --with-intl
LoadModule php5_module    /usr/local/Cellar/php/5.3.8/libexec/apache2/libphp5.so
AddType application/x-httpd-php .php
AddType application/x-httpd-php-source .phps

実はこのまま設定すると、参考にしたサイトの通りエラーが出力されてしまいPHPがインストールできませんでした。

[nakajijapan] #apachectl -t                                                                                                                                   [/usr/local/Cellar/httpd/2.2.21/conf]
httpd: Syntax error on line 431 of /usr/local/Cellar/httpd/2.2.21/conf/httpd.conf: Cannot load /usr/local/Cellar/php/5.3.8/libexec/apache2/libphp5.so into server: dlopen(/usr/local/Cellar/php/5.3.8/libexec/apache2/libphp5.so, 10): Symbol not found: _ap_loaded_modules\n  Referenced from: /usr/local/Cellar/php/5.3.8/libexec/apache2/libphp5.so\n  Expected in: /usr/local/Cellar/httpd/2.2.21/bin/httpd\n in /usr/local/Cellar/php/5.3.8/libexec/apache2/libphp5.so

どうもapache側でなんか悪さしているみたいとのことなのでとりあえず手動でインストールしてみることにします

brew uninstall httpd
cd /usr/local/Library
wget http://ftp.jaist.ac.jp/pub/apache/httpd/httpd-2.2.21.tar.gz
tar zxvf httpd-2.2.21.tar.gz
cd httpd-2.2.21
./configure -enable-shared=max --enable-rewrite --prefix=/usr/local/Cellar/httpd/2.2.20
make
make install

再度apacheを起動させたら無事起動できました。
mysqのpdoもインストールされているみたいでよかったですです。

■参照URL
http://notfornoone.com/2010/07……w-leopard/
http://d.hatena.ne.jp/pasela/2……26/mac_php
http://totoro.ws/blog/2011/09/……rew-2.html

No Comments »

[zend]ZendFrameworkでCSV出力をおこなう方法

突貫工事ではありますが、controllerからデータをCSV出力させるようにさせてみた。

        // csv?
        if (isset($params['csvFlg'])) {
            $this->getResponse()
                 ->setHeader('Content-disposition','attachment; filename="data_'.date('YmdHis').'.csv"' )
                 ->setHeader('Content-type', 'test/x-csv')
                 ->sendHeaders();
            foreach($users as $user) {
                $this->getResponse()->appendBody( implode(',', $user) . "\r\n" );
            }
            $this->getResponse()->outputBody();
            exit;
        }
No Comments »

[zend]アプリ側(UTF8)とDB(EUC-JP)の文字コード変換をPDOで行う

システム開発行っていると、なるべく昔の仕様を変更せずに既存リソースを生かしながらも新しい開発行っていかな
ければいけない自体が多々ある思われる。

今回の件でいえば、文字コードの問題。

システム側からみたら文字コードなんていっそのこと統一したほうが何も考えないで楽なんだけど、そうも
いってられず昔の文字コードをどう利用していくかを考えなければいけないときがある。

理想としてはすべてUTF-8にしたかったがそうはいかない。DBがEUC-JPだからだ。
DB・アプリ間でのインターフェースでそれぞれ変換する必要がある。

対策としては、ZendFrameworkで利用しているPDOのクラスを継承して変換をさせるようにしました。
(この場合、局所的な対処ですがとりあえず目的は果たせたのでこれでいきました)

※ZendでDIコンテナ使って細かいこと実現しているのでそのへんは・・・・。

まずは

abstract class App_Db_Adapter_Pdo_Abstract extends Zend_Db_Adapter_Pdo_Abstract
{
    /**
     * Creates a PDO object and connects to the database.
     *
     * @return void
     * @throws Zend_Db_Adapter_Exception
     */
    protected function _connect()
    {
        // if we already have a PDO object, no need to re-connect.
        if ($this->_connection) {
            return;
        }

        // get the dsn first, because some adapters alter the $_pdoType
        $dsn = $this->_dsn();

        // check for PDO extension
        if (!extension_loaded('pdo')) {
            /**
             * @see Zend_Db_Adapter_Exception
             */
            require_once 'Zend/Db/Adapter/Exception.php';
            throw new Zend_Db_Adapter_Exception('The PDO extension is required for this adapter but the extension is not loaded');
        }

        // check the PDO driver is available
        if (!in_array($this->_pdoType, PDO::getAvailableDrivers())) {
            /**
             * @see Zend_Db_Adapter_Exception
             */
            require_once 'Zend/Db/Adapter/Exception.php';
            throw new Zend_Db_Adapter_Exception('The ' . $this->_pdoType . ' driver is not currently installed');
        }

        // create PDO connection
        $q = $this->_profiler->queryStart('connect', Zend_Db_Profiler::CONNECT);

        // add the persistence flag if we find it in our config array
        if (isset($this->_config['persistent']) && ($this->_config['persistent'] == true)) {
            $this->_config['driver_options'][PDO::ATTR_PERSISTENT] = true;
        }

        try {
            $this->_connection = new PDOCSTM(
                $dsn,
                $this->_config['username'],
                $this->_config['password'],
                $this->_config['driver_options']
            );

            $this->_profiler->queryEnd($q);

            // set the PDO connection to perform case-folding on array keys, or not
            $this->_connection->setAttribute(PDO::ATTR_CASE, $this->_caseFolding);

            // always use exceptions.
            $this->_connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

        } catch (PDOException $e) {
            /**
             * @see Zend_Db_Adapter_Exception
             */
            require_once 'Zend/Db/Adapter/Exception.php';
            throw new Zend_Db_Adapter_Exception($e->getMessage(), $e->getCode(), $e);
        }

    }

}

なんてものを作成します。

実際変更したところといえば、

# その1
$this->_connection = new PDOCSTM();

あとは、PDOを継承して実装したクラスを記述しておしまいです。
これでほぼ取得や更新両方SQLを変換することができます。

class PDOCSTM extends PDO {
    public function __construct($dsn, $username="", $password="", $driver_options=array()) {
        parent::__construct($dsn, $username, $password, $driver_options);
        $this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('STMT', array($this)));
    }
}
class STMT extends PDOStatement {
    public $dbh;
    protected function __construct($dbh) {
        $this->dbh = $dbh;
    }
    function fetch($option=PDO::FETCH_ASSOC) {
        $row = parent::fetch($option);
        foreach ($row as $key=>$val) {
            # その1
            $row[$key] = mb_convert_encoding($val, "UTF-8", "EUC-JP");
        }
        return $row;
    }
    function fetchAll($option=PDO::FETCH_ASSOC) {
        $rows = parent::fetchAll($option);
        foreach ($rows as $key => $row) {
            foreach ($row as $crm => $val) {
                # その2
                $rows[$key][$crm] = mb_convert_encoding($val, "UTF-8", "EUC-JP");
            }
        }
        return $rows;
    }
    function execute($params=array()) {
        if (APPLICATION_ENV !== "production") {
            if (!preg_match("/SELECT/", $this->queryString)) {
                error_log("[SQL] " . $this->queryString . " Array::" . print_r($params,true));
            }
            else {
                error_log("[SQL] " . $this->queryString);
            }
            if (!empty($params)) {
                # その3
                $params = App_Array::getEncodedData($params, "EUC-JP", "UTF-8");
            }
        }
        return parent::execute($params);
    }
}

ちなみに「App_Array()」は配列のデータを再帰的に文字コード変換させてます。

                # その3
                $params = App_Array::getEncodedData($params, "EUC-JP", "UTF-8");
No Comments »

Zend_Application に Autoloderの設定を行う

昔のバージョンだとZendのソースを書き換えなくちゃいけなかったけど1.10からは自分でZend_Application利用してカスタマイズできるようになったみたいです。

まずはPHP.iniを以下のように設定します。
設定項目としては、どのクラスが宣言された場合はどのディレクトリを読み込みにいくかという設定です。

やりかたはいろいろあると思いますが、とりあえずこんな感じでいいかなレベルです。

;--------------------
; loader
;--------------------
; resources.autoloader.lists.(設定名) = "(どのクラス),(読み込み先)"
resources.autoloader.lists.validate = "Validate,models/Validate"
resources.autoloader.lists.dbtable = "Model_DbTable,models/DbTable"
resources.autoloader.lists.mappers = "Model_Mapper,models/mappers"

リソースのプログラムは以下のように実装します。


/*
 * My_Application_Resource_Autoloader
 */
class My_Application_Resource_Autoloader extends Zend_Application_Resource_ResourceAbstract
{
    /**
     *
     * @return My_Application_Resource_Autoloader
     */
    public function init()
    {
        // init
        $router = null;

        // オプション情報取得
        $options = $this->getOptions();

        $moduleLoader = new Zend_Application_Module_Autoloader(array(
            'basePath' => APPLICATION_PATH,
            'namespace' => '',
        ));

        foreach ($options['lists'] as $key => $resource ) {
            $data = explode(',', $resource);
            $moduleLoader->addResourceType($key, $data[1], $data[0]);
        }

        return ;
    }
}

これでいけるはず!!!

■参考URL
http://d.hatena.ne.jp/sasezaki……0090415/p1

No Comments »

[zendframework][smarty]PC/Mobile版切替時にSmartyの設定で気をつけること

最近ハマったこと。

携帯版とPC版でテンプレートを切り分けているときにちゃんとテンプレートキャッシュも別で保存しておかないと
最初に表示した画面の状態をずっと保持し続けてしまう。たとえば、PC版で表示したら携帯版で表示しても
PC版で表示されてしまう。

当たり前のことだけど、別にしないとだめだよね。

Smartyのコンパイルファイル(templates_c側)を一緒のディレクトリ・ファイルにしないようにします。
なので携帯版はSMARTY_COMPILE_IDに「_mb」を追加して別管理にしました。

以下がディレクトリ構造。

---------------- 例 -------------------
[root@hoge] # tree templates_c
templates_c
|-- ref
|   |
|   `-- %%DE
|       `-- DE7
|           `-- DE7C2150%%header.html.php
`-- ref_mb
    |
    `-- %%DE
        `-- DE7
            `-- DE7C2150%%header.html.php

Smartyのキャッシュを有効にしたときはまたもう少し考えないといけないな。

例えば、日記を新しく作成した場合はどちらとも作成しないといけないね。

No Comments »

MacにPeclのImagickをインスコしてみる

ImageMagickまではmac portで自動で入れられたのだがなぜかimagickは自動で入れられなかったため
自分でコンパイルしてインストールしてみた。

まず、ImageMagickをインストールする。

$ sudo port install ImageMagick

これで正常にインストールされることでしょう。

次はImagickをインストールします。

$ wget http://pecl.php.net/get/imagick-2.3.0.tgz
$ tar zxvf imagick-2.3.0.tgz
$ cd imagick-2.3.0
$ ./configure --with-imagick=/opt/local
$ make
$ sudo make install

モジュールを移動します

$ cd /usr/lib/php/extensions/no-debug-non-zts-20090626
$ sudo cp * ../

php.iniの設定を変更する

extension=imagick.so

最後にApacheを再起動すれば終了です。

いやー、リナックスだとrpmやらyumコマンドで簡単にインストールできるんだけど
OSによってやり方変えてインストールしなくちゃいけないのは大変ですわい。まぁ
そんな難しいことはしてないんですけどね。。。

■参考URL
MacにPHP/Imagickをインストールする
[pecl]imagick
ImageMagick

No Comments »

[memo]phpmyadminインストールメモ

いままでmysqlの設定というとcuiでやってきたけどなんとなくではありますが、phpMyAdmin
いれてみました。

楽なんですね、これ。

メモっす。本当にメモっす。
たいしたことは書きません。

1ソース落としてして展開。

2設定ファイル名変更

# mv config.sample.inc.php config.inc.php

3設定変更

# vi config.inc.php

設定はクッキーを利用してログインするようにします。
ログイン方法はクッキーを利用する方法とベーシック認証する方法の2パターンがありました。

$cfg['DefaultCharset']                = 'utf-8';
$cfg['PmaAbsoluteUri']              = 'http://hogehoge.com/phpmyadmin';
$cfg['Servers'][$i]['auth_type'] = 'cookie';
//$cfg['Servers'][$i]['auth_type'] = 'http';
$cfg['Servers'][$i]['port']             = '3306';
$cfg['Servers'][$i]['user']             = 'hoge';
$cfg['Servers'][$i]['password']     = 'hogehoge';

これで終了。

後は、もう操作が行えます。

ただ、
「mcrypt 拡張をロードできません。PHP の設定を確認してください」
というエラーがでるんだけど気にしてません。

MacPortでPHP入れたもんでそのコンパイルオプション入っとらんのですよね。。。

■参照URL
phpMyAdmin 3.4.0-dev Documentation
「phpMyAdmin」の導入
Mac に MacPorts を使って MySQL と PHPMyAdmin をインストールする方法

No Comments »

携帯でリダイレクトした際にセッションが切れてしまう件。

携帯版ではまってしまったのでメモ

携帯は基本的にはセッションはパラメータで引き回すようにしています。
しかし、リダイレクト時には自動的にはセッションIDは引き回さないようPHPの仕様でなっています。
そこで、リダイレクト時にもセッションを引き回せるように手動でセッションを引き回すように処理を
加えたのですがなぜかリダイレクト先の処理側でセッションが新しく生成されてしまう。

そう、セッションを引き回していなかったのです。

「加藤さん事件です。」(レポーター風)

一応セッション設定チェック

;----- mobile {-----
resources.session.use_only_cookies      = false
resources.session.use_cookies           = false
resources.session.use_trans_sid         = true
;----- mobile }-----

なんら問題無し。

各処理でのサーバ情報ゲット

[QUERY_STRING] =>
[REQUEST_URI] => /test.php

!?

むむむ、URI自体に問題があるのか。

そういえばリダイレクト先にパラメータとは別に「#top」なんてものも追加していた。。。


http://nakajijapan.net/test.php#top?PHPSESSID=xxxxxxxxxxxxxxx

だとだめで

http://nakajijapan.net/test.php?PHPSESSID=xxxxxxxxxxxxxxx#top

「#」が前に来るか後にくるかででパラメータを認識してくれないようですね。

RFCの決まりごと的には最初にqueryの解析を始めるからそれでもうないって認識されてしまったのかもね。

結構単純なことでした。。

■参照URL
URI – Uniform Resource Identifiers

No Comments »

ZendFrameworkでBasic認証 既にあるものを利用した編

以前、Zendでベーシック認証を自作したエントリーがありましたが、本当は
Zendに用意されているプラグインがあるのです。

なぜ利用しなかったっていうと、Zend側での必須項目としてrealmを必ず
指定しなければいけないのでです。それだとユーザ名とパスワードの認証情報
に対応しないので必ずエラーになってしまいます。

ベーシック認証としては「Zend_Auth_Adapter_Http_Resolver_File」のクラスが
当てはまるのでしょうね。このクラスに認証に必要なファイルをセットする。
Zendの認証用のAdapterを生成して、このクラスに実際の処理をさせていく感じですかね。

        $config = array(
            'accept_schemes'  => 'basic',      // basic認証
            'realm'           => 'aaaaa',      // realm(ベーシック認証のフォームに出力されます)
            'digest_domains'  => '/login',     // どのURL以下にベーシック認証をかけるかです。
            'nonce_timeout'   => 3600
        );

        $resolver = new Zend_Auth_Adapter_Http_Resolver_File();
        $resolver->setFile('passwd.txt');

        $adapter  = new Zend_Auth_Adapter_Http($config);
        $adapter->setBasicResolver($resolver)
                ->setRequest($this->getRequest())
                ->setResponse($this->getResponse());

        $result = $adapter->authenticate();
        if (!$result->isValid()) {
            // 認証エラーの場合
        }

passwd.txtは、ドキュメントルート(index.phpがあるところ)からのパスになります。
内容はこんな感じです

test:aaaaa:hogehoge
ユーザ名:realm:パスワード

realmはプログラム内で指定したrealmと一致している必要があります。

前回書いたものよりだいぶスマートに実装されていますね。感心感心です。
ちょっとわがままいうなら認証機構をもっと昔のにも親和性高くしてほしかったなと思います。

まぁでも勉強になったのでよしとします。

No Comments »

ZendFrameworkでベーシック認証を試みる 自作編

わけって、アプリ側(ZendFramework)でもベーシック認証できないかということで調べてみたらありました。

流れとしては、

1. 認証を行う対象のコントローラがリクエストされたら、認証用のリクエストを送信する
2. パスワードファイルは指定されたディレクトリから情報読み込み、そこから認証のチェックを行う
3. 認証できれば当該処理を終了させる
4. 認証できなければ、401にする

今回はプラグイン側で実行することにします。

/**
 * My_Controller_Plugin_HttpBasicAuth
 *
 */
class My_Controller_Plugin_HttpBasicAuth extends  Zend_Controller_Plugin_Abstract
{

    /**
     * Basic認証
     *
     * @param Zend_Controller_Request_Abstract $request
     */
    public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request)
    {
        // init
        $server         = $this->getRequest()->getServer();
        $htpasswdFile   = "/home/html/public_html/.htpasswd";

        // 処理系のアクションか?
        if (file_exists($htpasswdFile) && is_file($htpasswdFile)) {
            // init
            $response = $this->getResponse();
            $request  = $this->getRequest();

            // htpasswdから情報取得
            $htpasswds = file($htpasswdFile);

            // headerから情報取得
            $authHeader = $request->getHeader('Authorization');
            // 認証情報解析
            $cryptPass = '';
            $cryptUser = '';
            if (preg_match('/Basic (.+)/', $authHeader, $matches)) {
                $base64     = base64_decode($matches[1]);
                $userInfo   = explode(':', $base64);
                $cryptUser  = $userInfo[0];

                // パスワード情報があるまでチェックする
                foreach ($htpasswds as $line) {
                    if (empty($line)) {
                        continue;
                    }
                    $htpasswd  = My_Util::trimAll(explode(':', $line));
                    $username  = array_get($htpasswd, 0);
                    $password  = array_get($htpasswd, 1);

                    // 送信されたパスワード
                    $cryptPass  = crypt($userInfo[1], substr($password, 0, 2));

                    // 値は等しいければ終了
                    if ($password == $cryptPass && $username == $cryptUser ) {
                        return;
                    }
                }
            }

            // 認証リクエスト送信
            $response->setRawHeader('HTTP/1.1 401 Authorization Required');
            $response->setRawHeader('WWW-Authenticate: Basic realm="My User"');

            // 認証画面設定
            $response->clearBody();
            $request->setControllerName('error')
                    ->setActionName('authrequired')
                    ->setDispatched(false);
        }
    }
}

最後にapp.iniにプラグインを有効化して終了。

resources.frontController.plugins.HttpBasicAuth.class = "My_Controller_Plugin_HttpBasicAuth"

ベーシック認証の仕組みを理解してれば、容易くいけるものですね。

base64でデコードしてあげればいいだけですもの。

No Comments »