php

Phalconのバージョン確認方法

PHPのフレームワーク「Phalcon」のバージョン確認方法をメモ。

サーバーで以下のコマンド実行で確認できます。

php -r "echo Phalcon\Version::get();"

Phalcon5は以下のコマンドで確認できます。

php -r "echo (new Phalcon\Support\Version())->get();"

※Phalcon5のVersion Componentのマニュアル
https://docs.phalcon.io/5.0/ja-jp/support-version

【Phalcon】Validator\Fileのエラー strtr(): The second argument is not an array

PHPのフレームワーク「Phalcon」で画像のバリデーションをしようとしたところエラーが発生したのでメモ。

エラーメッセージ
FastCGI sent in stderr: "PHP message: PHP Warning: strtr(): The second argument is not an array in {filepath}

環境

  • PHP 7.1.33
  • Phalcon 3.2.2

原因

Phalconのバグのようです。
2017年9月頃に修正が終わっているようなので、それ以降の3.2.x系のphalconだと大丈夫みたいです。
https://github.com/phalcon/cphalcon/issues/12947

今回は2017年9月以前のPhalcon3.2.2を使用していたため、エラーが発生。
コードは以下のようにしていました。

Formクラス

・・・
use Phalcon\Forms\Form;
use Phalcon\Forms\Element\File;
use Phalcon\Validation\Validator\File as FileValidator;

class xxxx extends Form
{
	$imageFile = new File('image_file');
	$imageFile->setLabel('画像');
	$imageFile->addValidators(array(
		new FileValidator(array(
			'allowEmpty' => true,
			'maxSize' => '2M',
			'messageSize' => ':field exceeds the max filesize (:max)',
			'allowedTypes' => array('image/jpeg', 'image/png'),
			'messageType' => 'Allowed file types are :types',
			'maxResolution' => '800x600',
			'messageMaxResolution' => 'Max resolution of :field is :max'
		))
	));
	$this->add($imageFile);
}

allowEmpty=trueで空を許可したので、画像を入力しなかった場合はエラーになりません。
画像を入力したときのみエラーになります。

allowEmpty=falseの場合は、画像未入力でもエラーになります。

対応策

Phalcon\Validation\Validator\File は使えないので、カスタムバリデーション等で対応。

いったん、バージョンアップするまでこんな感じでカスタムバリデーションを作成して暫定対応しました。

複数画像対応とか制約とか足りない部分もありますが、ベースとしてはこんな感じ。

カスタムバリデーション

namespace App\xxx\Validation\Validator;
 
use Phalcon\Validation;
use Phalcon\Validation\Message;
use Phalcon\Validation\Validator;
 
/**
 * Fileのバリデーション
 *
 * Phalcon\Validation\Validator\Fileがバグでうまく動作しないのでカスタムで作成(バグ:phalcon3.2.xの最新で改善するよう)
 */
class File extends Validator
{
    /**
     * バリデーションの実行
     * 
     *     use App\xxx\Validation\Validator\File as FileValidator;
     * 
     *     new FileValidator(
     *         [
     *             "maxSize"              => 3072, // キロバイトで指定
     *             "messageSize"          => "field exceeds the max filesize ",
     *             "allowedTypes"         => [
     *                 "image/jpeg",
     *                 "image/png",
     *             ],
     *             "messageType"          => "Allowed file types are types",
     *         ]
     *     )
     *
     * @param Validation $validator
     * @param string     $attribute
     * @return boolean
     */
    public function validate(Validation $validator, $attribute)
    {
        $request = $validator->getDI()->get('request');
        if (!$request->hasFiles(true)) return true;
 
        $file = $this->getTargetFile($attribute, $request->getUploadedFiles(true));
        if (!$file) return true;
        
        $maxSize = $this->getOption('maxSize');
        if (!is_null($maxSize)) {
            if ($file->getSize() > $maxSize * 1024) {
                $message = new Message($this->getOption('messageSize'), $attribute, 'maxSizeFile');
                $validator->appendMessage($message);
                return false;
            }
        }
 
        $allowedTypes = $this->getOption('allowedTypes');
        if (!is_null($allowedTypes)) {
            if (!in_array($file->getRealType(), $allowedTypes)) {
                $message = new Message($this->getOption('messageType'), $attribute, 'allowedTypesFile');
                $validator->appendMessage($message);
                return false;
            }
        }
        return true;
    }
 
    /**
     * リクエストからバリデーション対象ファイルを取得
     *
     * @param array $attribute key
     * @param array $files $request->getUploadedFiles()
     * @return Phalcon\Http\Request\File | null
     */
    public function getTargetFile($attribute, $files)
    {
        foreach ($files as $file) {
            if ($attribute === $file->getKey()) {
                return $file;
            }
        }
        return null;
    }
}

【PHP】クラス定数の文字列連結

phpのクラス定数で文字列連結ができるのは、PHPのバージョンが5.6.0以降になります。

phpのクラス定数の基本的な使い方

<?php
class MyClass
{
    const CONSTANT = 'constant value';

    function showConstant() {
        echo  self::CONSTANT . "\n";
    }
}

echo MyClass::CONSTANT . "\n";

$class = new MyClass();
$class->showConstant();

php5.3.0以降で使用可能なクラス定数

変数を用いてクラスを参照することが可能になりました。
ヒアドキュメントや Nowdoc を用いた定数の初期化も使用できるようになりました。

<?php
class MyClass
{
    const CONSTANT = 'constant value';

    function showConstant() {
        echo  self::CONSTANT . "\n";
    }
}

// 変数を用いてクラスを参照
$classname = "MyClass";
echo $classname::CONSTANT . "\n"; // PHP 5.3.0 以降で対応

// 変数を用いてクラスを参照
$class = new MyClass();
echo $class::CONSTANT."\n"; // PHP 5.3.0 以降で対応


class foo {
    // PHP 5.3.0 以降で対応(Nowdoc)
    const BAR = <<<'EOT'
bar
EOT;
    // PHP 5.3.0 以降で対応(ヒアドキュメント)
    const BAZ = <<<EOT
baz
EOT;
}

php5.6.0以降で使用可能なクラス定数

数値リテラルや文字列リテラルそして定数を含むスカラー式を指定できるようになりました。

const ONE = 1;

class foo {
    // PHP 5.6.0 以降
    const TWO = ONE * 2;
    const THREE = ONE + self::TWO;
    const SENTENCE = 'The value of THREE is '.self::THREE;
}

Phalconチュートリアル実装2(PHP Framework)

Phalconのマニュアルにあるチュートリアルを実装し、INVOという名のWebサイトが表示されるところまで行います。
INVOというのは、Phalcon側で作成したサンプルWebサイトです。
Phalconのインストールは以下の内容で済んでいる前提です。

Phalconインストール(CentOS7.2 + PHP5.4)
または
Phalconインストール(CentOS7.2 + PHP7.0)

Phalconのサンプルソース取得

以下のマニュアルを参考にチュートリアルのソースを取得し、「Hello!」を表示します。
https://docs.phalconphp.com/ja/latest/reference/tutorial-invo.html

今回は、「/var/www/html/」配下にサンプルソースを配置します。
git cloneすることで、html下にinvoフォルダが作成されます。

$ cd /var/www/html/
$ git clone https://github.com/phalcon/invo.git

cloneしてソースを取得したら、gitは不要かと思いますので、削除してしまってよいです。

$ rm -rf /var/www/html/invo/.git/

Nginxの設定

以下のマニュアルを参考にnginx.confまたは、conf.d配下のconfファイルにnginxの設定を行います。
https://docs.phalconphp.com/ja/latest/reference/nginx.html

今回は、マニュアルの「$_SERVER['REQUEST_URI'] をURIsとする場合」の設定を使用します。
プロジェクトフォルダは「/var/www/html/invo/」です。
rootに設定するディレクトリは「/var/www/html/invo/public」ですので、ご注意を!

server {
    listen      80;
    server_name localhost;
    root        /var/www/html/invo/public;
    index       index.php index.html index.htm;

    location / {
        try_files $uri $uri/ /index.php;
    }

    location ~ \.php$ {
        try_files     $uri =404;

        fastcgi_pass  127.0.0.1:9000;
        fastcgi_index /index.php;

        include fastcgi_params;
        fastcgi_split_path_info       ^(.+\.php)(/.+)$;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

    location ~ /\.ht {
        deny all;
    }
}

設定が完了したら、Nginxを再起動します。

CentOS7の場合

$ /bin/systemctl restart nginx

以上で完了です。
ブラウザでアクセスすると、INVOというWebサイトが表示されると思います。

もし、表示されない場合は以下の対応で直るかもしれません。

画面が表示されない場合の対応

Voltのエラー

もし、以下のようなエラーが画面に表示されたら、cache/volt/への書き込みが行えないためにエラーになっています。

Volt directory can't be written
#0 [internal function]: Phalcon\Mvc\View\Engine\Volt\Compiler->compileFile('/web/dev/ttonos...', '/web/dev/ttonos...', false)
#1 [internal function]: Phalcon\Mvc\View\Engine\Volt\Compiler->compile('/web/dev/ttonos...')
#2 [internal function]: Phalcon\Mvc\View\Engine\Volt->render('/web/dev/ttonos...', NULL, true)
#3 [internal function]: Phalcon\Mvc\View->_engineRender(Array, 'index/index', true, true, NULL)
#4 [internal function]: Phalcon\Mvc\View->render('index', 'index', Array)
#5 /web/dev/ttonosaki/iot/public/index.php(32): Phalcon\Mvc\Application->handle()
#6 {main}

cache/voltフォルダへの書き込み権限を与えてください。
手っ取り早くやるには、フォルダ権限を777にすると解決します。(セキュリティ的に微妙そうですが・・・)

$ chmod 777 /var/www/html/invo/cache/volt

デザイン(css)が適用されない

baseUriの設定が合っていない可能性があります。
以下のように修正すると直るかもしれません。

修正ファイル:/var/www/html/invo/app/config/config.ini

baseUri        = /invo/
↓
baseUri        = /

以上です。
お疲れさまでした。

Phalconインストール(CentOS7.2 + PHP7.0)

Phalconについて

Phalconはphpのフレームワークです。
Phalconは最適化された高速なフレームワークで、C拡張として実装されています。
C拡張として実装されているので、かなり高速なようです。

Phalconインストール

前提

以下の環境でPhalconをインストールします。

  • ConoHa(クラウドサービス)
  • CentOS7.2
  • PHP7.0(php-fpm)
  • Nginx1.6

以下インストールのコマンドはrootユーザで実行するのを前提にしています。
必要に応じてsudoでコマンド実行してください。

Phalconのバージョンは、2.1.0です。
※2016年5月にインストールを実行した際のバージョン

php7でPhalconをインストールするのにだいぶ苦戦しました。。。

Nginxインストール

WebサーバとしてNginxを使用します。
以下コマンドでインストール

$ yum -y install nginx

PHP7インストール

Nginxではphp-fpmを使用するので、php-fpmをインストールします。
php7をrpmを取得し、インストールします

php7のrpmを取得し、実行

$ yum -y install epel-release
//rmpを取得する場所をどこでもいいですが、今回はrootディレクトリにします。
$ cd ~
$ wget http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
$ rpm -ivh ./remi-release-7.rpm

php-fpmインストール(必要な他のphpパッケージもインストール)

$ yum install --enablerepo=remi,remi-php70 php-fpm php-devel php-mbstring php-pdo php-gd php-xml

以下でphp-fpmのバージョンを確認できます。

$ php-fpm -v

gitインストール

Phalconをインストールするのに、gitが必要なのでインストールします。

$ yum -y install git

Phalconインストール

以下の公式ブログを参考にインストールします。
https://blog.phalconphp.com/post/phalcon-2-1-0-RC1-released

必要なパッケージをインストール

$ yum install php-devel pcre-devel gcc make re2c

zephirインストール

php7に対応したPhalconをインストールするのに、zephirを使用します。
zephirはphpを拡張するためのphpエクステンションを生成する開発言語です。

gitからソースを持って来てインストールします。
今回は、gitから持ってくるソースを「/var/www/html/」下にします。

$ cd /var/www/html/
$ git clone https://github.com/phalcon/zephir
$ cd zephir/
$ ./install-nosudo

以下のコマンドを実行し、「zephir」と表示されれば、インストールOKです。

$ zephir

 _____              __    _
/__  /  ___  ____  / /_  (_)____
  / /  / _ \/ __ \/ __ \/ / ___/
 / /__/  __/ /_/ / / / / / /
/____/\___/ .___/_/ /_/_/_/
         /_/

Zephir version 0.9.3a-dev-0abce0f671
・・・・・

コンパイル

git cloneでソースを持ってきます。
今回は「/var/www/html/」下にソースを配置します。

masterブランチはまだphp7に対応していないようでエラーになるので、2.1.xブランチを使用します。
Warning出ますがインストール完了できます。

$ cd /var/www/html
$ git clone git://github.com/phalcon/cphalcon.git
$ cd cphalcon/
$ git checkout 2.1.x
$ zephir build
・・・・・・・
Copying new kernel files...
Preparing for PHP compilation...
Preparing configuration file...
Compiling...
Installing...
Extension installed!
Add extension=phalcon.so to your php.ini
Don't forget to restart your web server

拡張モジュール追加

phalconの拡張モジュールをphpに追加します。
「/etc/php.d/」以下に「extension=phalcon.so」を記述して、読み込む設定をします。
今回は「/etc/php.d/」以下にphalcon.iniというファイルを作成してます。

$ vi /etc/php.d/phalcon.ini
//以下を記述
extension=phalcon.so

上記でインストール完了です。
既にphp-fpmを起動済みでしたら、php-fpmの再起動が必要なので再起動してください。

/bin/systemctl restart php-fpm

Phalconインストールの確認

Phalconがインストールされているか確認します。
以下のマニュアルを参考に確認できます。
https://docs.phalconphp.com/ja/latest/reference/tutorial.html#id2

Nginx、php-fpmを起動していなければ起動してください。

$ /bin/systemctl start php-fpm
$ /bin/systemctl start nginx

get_loaded_extensions()を表示するか、phpinfo()を表示して、PhalconがあればOKです。

<?php print_r(get_loaded_extensions()); ?>

or

<?php echo phpinfo(); ?>

get_loaded_extensions()の場合は、以下のように「phalcon」という記載があればOKです。

Array
(
    [0] => Core
    [1] => libxml
    [2] => filter
    [3] => SPL
    [4] => standard
    [5] => phalcon
    [6] => pdo_mysql
)

phpinfo()の場合は、以下のようなPhalconのセクションがあればOKです。
[peg-image src="https://lh3.googleusercontent.com/-3lyvg16zJUM/V0sZNgTydjI/AAAAAAAAANs/S1Hvp0njbyoH-3Wfnykl4OSkBnKJugVtgCHM/s144-o/%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AA%25E3%2583%25BC%25E3%2583%25B3%25E3%2582%25B7%25E3%2583%25A7%25E3%2583%2583%25E3%2583%2588%2B2016-05-30%2B1.30.13.png" href="https://picasaweb.google.com/107888545635181725503/Web#6290149024354956850" caption="phpinfo()のPhalconセクション" type="image" alt="phpinfo()のPhalconセクション" image_size="985x556" ]

※画面が見れない場合は、centOS7のfirewallの設定の可能性があります。firewallかiptablesの設定で、80又は443ポートが開放されていない可能性があるので確認してください。

ちなみに、firewallで80番ポートを開放する場合は以下のコマンドで可能です。

$ firewall-cmd --add-service=http --zone=public --permanent

以上で、インストールまで完了になります。
お疲れさまでした。

実際に動かしてみるのは、以下のチュートリアルを参考に!
Phalconチュートリアル実装