@blog.justoneplanet.info

JavaScript、PHP、MySQLを使ったり

Windows XPでPHPとimageMagickを使用する

■ImageMagick

以下のサイトからWindows版をダウンロードしてインストールする。

http://www.imagemagick.org/script/binary-releases.php?ImageMagick=pjjjn3udinf3ldej2osq7k8nj1#windows

Program Files配下などのスペースを含むパスにインストールせず、cドライブ直下が望ましいらしい。

環境変数

設定>コントロールパネル>システム>詳細設定>環境変数>システム環境変数

変数名はMAGICK_HOMEとし値はインストールしたパスを入力する。

■Microsoft Visual C++ 2005 SP1

以下のサイトからインストール

http://www.microsoft.com/downloads/details.aspx?familyid=200B2FD9-AE1A-4A14-984D-389C36F85647&displaylang=ja

■php_imagick

以下のサイトからインストールする。

http://www.sk89q.com/2010/03/vc6-windows-binaries-for-imagick-2-3-0/

リンクが切れている場合はここ

上手くいかない場合は以下のサイトのdllを使用した方が良いかもしれない。

http://valokuva.org/?page_id=50

extension_dir = "C:\xampp\php\ext"

php.iniが上述のような場合は「C:\xampp\php\ext」にファイルを配置する。

php.ini

以下の設定を追加(パスは環境に合わせて変更してください)

extension=php_imagick.dll

Windowsを再起動すると使用可能になる。

PHPとGDでテキスト量に合わせたサイズの画像を生成する

GDは意外にもやってくれる!

■ソースコード

以下のように、imagettfbbox関数によってテキストボックスのサイズが取得可能である。

<?php
$text     = 'Open the door!';// string
$fontSize = 30;
$font     = '/usr/share/fonts/bitstream-vera/ACaslonPro-Bold.otf';// path

$box    = imagettfbbox($fontSize, 0, $font, $text);
$img    = imagecreatetruecolor($box[2] - $box[6] + 10, $box[3] - $box[7] + 10);
$color  = imagecolorallocatealpha($img, 210, 0, 0, 255);
$backgroundColor = imagecolorallocatealpha($img, 255, 255, 255, 127);
imagealphablending($img, true);
imagesavealpha($img, true);

imagefill($img, 0, 0, $backgroundColor);
imagettftext($img, 30, 0, 0, $box[3] - $box[7], $color, $font, $text);

header('Content-type: image/png');
imagepng($img);
imagedestroy($img);
?>

■画像

こんな感じのができる!

font

PHPとImageMagickでテキスト量に合わせたサイズの画像を生成する

■ソースコード

以下のように記述する。

<?php
$text            = "にこにこぷん";//utf-8
$color           = 'black';
$backgroundColor = 'transparent';

$im    = new Imagick();
$idraw = new ImagickDraw();
$idraw->setFont('/usr/share/fonts/bitstream-vera/A-OTF-ShinMGoPro-DeBold.otf');// font
$idraw->setFontSize(30);// font size
$idraw->setGravity(Imagick::GRAVITY_CENTER);// gravity
$idraw->setFillColor($color);// 文字色塗り
$idraw->setStrokeColor($color);// 文字色輪郭
$idraw->annotation(0, 0, $text);
$metrics = $im->queryFontMetrics($idraw, $text);//get the size of string

$im->newImage($metrics['textWidth'], $metrics['textHeight'], $backgroundColor);
$im->drawImage($idraw);
$im->setImageFormat('png');
header('Content-Type: image/png');
echo $im;
$im->destroy();
$idraw->destroy();
?>

14行目でサイズを取得し、16行目でイメージのサイズとして使用する。

■画像

こんな感じのができる!

Zend_Validateをつかってみる

■使用方法

以下のようにしてバリデートする。

$validator = Zend_Validate_EmailAddress();
if($validator->isValid($str)){
    //success
}
else{//falure
    $this->view->error = $validator->getMessages();//array
}

エラーメッセージの変更

以下のようにするとエラーメッセージを変更することができる。

$validator = new Zend_Validate_StringLength(8);
$validator->setMessage(
    'コラァ=3',
    Zend_Validate_StringLength::TOO_SHORT
);
if($validator->isValid($str)){
    //success
}
else{
    $this->view->error = $validator->getMessages();//array
}

以下のように数パターンエラーメッセージを指定することも考えられる。

$validator = new Zend_Validate_StringLength(array(
    'min' => 2,
    'max' => 10
));
$validator->setMessage(
    Zend_Validate_StringLength::TOO_SHORT => 'コラァ=3',
    Zend_Validate_StringLength::TOO_LONG => 'ゴルァ=3'
);
if($validator->isValid($str)){
    //success
}
else{
    $this->view->error = $validator->getMessages();//array
}

■静的に扱う

以下のようにZend_Validateクラスの静的メソッドを用いてバリデートすることもできる。

if(Zend_Validate::is($str, 'EmailAddress')){
    //success
}
if(Zend_Validate::is($str, 'StringLength', array('min' => 10, 'max' => 20))){
    //success
}

■多言語対応

デフォルトのメッセージはベタ&英語なのでパンチの利いたセリフが必要だ。

$validator = new Zend_Validate_EmailAddress();
$validator->setTranslator(new Zend_Translate(
    'array',
    array(
        Zend_Validate_Hostname::UNKNOWN_TLD => 'そんなトップレベルドメインしらねーぜぃ'
    ),
    'en'
));
if($validator->isValid()){
    //success
}
else{
    //failure
}

以下のようにして一度に適用できる。

Zend_Validate::setDefaultTranslator(new Zend_Translate(
    'array',
    array(
        Zend_Validate_Hostname::UNKNOWN_TLD => 'そんなトップレベルドメインしらねーぜぃ'
    ),
    'en'
));

バリデートのクラスはすごくいっぱい。

http://framework.zend.com/manual/ja/zend.validate.set.html

■バリデータチェーン

以下のようにして1つのインスタンスに複数のルールを付加できる。

$validator = new Zend_Validate();
$validator->addValidator(new Zend_Validate_Alnum());
$validator->addValidator(new Zend_Validate_StringLength(array(
    'min' => 10,
    'max' => 20
)));

■自作バリデータ

めんどくさいけど作ってみる。以下のようにZend_Validate_Abstractを継承して自作バリデータを作ることができる。

class MyValidate_Array extends Zend_Validate_Abstract
{
    const ARRAY = 'array';
    protected $_messageTemplates = array(
        self::ARRAY = "'%value'は配列を入れてね!"
    );
    public function isValid($value)
    {
        if(!is_array($value)){
            $this->_error(self::ARRAY);
            return false;
        }
        else{
            return true;
        }
    }
}

Zend_Layoutを触ってみる

■フロントコントローラ

大枠(レイアウト部分)が置いてあるディレクトリのパスはここで指定してもよいと思う。

/public_html/index.php

Zend_Layout::startMvc(array(
    'layout'     => 'layout',// layout.phtml
    'layoutPath' => '../application/modules/admin/views/layouts/'// path
));
$front = Zend_Controller_Front::getInstance();

■コントローラ

まぁ大体一つのコントローラ内でレイアウトが変わるなんて事はないから、initで設定してイイよね。

    /**
     * init
     * @return void
     */
    public function init()
    {
        $this->_helper->layout->setLayout('layout');// layout.phtml
        //$this->_helper->layout->setLayoutPath('../application');// path
        $this->_helper->layout->assign('menu', $this->view->render('menu.phtml'));
    }

こんな感じにしておけば、以下の様な感じでイケる!

■ビュー

/application/modules/admin/views/scripts/index/index.phtmlの部分は$this->layout()->contentに出力される。

/application/modules/admin/views/layouts/layout.phtml

<div id="sidebar">
<?php echo $this->layout()->menu ?>
</div>
<div id="main">
<?php echo $this->layout()->content ?>
</div>

■その他の設定

    /**
     * init
     * @return void
     */
    public function init()
    {
        $this->_helper->layout->setLayout('layout');// layout.phtml
        $this->_helper->layout->assign('menu', $this->view->render('menu.phtml'));
        $this->_helper->layout->disableLayout();// レイアウトを無効化できる
        $this->_helper->layout->setContentKey('main');// デフォルト名$this->layout()->contentを$this->layout()->mainに変更できる
    }

Zend_Formをもっと触ってみる

特定の要素をグルーピングしたい時だってある。

<?php
class Admin_IndexController extends Zend_Controller_Action
{
    public function indexAction()
    {
        $this->view->form = $this->_createForm();
    }
    public function registerAction()
    {
        $form = $this->createForm();
        if(!form->isValid($this->_getAllParams())){// error
            $this->view->assign('form', $form);
            return $this->render('index');
        }
        else{// success
            $this->_dbh->register($form->getValues());
        }
    }
    private function _createForm()
    {
        $form = new Zend_Form();
        $form->setAction('/admin/index/register/')->setMethod('post');
        $form->addElement(
            'text',
            'name',
            array(
                'validators' => array(
                    array('Regex', false, array('/^[a-z]/i'))
                ),
                'label'      => 'Name : ',
                'required'   => true
            )
        );
        $form->addElement(
            'password',
            'pass',
            array(
                'validators' => array(
                    'Alnum'
                ),
                'label'      => 'Password : ',
                'required'   => true
            )
        );
        $form->addDisplayGroup(
            array(
                'name',
                'pass'
            ),
            'login',
            array(
                'disableLoadDefaultDecorators' => false
            )
        );
        $form->addElement('hash', 'checkHash');
        $form->addElement('submit', '送信');
        return $form;
    }
}
?>

上述のようにしてグループ毎にfieldsetで括ることができる。addDisplayGroupは要素を定義した直後にコールしないとフォームの要素の順序が変わってしまうので注意が必要である。

出力html

<form enctype="application/x-www-form-urlencoded" action="" method="post">
<dl class="zend_form">
<dt id="login-label">&nbsp;</dt>
<dd id="login-element"><fieldset id="fieldset-login">
<dl>
<dt id="name-label"><label for="name" class="required">Name :</label></dt>
<dd id="name-element"><input type="text" name="name" id="name" value=""></dd>
<dt id="pass-label"><label for="pass" class="required">Password :</label></dt>
<dd id="pass-element"><input type="password" name="pass" id="pass" value=""></dd>
</dl>
</fieldset></dd>
<dt id="checkHash-label">&nbsp;</dt>
<dd id="checkHash-element"><input type="hidden" name="checkHash" value="c15806d5c0f9bc7f6b414ba2cf40468d" id="checkHash"></dd>
<dt id="送信-label">&nbsp;</dt>
<dd id="送信-element"><input type="submit" name="送信" id="送信" value="送信"></dd>
</dl>
</form>

なかなか構造化された綺麗なHTMLが出力される!

Zend_Form::addElement(string $type, string $name, array $options);
第一引数でtype属性を指定、第二引数でname属性、第三引数でバリデータやフィルタのオプション設定をする
Zend_Form::addDisplayGroup(array $elementNames, string $fieldsetName, array options);
第一引数で要素のname属性を配列で指定、第二引数でfieldsetの任意の名前、第三引数でオプション設定をする

■フォームのデコレータ

勝手にタグがついて全体をfieldsetで括ってくれて便利なんだが余計なお世話になるときだってある。そこでデフォルトでフォームに付加されるHTMLタグを変更する。

<?php
class Admin_IndexController extends Zend_Controller_Action
{
    public function indexAction()
    {
        $this->view->form = $this->_createForm();
    }
    public function registerAction()
    {
        $form = $this->createForm();
        if(!form->isValid($this->_getAllParams())){// error
            $this->view->assign('form', $form);
            return $this->render('index');
        }
        else{// success
            $this->_dbh->register($form->getValues());
        }
    }
    private function _createForm()
    {
        $form = new Zend_Form();
        $form->setAction('/admin/index/register/')->setMethod('post');
        $form->addElement(
            'text',
            'name',
            array(
                'validators' => array(
                    array('Regex', false, array('/^[a-z]/i'))
                ),
                'label'      => 'Name : ',
                'required'   => true
            )
        );
        $form->addElement(
            'password',
            'pass',
            array(
                'validators' => array(
                    'Alnum'
                ),
                'label'      => 'Password : ',
                'required'   => true
            )
        );
        $form->addElement('hash', 'checkHash');
        $form->addElement('submit', '送信');
        $form->clearDecorators();
        $form->addDecorator('FormElements')->addDecorator('HtmlTag', array('tag' => 'ul', 'class' => 'form'))->addDecorator('Form');
        $form->setElementDecorators(array('ViewHelper', 'Label', array('HtmlTag', array('tag' => 'li'))));
        return $form;
    }
}
?>

出力コード

<form enctype="application/x-www-form-urlencoded" action="" method="post">
<ul class="form">
<li><label for="name" class="required">Name :</label><input type="text" name="name" id="name" value=""></li>
<li><label for="pass" class="required">Password :</label><input type="password" name="pass" id="pass" value=""></li>
<li><input type="hidden" name="checkHash" value="f2bcb658321fb39cdc0bd92c61210f7d" id="checkHash"></li>
<li><label for="送信" class="optional">送信</label><input type="submit" name="送信" id="送信" value="送信"></li>
</ul>
</form>
Zend_Form::addDecorator(string $className, , array $options = null);
Zend_Form::addDecorators(array $decorators);

いろんなデコレータ

    private function _createForm()
    {
        $form = new Zend_Form();
        $form->setAction('/admin/index/register/')->setMethod('post');
        $form->addElement(
            'text',
            'name',
            array(
                'validators' => array(
                    array('Regex', false, array('/^[a-z]/i'))
                ),
                'label'      => 'Name : ',
                'required'   => true
            )
        );
        $form->addElement(
            'password',
            'pass',
            array(
                'validators' => array(
                    'Alnum'
                ),
                'label'      => 'Password : ',
                'required'   => true
            )
        );

        $name = $form->getElement('name');
        $name->setDescription('<span class="description">名前をいれる感じで</span>');
        $name->addDecorator(//<p>
            'description',
            array(
                'class'  => 'descrition',
                'escape' => false
            )
        );

        $form->addElement('hash', 'checkHash');
        $form->addElement('submit', '送信');
        $form->clearDecorators();
        $form->addDecorator('FormElements')->addDecorator('HtmlTag', array('tag' => 'ul', 'class' => 'form'))->addDecorator('Form');
        $form->setElementDecorators(array('ViewHelper', 'Label', array('HtmlTag', array('tag' => 'li'))));
        return $form;
    }

出力HTML

<form enctype="application/x-www-form-urlencoded" action="" method="post">
<ul class="form">
<li><label for="name" class="required">Name :</label>
<input type="text" name="name" id="name" value=""></li>
<p class="descrition_class"><span class="description">名前をいれる感じで</span></p>
<li><label for="pass" class="required">Password :</label>
<input type="password" name="pass" id="pass" value=""></li>
<li><input type="hidden" name="checkHash" value="0162b9bd58af60eb903fe52237bc6a8f" id="checkHash"></li>
<li><label for="送信" class="optional">送信</label>
<input type="submit" name="送信" id="送信" value="送信"></li>
</ul>
</form>

■自作デコレータ

以下のようにZend_Form_Decorator_Abstractを継承してあげればオリジナルデコレータができる!

../application/decorators/Original.php

<?php
class Jop_Decorator_Original extends Zend_Form_Decorator_Abstract
{
    public function render($content)
    {
         return "<span>{$content}</span>";
    }
}
?>

以下のようにして使用する。

    private function _createForm()
    {
        $form = new Zend_Form();
        $form->setAction('/admin/index/register/')->setMethod('post');
        $form->addPrefixPath('Jop_Decorator', '../application/decorators', 'decorator');
        //追加したフォーム要素に登録
        //$form->addElementPrefixPath('Jop_Decorator', 'path', 'decorator');
        $form->addElement(
            'text',
            'name',
            array(
                'validators' => array(
                    array('Regex', false, array('/^[a-z]/i'))
                ),
                'label'      => 'Name : ',
                'required'   => true
            )
        );
        $form->addElement(
            'password',
            'pass',
            array(
                'validators' => array(
                    'Alnum'
                ),
                'label'      => 'Password : ',
                'required'   => true
            )
        );

        $name = $form->getElement('name');
        //個別のフォーム要素に加える
        $name->addPrefixPath('Jop_Decorator', '../applications/decorators', 'decorator');
        $name->addDecorator('Original');

        $form->addElement('hash', 'checkHash');
        $form->addElement('submit', '送信');
        return $form;
    }

以下のようにspanで括られて出力される。

<form enctype="application/x-www-form-urlencoded" action="" method="post">
<dl class="zend_form">
<span><dt id="name-label"><label for="name" class="required">Name :</label></dt>
<dd id="name-element"><input type="text" name="name" id="name" value=""></dd></span>
<dt id="pass-label"><label for="pass" class="required">Password :</label></dt>
<dd id="pass-element"><input type="password" name="pass" id="pass" value=""></dd>
<dt id="checkHash-label">&nbsp;</dt>
<dd id="checkHash-element"><input type="hidden" name="checkHash" value="784473de7bc7e8048eff4538060bce03" id="checkHash"></dd>
<dt id="送信-label">&nbsp;</dt>
<dd id="送信-element"><input type="submit" name="送信" id="送信" value="送信"></dd>
</dl>
</form>

■エラーメッセージの日本語化

以下のようにすると対応するエラーメッセージを日本語化できる。

    private function _createForm()
    {
        $form = new Zend_Form();
        $form->setAction('/admin/index/register/')->setMethod('post');
        $form->addElement(
            'text',
            'name',
            array(
                'validators' => array(
                    array('Regex', false, array('/^[a-z]/i'))
                ),
                'label'      => 'Name : ',
                'required'   => true
            )
        );
        $form->addElement(
            'password',
            'pass',
            array(
                'validators' => array(
                    'Alnum'
                ),
                'label'      => 'Password : ',
                'required'   => true
            )
        );
        $form->addElement('hash', 'checkHash');
        $form->addElement('submit', '送信');
        $adapter = new Zend_Translate(
            'array',
            array(
                "'%value%' has not only alphabetic and digit characters" => "'%value%' に英数字以外の文字が含まれています",
                "'%value%' does not match against pattern '%pattern%'"   => "'%value%' は '%pattern%' にマッチしません。"
            )
        );
        $form->setTranslator($adapter);
        return $form;
    }

全てのフォームに適用する場合は以下のようにする。

Zend_Form::setDefaultTranslator($adapter);

Zend_Formを触ってみる

■結論

コントローラ

<?php
class Admin_IndexController extends Zend_Controller_Action
{
    public function indexAction()
    {
        $form = $this->createForm();
        $this->view->form = $form;
    }
    public function registerAction()
    {
        $form = $this->createForm();
        if(!$form->isValid($this->_getAllParams())){// error
            $this->view->assign('form', $form);
            return $this->render('index');
        }
        else{// success
            $this->_dbh->register($form->getValues());
        }
    }
    private function createForm()
    {
        $form = new Zend_Form();
        $form->addElement(
            'text',
            'name',
            array(
                'validators' => array(
                    array('Regex', false, array('/^[a-z]/i'))
                ),
                'label'      => 'Name : ',
                'required'   => true
                'filters'    => array(
                    'StringToLower',
                    'StripTags'
                )
            )
        );
        $form->addElement('hash', 'checkHash');
        $form->addElement('submit', '送信');
        return $form;
    }
}
?>

index.phtml

<?php echo $this->form; ?>

最初にZend_Formのインスタンスを作成する。

他のモジュールとの連携

  • バリデート(Zend_Validate)
  • フィルタリング(Zend_Filter)

■Zend_Form

コントローラ

$form = new Zend_Form();
$form->setAction('/admin/index/register/')->setMethod('post');
$this->view->form = $form;

ビュー

<?php echo $this->form; ?>

出力

<form enctype="application/x-www-form-urlencoded" action="/admin/index/register/" method="post">
<dl class="zend_form">
</dl>
</form>

■ 要素を作る

簡単。(コントローラ)

$name = $form->createElement('text', 'name');

addElement がもっと簡単(コントローラ)

$form->addElement('text', 'name');

バリデートもフィルタリングも一緒に追加できちゃう。(コントローラ)

$form->addElement(
    'text',
    'name',
    array(
        'validators' => array(
            array('Regex', false, array('/^[a-z]/i'))
        ),
        'label'      => 'Name : ',
        'required'   => true,
        'filters'    => array(
            'StringToLower',
            'StripTags'
        )
    )
);

こんなんもある。めんどー。(コントローラ)

require_once 'Zend/Form/Element/Text.php';
$name = new Zend_Form_Element_Text('name');

■ バリデータを作る

addValidator(mixed $nameOrValidator, bool $breakChainOnFailure, array $options)
$name = new Zend_Form_Element_Text('name');
$name->addValidator('Alnum', false, array(true))
    ->addValidator('Regex', false, array('/^[a-zA-Z\s]+/'))
    ->setLabel('Name : ')
    ->setRequired(true);
Zend_Form_Element::addValidator(string $class, bool $is_next, array $options);
第一引数で指定したバリデータを要素に付加する。

バリデータ一覧

http://framework.zend.com/manual/ja/zend.validate.set.html

■フィルターを作る

addFilter(mixed $nameOrFilter, array $options)
$name = new Zend_Form_Element_Text('name');
$name->addFilter('StringToLower');

フィルタ一覧

http://zendframework.com/manual/1.5/ja/zend.filter.set.html

Zend_Viewをもっと触ってみる

■パーシャルビュー

scripts配下から指定する。

<?php echo $this->partial('index/edit.phtml'); ?>

他のビュースクリプトを呼び出すための仕組みだ。

<?php
echo $this->partial(
    'index/edit.phtml',
    array(
        'val' => $this->val
    )
);
?>

上述のように、変数は明示的して引数で渡す必要がある。

■プレイスホルダ

コントローラ

$this->view->HeadScript()->appendFile('/admin/js/init.js');

ビュー

<?php echo $this->HeadScript(); ?>

出力

<script type="text/javascript" src="/admin/js/init.js"></script>

■Zend_Translate

その名の通り多言語サイトをつくるときに使うやつ。

Zend_Registry::set(
    'Zend_Translate',
    new Zend_Translate(
        'array',
        array(
            'submit' => '送信'
        ),
        'ja'
    )
);

ビュー

<?php echo $this->formSubmit('', $this->translate('submit')); ?>

出力

<input type="submit" name="" id="" value="送信">

なんかファイルフォーマットのアダプタがいっぱいある。

■自作ビューヘルパー

クラスを定義

application/modules/admin/views/helpers/Br.php

<?php
class Zend_View_Helper_Br
{
    //呼び出し元のZend_Viewが自動的に$viewに代入される
    public $view;
    public function setView(Zend_View_Interface $view)
    {
        $this->view = $view;
    }
    public function br()
    {
        return "<br />\n";
    }
}
?>

コントローラ

$this->view->addHelperPath('application/modules/admin/views/helpers', 'Zend_View_Helper_');

ビュー

<?php echo $this->br(); ?>

どっちかというと命名規則が重要である。

自作クラス名
Zend_View_Helper_ + Br
自作クラス名(メソッド)
br
ビュー
echo $this->br();

PHPとGDで透過png画像テキストを出力する

透明度のあるイメージをつくる。

<?php
$width  = 300;// px
$height = 40;// px
$text   = 'This is a sample.';// string
$font   = '/usr/share/fonts/bitstream-vera/ACaslonPro-Bold.otf';// path

$img             = imagecreatetruecolor($width, $height);
$color           = imagecolorallocatealpha($img, 210, 0, 0, 255);
$backgroundColor = imagecolorallocatealpha($img, 255, 255, 255, 127);
imagealphablending($img, true); // ブレンドモードを設定する
imagesavealpha($img, true); // 完全なアルファチャネルを保存する

imagefill($img, 0, 0, $backgroundColor); // 指定座標から指定色で塗る
imagettftext($img, 16, 0, 16, 40, $color, $font, $text);

header('Content-type: image/jpeg');
imagepng($img);
imagedestroy($img);
?>

すけすけ画像テキストだ!=3