Pages

2010年3月31日水曜日

PHP DBの結果(西暦)から年齢を計算する

これが現時点で最もシンプルかな。。。

(int)((date('Ymd') - date('Ymd', strtotime($row['birthday']))) /
10000)

2010年3月27日土曜日

Zend_Framework SQL Server利用時 Zend_Paginatorの不具合

現在の Zend Framework1.10.0 では SQL Server を利用時Zend_Paginatorが正常に動作しない。

不具合発生条件は1ページ10件表示の場合にデータが15件等入っていた場合、2ページ目が5~10件目が表示される。

これはSQL Serverにoffsetとlimitが無いためにTOPを3重のSELECTとして実装しているから。

詳しくは DbSelect.php の147行目

$this->_select->limit($itemCountPerPage, $offset);
の後で
echo $this->_select;
すれば解る。

以下は解決策である。

今回はあまり触りたくはないがZend_Frameworkファイルの方を修正する事にした。
時間が無かったので。。。

まず「Zend\Paginator\Adapter\DbSelect.php」ファイルの147行目にある
$this->_select->limit($itemCountPerPage, $offset);
の上に
$this->_select->getAdapter()->setRowCount($this->count());
を追記する。
これによって問題の処理を行っているところに正常な判断材料となる全件数を渡す。

同じように「Zend\Paginator\Adapter\DbTableSelect.php」の 44行目にある
$this->_select->limit($itemCountPerPage, $offset);
の上に
$this->_select->getAdapter()->setRowCount($this->count());
を追記する。

次に「Zend\Db\Adapter\Mssql.php」ファイルの最後に以下メソッドを追加する。

public function getRowCount()
{
    return $this->_rowCount;
}

public function setRowCount($count)
{
    $this->_rowCount = $count;
}
これでさきほどの全件数を受け取る事ができ、取得できるようになる。
プロパティに直接でも良かったんですが、一応Zend_Frameworkらしくメソッドを用意しました。

同ファイル48行目に下記を追加
protected $_rowCount;
念のため宣言しておく。

次に同じファイルの367行目に以下を追記する。

if (!is_null($this->getRowCount()) && ($count+$offset) > $this->getRowCount())
    $count = $this->getRowCount() - $offset;
これによって問題箇所を正常な数値とする事ができる。

2010年3月20日土曜日

ZendFramework アップした画像をランダムなファイル名へ変更してアップする

現在のベストと思える方法をメモ。

やりたい事は日本ファイル名でもアップされても良いという事とアップされたものが重複する事によって上書きされないようにする事。

class Default_Form_Foo extends Zend_Form
{
    public function init()
    {
        $element = new Zend_Form_Element_File('foo');
        $element
            ->setRequired(false)
            ->setValidators(array(
                array (
                    'validator' => 'Count',
                    'breakChainOnFailure' => true,
                    'options' => array(1),
                ),
                array (
                    'validator' => 'Size',
                    'breakChainOnFailure' => true,
                    'options' => array(20000),
                ),
                array (
                    'validator' => 'IsImage',
                    'breakChainOnFailure' => true,
                    'options' => array('jpeg,jpg,png,gif'),
                ),
            );
        $this->addElement($element, 'imagefile');
     }

    public function isValid($data) {
      
        $oldname = pathinfo($this->foo->getFileName());
      
        do {
            $newname =
                date("ymdHis") . '_' .
                uniqid() . '.' .
                $oldname['extension'];
        } while (
            @file_exists (
                $this->getConfigs()
                    ->tmp
                    ->img . '/' .
                    $filename));

        $this->getElement('foo')
            ->addFilter('Rename', array(
                'target'    =>
                    $this->getConfigs()
                        ->banner
                        ->tmp_path . '/' .
                        $filename,
                'overwrite' => true,
            )
        );
      
        return parent::isValid($data);
    }
}

2010年3月19日金曜日

Zend_Form グループ化されてるようなフォームの実装方法。しかも動的

グループ化されてるようなフォームの実装方法を考えてみた。
しかも動的なものを。

場面としては、オンラインアドレス帳をイメージした。
要望としては
・複数ユーザーを同時に追加したい。
・1ユーザーに登録できる項目は増減できるようにしたい。

なんと嫌な仕様なんだ。。。
断ろう。。。

が、できなかった場合のために下記のようなものを考えました。
エラー文言もやっぱりFormを使って表示したいとなるとユーザーや項目追加はその都度ページをサブミットさせるしかないかな。。。



class Default_Form_Foo extends Zend_Form
{
    public function init()
    {
        $this->addElementPrefixPath('Default_Plugin_Validate_'   , '/plugins/Validate'  , 'validate');
        $this->addElementPrefixPath('Default_Plugin_Filter_'     , '/plugins/Filter'    , 'filter');
    }
   
    public function addSubForm($params)
    {
        $cnt1 = count($params);
        foreach ($params as $key1 => $val2) {
            unset($subForm1);
            $subForm1 = new Zend_Form_SubForm();
            foreach ($val1 as $key2 => $val2) {
                unset($subForm2);
                $subForm2 = $this->createSubForm();
                $subForm1->addSubForm($subForm2, $key2);
            }
            $this->addSubForm($subForm1, $key1);
        }
    }
   
    public function createSubForm ()
    {
        $subForm = new Zend_Form_SubForm();

        $element = new Zend_Form_Element_Text('key1');
        $subForm->addElement($element);

        $element = new Zend_Form_Element_Text('key2');
        $subForm->addElement($element);

        return $subForm;
    }
}



    public function init ()
    {
        $form = new Default_Form_Foo();
        $form->addSubForm(array(
            'element1' => array(
                'element1_1' => array(
                    'key1' => 'value1',
                    'key2' => 'value2',
                )
            )
        ));
       
    }

ZendFramework Zend_Form 以下のdescriptionで改行する方法

下記のように記述するようにすれば改行する事ができます。

$element = new Zend_Form_Element_Text('freeword');
$element
    ->setDescription('※100文字
以内')
    ->setDecorators(array(
        array('ViewHelper', array()),
        array('Description', array('tag'=>'div', 'escape' => false)),
        array('Errors', array()),
    ));
$this->addElement($element);

方法としてはdecoratorにてエスケープしないように設定した後にdescriptionに自分で改行タグを書くという事です。
でもこれによってエスケープされないので、他の所も必要であればエスケープする事を忘れずに。。。

ZendFramework 関連する他の項目をチェックする方法

オリジナルのValidateを作ってもいいけどもどうしてもその方法だと、1か所しか使用しないのに作る必要があったりとなんだかスッキリしない。
そこでZend_Validate_Callback を利用する事により、解決する事を発見。

下記のようにformファイル内で実装する。


class Default_Form_Foo extends Zend_Form
{
    public function init()
    {
        $this->addElementPrefixPath('Default_Plugin_Validate_'   , '/foo/Validate'  , 'validate');
        $this->addElementPrefixPath('Default_Plugin_Filter_'     , '/foo/Filter'    , 'filter');

        $element = new Zend_Form_Element_Radio('mode');
        $element
            ->setRequired(true)
            ->setMultiOptions(array(
                'foo1' => 'bar1',
                'foo2' => 'bar2',
            ))
            ->setFilters(array(
                'StringTrim',
            ))
            ->setValidators(array(
                array (
                    'breakChainOnFailure' => true,
                    'validator' => 'Callback',
                    'options' => array(array($this, 'targetNotEmpty'))
                ),
            ))
            ->setDecorators(array(
                array('ViewHelper', array()),
                array('Description', array('tag'=>'div')),
                array('Errors', array('class'=>'Errors')),
            ));
        $this->addElement($element);
    }

    public function targetNotEmpty($value, $context)
    {
        $newsMode = $this->getMaster()->getNewsMode('key');
        $valid = new Zend_Validate_NotEmpty();

        if ($value == $newsMode['summary']) {
            if (!$valid->isValid($context['summary'])) {
                $this->getElement('summary')->addError('未入力です。');
            }
        }
        elseif ($value == $newsMode['link_url']) {
            if (!$valid->isValid($context['link_url'])) {
                $this->getElement('link_url')->addError('未入力です。');
            }
        }
        return true;
    }
}

フォームのフィールドにファイルがある場合はMAX_FILE_SIZEは本来必須であるようだ

 下記のようにFORMでファイルをアップする場合MAX_FILE_SIZEを指定する必要があるようです。

<input name="foo" type="file" />

知らなかった。。。
正解はこうですね。。。
<input type="hidden" name="MAX_FILE_SIZE" value="2097152" />
<input name="foo" type="file" />
仕様としてはfileより前に書くというルールがあるようです。
もちろんこれはブラウザ用のためなので、この値を利用してどうこうというのはダメですけどね。。。

Zend_Form_Element_File を利用する際にハマった事Ⅱ

どうやら Zend_Form_Element_File にはまだうまく実装できていない機能が一部あるようです。

通常下記のようにしてエラー文言を日本語化できるんですが、Zend_Form_Element_Fileでは翻訳されません。。。
$translate = new Zend_Translate('ini', '/hogehoge/translate.ini', 'ja');
$form->setTranslator($translate);
なぜ。。。
調べてませんw

でも解決策は見付けました。
さらに上層で下記のようにtranslateを指定する事で解決できます。
$translate = new Zend_Translate('ini', '/hogehoge/translate.ini', 'ja');
Zend_Registry::set('Zend_Translate', $translate);

Zend_Form_Element_File を利用する際にハマった

Zend_Form_Element_File を利用する際にハマった事をメモ。

Zend_Form_Element_Text とかだと下記のようにDecoratorを指定する事が多いんだけど、その勢いで Zend_Form_Element_File もやったらハマってしまった。。。

->setDecorators(array(
    array('ViewHelper', array()),
    array('Description', array('tag'=>'div')),
    array('Errors', array('class'=>'Errors')),
));

どういう理由かまでは調べてないけど、Zend_Form_Element_File ではデコレータを取得してレンダリングするところで下記のような記述があった。

$marker = false;
foreach ($this->getDecorators() as $decorator) {
    if ($decorator instanceof Zend_Form_Decorator_Marker_File_Interface) {
        $marker = true;
    }
}

if (!$marker) {
    require_once 'Zend/Form/Element/Exception.php';
    throw new Zend_Form_Element_Exception('No file decorator found... unable to render file element');
}

つまりZend_Form_Decorator_Marker_File_Interfaceじゃないインスタンスのみの場合スローされてしまう。
ではZend_Form_Decorator_Marker_File_InterfaceのDecoratorって何なんだって事で調べてみると。

Zend_Form_Decorator_Form というのがそれにあたるようだと解った。

つまりZend_Form_Element_Fileを利用する時はZend_Form_Decorator_Formが必須となるという事。
となるとViewHelperは使わないという事を意味する。

という事で下記がサンプルとなります。

$element = new Zend_Form_Element_File('test');
$element
    ->setRequired(false)
    ->setValidators(array(
        array (
            'validator' => 'Count',
            'breakChainOnFailure' => true,
            'options' => array(1),
        ),
        array (
            'validator' => 'FilesSize',
            'breakChainOnFailure' => true,
            'options' => array(1 * 1024 * 1024),
        ),
        array (
            'validator' => 'Extension',
            'breakChainOnFailure' => true,
            'options' => array('jpg,jpeg,bmp'),
        ),
        array (
            'validator' => 'ImageSize',
            'breakChainOnFailure' => true,
            'options' => array(
                'minwidth'  => 200,
                'minheight' => 200,
                'maxwidth'  => 1000,
                'maxheight' => 1000
            ),
        )
    ))
    ->setDecorators(array(
        array('File', array()),
        array('Description', array('tag'=>'div')),
        array('Errors', array('class'=>'Errors')),
    ));
$this->addElement($element);

2010年3月18日木曜日

Xperiaの発売日が4月1日に決定!?

ドコモのスマートフォン用サイトにXperiaの発売日が4月1日と記載されていた♪


どうやら動画なんかのメディア関連はiPhoneより良いとかレビューもあったしほしいな。。。

ドコモスマートフォンサイト
http://smartphone.nttdocomo.co.jp/

2010年3月14日日曜日

The Blogger Template Designer 面白いな~

 The Blogger Template Designer というのを発見!!

ブログはずっと自分のドメインが使えるのでBloggerを利用していた。
それ以前はMTを利用していたけど、あまりにも動画重いので挫折した。。。
あれは更新する気にはとてもなれない。。。

Bloggerはテンプレートも多いし、制限はあるもののオリジナルのテンプレートも作れる。

だが、なかなか作ろうと思っても時間が取れない。。。
そこで出てきたのがこれなのかは知らないが、凄く良い♪

もっとパターンが増えてきてくれたら良いのにな~♪

http://bloggerindraft.blogspot.com/2010/03/blogger-template-designer.html

今度はトラックバックだな。。。頼みますよGoogleさん。。。

最初あれ?俺のには無いぞ。。。とか思ったけど、下記リンク先から行くと自動的に機能が追加される。

http://draft.blogger.com/

2010年3月9日火曜日

Open Eclaire 入れたらBluetoothが使えない。。。

Open Eclaireを入れて凄いサクサクでウキウキになっていたら、ショックな事が。。。

Bluetoothが使えない。。。

せっかくヘッドセット買ったのに。。。仕方ない。。。Eclaire_2.1に戻すか。。。

2010年3月7日日曜日

Ver1.6に戻してみたけど。。。

最近2.1(Eclaire2.1)だから無線LANがおかしいのかと思って1.6(SuperD)に戻してみたけど、直らなかった。。。

また2.1に戻すのも面倒なので、そのまま使っていたんだけど、やっぱり2.1に戻す事にした。

理由は
1.複数のアカウントをGmailに設定できない。
2.2.1の方が安定してる気がした。

でもVer1.6の方が早いし、色々機能もあるからいいような気もするけど慣れてくると機能よりも安定してるかが重要になってくる。。。

いいかげんAppsアカウントでマイマップ連携できたらな。。。

今回入れてみたROMはこれ

OpenEclair v1.2.2(CFS with RAM Hack)
http://androidspin.com/forum/showpost.php?p=9768&postcount=1

前に入れたEclair_2.1でも良かったんですが、ま~せっかくなので違うものを。。。
っていうかEclair_2.1のROMが前と同じ1.5までしか見付けられなかった。。。

Ver2.6があるだの無いだの。。。

2010年3月5日金曜日

PHP Zend_Dbではまりがちなパターン

$db->selet()->from('t_foobar', 'okane * 1.05');

と書いたらエラーとなる。多分。。。w

対応策としては

$db->selet()->from('t_foobar', '(okane * 1.05)');

または、

$db->selet()->from('t_foobar', new Zend_Db_Expr('okane * 1.05'));

で、対応可能です。1つ目もは今回リファレンス見て気付きました。。。

▼該当リファレンス
http://doc.unlax.com/ZendFramework-1.10.0/zend.db.select.html

PHP Zend_DbでSQL Serverを利用した時にDATETIME型の値がちゃんと取得できない。。。

Zend_Dbと言っても中身はPDOであって、PDO_MSSQLを利用する事となる。

テーブルの型にDATETIMEを利用すると、何故か下記のような変な値で取得してしまう。。。

05 16 2007 11:49AM

これはODBCを利用するとならないようで、どうやらPDO_MSSQLの問題のようです。
でもZend_DbにはPDO_ODBCのアダプタは標準では入ってはいないので、自作するか。。。
とはななかなかならないので、頑張ってこれくらい対応しようかと。。。

最初変換する関数を作ってたのですが、どうやら環境によっては「05 16 2007 11:49午前」と日本語が入ってしまう事があるようでして。。。

やっぱりDB側で何とかするしかないなって事で調べるとどうやらSQL ServerにはCONVERTという関数が用意されているようでそれを利用すれば対応可能でした。
毎回SQL文がうっとうしいですが。。。

$stmt = $db->query("SELECT *,CONVERT(VARCHAR , ins_date ,120) as ins_date FROM hogehoge");
$data = $stmt->fetch();

▼参考サイト
http://www.ilovex.co.jp/Division/SRD/archives/2007/08/convert.html

2010年3月4日木曜日

EPSファイルからJPEGファイルへ変換する方法

ちょっとEPSファイルからJPEGファイルへLINUXサーバー上で変換する方法を探していたのをメモ

PHPから行いたかったがそんな関数はもちろん無いと思うので、何かアプリを入れてコマンドから対応する方向で調査した。

結局辿りついたのは「Ghostscript」というもの

Ghostscript
http://ja.wikipedia.org/wiki/Ghostscript

ライセンスはGPLみたい。
ライセンスGPL。。。よく解らんがGPLは良く見るのでOKだ。。。ろう。。。
毎回このライセンスについて調べるけど明確な回答がなかなか出ない。。。

使い方は下記のようにgsというコマンドで行うようですね。
gs -sDEVICE=jpeg -dJPEGQ=100 -dNOPAUSE -dBATCH -dSAFER -r300 -sOutputFile=myfile.jpg myfile.eps

参考サイト
http://fourforces.wordpress.com/2008/03/27/covert-eps-files-to-jpg-in-linux/ 

あと、ImageMagickからも可能なようだけど結局Ghostscriptは入れる必要があるらしいので一緒ですね。。。

無線LANへの接続がおかしい。。。

現在E-MOBILEのPocketWifiで接続してるんですが、何かおかしいです。。。
使ってる時からちょっとづつ気になっていたんですが、やっぱりおかしい。。。

症状が明確ではないんですが、結果的にはWifiの接続が切れているという事です。

デフォルトの無線LAN設定は画面の電源が切れたタイミングで切断されるようになっています。

でもこれだと画面が消えている状態ではメールを受け取ってくれないという事になります。
(3Gに契約していない場合)
なので、画面電源をOFFにした時でも無線LANは切断しないように設定します。

設定方法は前にも書きましたが、アクセスポイント一覧の画面からMENUボタンをクリックして出てくる詳細設定から行えます。

しかしここからが問題。。。

どうもAndoroidはLANでの接続はできているけど通信のレスポンスが得られない場合、もちろんリトライしますが、そのリトライで何回も失敗するとバグってしまうようです。。。

これは自分のOSがカスタムROMなので、そのせいなのかもしれませんが。。。

PocketWifiは画面に現在接続されている端末数が表示されるのですが、そこでは0件なのに携帯のWifiアンテナはMAX。。。。
状態を確認しても接続中ステータスで表示される。。。
もちろん通信はできないのでブラウザ等はタイムアウト。。。

他のパターンとしては画面から復帰してもなかなか接続しない。。。
で、アクセスポイント一覧でステータスを確認すると接続しっぱい。。。
クリックしないとリトライしませんよ!みたいなメッセージが。。。なぜ。。。頑張れよ。。。

とりあえず1.6に戻した方がよさそうですね。。。SuperDにしよ~

改善策は無いですが、結局常時無線LAN接続するに設定してもPocketWifiだとダメという事です。。。

 SuperD(Andorid1.6)にしても同じ症状でした。。。
ダメダメですね。。。

2010年3月2日火曜日

PHP MDB2でSELECTクエリをループさせるとメモリーがどんどん増えていく。。。

$options = array(
    'debug' => 2,
    'portability'   =>  MDB2_PORTABILITY_EMPTY_TO_NULL,
);

$mdb2 = MDB2::factory($db_dns, $options);

$sql = <<<__EOS
    SELECT
        COUNT(*)
    FROM
        ta_poi
    WHERE
        poi_id > 0
__EOS;

$result = $mdb2->query($sql);
if ( PEAR::isError($sth) )
    throw new Exception($sth->getMessage() . "\n" . $sth->getUserInfo());

$hogehoge = $result->fetchOne();
$result->free();

上記の場合どんどん消費メモリーが増えていくんです。。。
どうもvar_dump($mdb)でDBオブジェクトを確認してみるとコネクトしてからのSQL文が貯まっていっているようなので、そこが原因かなとdebugを0に変更してみる。

が、ダメ。。。
もっと何か貯めているのかなと思って下記リファレンスを見てみるとresult_bufferingという設定値があるではないか!!
早速falseで指定してみると無事治りましたとさ♪

▼リファレンス
http://pear.php.net/manual/ja/package.database.mdb2.intro-connect.php


▼修正後
$options = array(
    'debug' => 0,
    'portability'   =>  MDB2_PORTABILITY_EMPTY_TO_NULL,
    'result_buffering' => false,
);

問題は、result_bufferingをfalseにした場合の影響だな。。。
どうやらデフォルトではtrueなようなので。。。

Followers