日頃の行い

個人的な日頃の行いをつらつら書いてます\\\\ ٩( 'ω' )و ////

phpredisをPHP7系で触るためにやったこと

ISUCONでredis使おうと思った時にPHPからredis触ったこと無いなということに気がついたので、
触れる用にphpredisを試してみた備忘録です。
利用したPHPのversionは 7.1.10 です。

php -v
PHP 7.1.10 (cli) (built: Oct 10 2017 01:16:36) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2017 Zend Technologies

phpredisはCで書かれたPHP Extensionなのでbuildしてphp.iniに設定を追加する必要があります。

github.com

やることは、phpredisのレポジトリをcloneしてビルドし、php.iniに設定を追加するだけです。

https://github.com/phpredis/phpredis#installation

検証に利用したコードはここに置きました。

github.com

検証に利用したコードではDockerfile内で行いました。 設定が反映されているかは php -i で確認できます。

# 反映されている場合
$php -i |grep -e redis -e Redis 
Additional .ini files parsed => /usr/local/etc/php/conf.d/redis.ini
redis
Redis Support => enabled
Redis Version => develop
Registered save handlers => files user redis rediscluster
This program is free software; you can redistribute it and/or modify

# 反映されていない場合
$php -i |grep -e redis -e Redis
This program is free software; you can redistribute it and/or modify

雑に値をsetするphpコードを書いてみました。

<?php

function connect($server, $port = 6379, $db = 0): \Redis {
    $redis = new \Redis();
    $success = $redis->connect($server, $port);
    if ($success !== true) {
        throw new \Exception(spritnf('failed to connect to %s. port: %s', $server, $port));
    }
    $success = $redis->select($db);
    if ($success !== true) {
        throw new \Exception(spritnf('failed to select database %s. server: %s. port: %s', $db, $server, $port));
    }

    return $redis;
}


function main() {
    // docker-composeのlinksで追加しているのでredisとなっています。
    // アドレス入れる場合は下記のような形になります。
    // $redis = connect('127.0.0.1');
    $redis = connect('redis');
    $redis->set('xxx', 'aaa');
    $redis->set('yyy', 'bbb');
    $saved = $redis->get('yyy');
    var_dump($saved);
}

main();

実行すると var_dump の結果が出るだけですね。

$php main.php
string(3) "bbb"

redis-cliで確認すると xxx, yyy というkeyに書き込まれているのがわかります。

$redis-cli
127.0.0.1:6379> keys *
1) "yyy"
2) "xxx"

もっと色々やりたい場合はUsageが充実していたのでそっちが参考になりそうです。

https://github.com/phpredis/phpredis#usage

そんなに難しくないので使う際には使っていこうと思いました。

PHPのビルトインサーバっぽく開発しつつhttpsアクセスをしたくなったときにしたこと

最近Mockアプリケーションを作るときにAPIサーバを一旦雑に作りたくて、
phpを使っているんですが、ローカルの開発環境をhttpsにしているため、XMLHttpRequestを投げようとした際に、

Mixed Content: The page at 'https://xxx' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://yyy'. This request has been blocked; the content must be served over HTTPS.

と怒られました。
何個か方法はあると思うんですが、phpのビルトインサーバで出来ないのかなぁ
とふと思って検索したらライブラリがあったのでそれを使ってみました。
その時のメモです。

使ったライブラリはこちらです。

github.com

雑に検証したファイル群はこちらです。

gist.github.com

実際に動かしてみました。
hyper-run -S localhost:8080 -s localhost:8081 ./index.php を実行して、curlでアクセスしただけです。

$make server
./composer.phar install
Loading composer repositories with package information
Installing dependencies (including require-dev) from lock file
Nothing to install or update
Generating autoload files
./vendor/bin/hyper-run -S localhost:8080 -s localhost:8081 ./index.php
[Tue May 16 19:40:20 2017] 127.0.0.1:50957 [200]: /
[Tue May 16 19:40:27 2017] 127.0.0.1:50960 [200]: /

...
# 別ターミナル
$curl -i http://localhost:8080
HTTP/1.1 200 OK
Host: localhost:8080
Date: Tue, 16 May 2017 10:40:38 +0000
Connection: close
X-Powered-By: PHP/7.1.2
Content-type: text/html; charset=UTF-8

Hello World

$curl -i --insecure https://localhost:8081
HTTP/1.1 200 OK
Host: localhost:8081
Date: Tue, 16 May 2017 10:40:33 +0000
Connection: close
X-Powered-By: PHP/7.1.2
Content-type: text/html; charset=UTF-8

Hello World

ビルトインサーバっぽく使えて、httpsでつなげて便利でした。
nginxやapache立てるのもめんどいくらい初期のときには使っていきたい。

PHP(Laravel)製TaskRunner「Envoy」を試してみた

この記事は PHP Advent Calendar 2015 - Qiita の20日分として書かれています。
個人的な開発でLaravel製マイクロフレームワークLumenを利用しているので、デプロイ等に使えないかと思いLaravel製のTask Runner「Envoy」を試してみました。
結論から言うと私は今後多分使わないです。
※Envoyは、Bladeのシンタックスを利用してタスクを定義し、リモートサーバに対してそれらのタスクを適用させることが出来るタスクランナーです。

ドキュメント laravel.com

レポジトリ github.com

今回試した色々はこちらのレポジトリで試せます。 github.com

この後の話の流れはある程度Envoyのドキュメントにそって試していこうと思っています。

  • インストール
  • タスクとマクロの実行
  • 通知機能

1. インストール

インストールはcomposerを利用することで可能です。 ara-ta3/envoy-getting-started · GitHub では make install でおkです。

$curl -sS https://getcomposer.org/installer | php
$php composer.phar require "laravel/envoy: ~1.0"

これで /path/to/directory/vendor/bin/envoy が利用できるようになります。 そして、envoy initを実行するとテンプレートを作成することが出来ます。

$./vendor/bin/envoy init vagrant@192.168.33.10
Envoy file created!
$cat Envoy.blade.php
@servers(['web' => 'vagrant@192.168.33.10'])

@task('deploy')
    cd /path/to/site
    git pull origin master
@endtask

2. タスクとマクロの実行

ダミーサーバとしてvagrantcentosのサーバをローカルに立てています。 書いてみたタスクはこんな感じです。

  • Envoy.blade.php
@include("./vendor/autoload.php")

@servers (['vm' => 'vagrant@192.168.33.10'])

@setup
    $start = date('Y/m/d H:i:s');
@endsetup

@task ('ls', ['on' => 'vm'])
    ls -la /tmp
@endtask

@task ('touch', ['on' => 'vm'])
    touch /tmp/hoge
@endtask

@task ('fail', ['on' => 'vm'])
    test -f /tmp/fuga
    echo "failed"
@endtask

@macro ('all')
    touch
    ls
@endmacro

@macro ('all-fail')
    touch
    fail
    ls
@endmacro

@after
    echo "after" . PHP_EOL;
    echo "started: " . $start . PHP_EOL;
    echo "endted: " . date('Y/m/d H:i:s');
@endafter

簡単な文法

  • @includeはrequire_onceのエイリアス
  • @serversはデプロイ対象のサーバを設定できる
  • @taskはシェルスクリプトが書ける
  • @taskのシェルスクリプトが途中で終了コード0以外が出た場合、@taskはその終了コードで終了する。
  • @macroは@taskの名前が書ける
  • @setupはマクロまたはタスクの開始前に呼ばれ、phpのコードが書ける
  • @afterはマクロまたはタスクが終わった後に呼ばれ、phpのコードが書ける

あぁ・・・って思ったこと

@servers ([
  'vm1' => 'vagrant@192.168.33.10',
  'vm2' => 'vagrant@192.168.33.11'
])

みたいなことしたいじゃないですか。
できないです。
アノテーションはその行しか見てくれないんです。くっ・・・

  • @macroの中のタスクが異常終了しても@macroは止まらない。
@task ('ls', ['on' => 'vm'])
    ls -la /tmp
@endtask

@task ('touch', ['on' => 'vm'])
    touch /tmp/hoge
@endtask

@task ('fail', ['on' => 'vm'])
    test -f /tmp/fuga
    echo "failed"
@endtask

@macro ('macro-fail')
    touch
    fail
    ls
@endmacro

↑でenvoy run macro-failを実行すると途中のfail taskで失敗します。
が、failタスクの後のlsタスクも実行され、macro-failマクロは正常終了します。くっ・・・

  • @serversのサーバはsshコマンドの形式と全く同じ
@servers (['vm' => 'vagrant@192.168.33.10'])

のようになってる時、port変えてたらどうするんだ・・・みたいになるじゃないですか。
その時はこのようにします。

@servers (['vm' => 'vagrant@192.168.33.10 -p 10022'])

sshコマンドと同じですね。
別にいいんだけど、なんかなぁみたいな気持ちです。

3. 通知機能

slackとhipchatに通知が出来るらしいです。
下みたいな感じです。 タスクやマクロがまともだったらすごく便利だなぁーみたいに思ったかもしれません。

@after
    @hipchat('token', 'room', 'Envoy', "$task ran on [$environment]")
@endafter

@after
    @slack('https://hooks.slack.com/services/ZZZZZZZZZ/YYYYYYYYY/XXXXXXXXXXXXXXX', '#general', 'test with envoy')
@endafter

4. まとめ

bladeのテンプレートといいつつ、blade感あまりないですね。
PHP製といいつつPHPあんまり出てなくて、PHPで作られたツールみたいな立ち位置っぽいです。
マクロの途中でタスクが失敗してもマクロは失敗しないのはちょっと厳しい気がしました。
これならMakefileで良さそう。たぶんEnvoyは使いません。
調べている間に似たようなものにRoboというのも見つけたのでそっちもそのうち試してみたいと思います。

github.com

明日のアドベントカレンダーhidakatsuya - Qiita さんによる記事です!

Laravel製マイクロフレームワークLumenを使おうとして困ったこととその解決策

この記事はLaravelアドベントカレンダーの13日目として書かれています。

www.adventar.org

最近Laravel製のマイクロフレームワークLumenを使って個人的な開発をしています。
その時にこれしたいんだけど、どうやるの?みたいなことを思ったタイミングが何度か合ったので、それをまとめようと思います。

目次

下記のことについて触れようと思います。
ほんとはLumenからLaravelに移行したい時にどうすればよいのかとかも検証したかったのですが、Laravel力が足りなかったので割愛しました。

  • lumenコマンドを使わずにプロジェクトを作成する方法
  • debugをオンにする方法
  • Laravel用のプラグイン利用時にconfigを置く場所について
  • テンプレートエンジンにtwigを使う方法
  • 自前のクラスを置く場所について

lumenコマンドを使わずにプロジェクトを作成する方法

lumenコマンドを利用せず特定のディレクトリにLumenプロジェクトを作成する方法です。
composer create-projectコマンドを利用すれば簡単でした。
Lumen - PHP Micro-Framework By Laravel

$php -r "readfile('https://getcomposer.org/installer');" | php
#!/usr/bin/env php
All settings correct for using Composer
Downloading...

Composer successfully installed to: /path/to/composer.phar
Use it: php composer.phar

$php composer.phar create-project laravel/lumen my_project_dir
Installing laravel/lumen (v5.1.4)
  - Installing laravel/lumen (v5.1.4)
    Loading from cache

Created project in my_project_dir
Loading composer repositories with package information
Installing dependencies (including require-dev)
...
$tree -L 2
.
├── composer.phar
└── my_project_dir
    ├── app
    ├── artisan
    ├── bootstrap
    ├── composer.json
    ├── database
    ├── phpunit.xml
    ├── public
    ├── readme.md
    ├── resources
    ├── server.php
    ├── storage
    ├── tests
    └── vendor

9 directories, 6 files

debugをオンにする方法

Lumenは初期状態だとデバッグがオフになっています。
なので例えば下記のようにしょうもないミスをしていたりするときにLumenを実行したとしても500ページが出るだけで、何が起こっているのか全くわかりません。

<?php

/*
|--------------------------------------------------------------------------
| Application Routes
|--------------------------------------------------------------------------
|
| Here is where you can register all of the routes for an application.
| It is a breeze. Simply tell Lumen the URIs it should respond to
| and give it the Closure to call when that URI is requested.
|
*/

$app->get('/', function () use ($app) {
    $a = $app->welcome();
    return $b;
});

アクセスしたとしてもこのように500エラーのページが表示されるのみ。

f:id:arata3da4:20151213220445p:plain

ビルトインサーバ側も特に何も言ってくれません。

$php artisan serve
Lumen development server started on http://localhost:8000/

これを切り替えるために .envファイルを利用します。
参考 http://lumen.laravel.com/docs/errors

$cd /path/to/my_project_dir
$ls -a
.             .gitignore    bootstrap     database      readme.md     storage
..            app           composer.json phpunit.xml   resources     tests
.env.example  artisan       composer.lock public        server.php    vendor
# この.env.exampleをコピーして利用します。
$cp .env.example .env

よしこれでデバッグがオンになるぜ。って思うじゃないですか。
実はならないです。
理由はこのenvファイルを読みに行くという設定がbootstrap/app.phpコメントアウトされているからです。

$head -n 10 /path/to/my_project_dir/bootstrap/app.php
<?php

require_once __DIR__.'/../vendor/autoload.php';

// Dotenv::load(__DIR__.'/../');

/*
|--------------------------------------------------------------------------
| Create The Application
|--------------------------------------------------------------------------

このDotenv::load(__DIR__.'/../');のコメントアウトを外すと.envファイルを読みに行くようになり、APP_DEBUGがtrueとなっていればデバッグがオンになります。
こんな感じ

f:id:arata3da4:20151213221542p:plain

Laravel用のプラグイン利用時にconfigを置く場所について

Laravelのプラグイン等をインストールし、設定を上書きして変えたい時、configディレクトリにその設定を書けば良いと思うのですが、初期状態のLumenにはconfigディレクトリがありません。
Document見るとなにか書いてあります。
http://lumen.laravel.com/docs/installationConfiguration Filesあたり
なるほど、勝手に足せばよいみたいです。
次の「テンプレートエンジンにtwigを使う方法」でtwigbridgeというプラグインを使うのですが、その場合だとこんな感じになりました。

$cd /path/to/my_project_dir
$mkdir config
$ls
Makefile      bootstrap     composer.phar phpunit.xml   resources     tests
app           composer.json config        public        server.php    vendor
artisan       composer.lock database      readme.md     storage
$cp ./vendor/rcrowe/twigbridge/config/twigbridge.php ./config/
$ls ./config
twigbridge.php

これでプラグインの設定を上書きすることが出来ます。

テンプレートエンジンにtwigを使う方法

よーく考えてみたら、昔記事書いてました。
わりとまじめに書いたのでこちらを参考に・・・

arata.hatenadiary.com

自前のクラスを置く場所について

自前のクラスをどこに置けば良いのかふと悩んだのでその時のメモです。
autoloaderの設定がどうなっているかがわかれば良いので、composer.jsonを見れば良さそうですね。

$cat composer.json
{
    "name": "laravel/lumen",
    "description": "The Laravel Lumen Framework.",
    "keywords": ["framework", "laravel", "lumen"],
    "license": "MIT",
    "type": "project",
    "require": {
        "php": ">=5.5.9",
        "laravel/lumen-framework": "5.1.*",
        "vlucas/phpdotenv": "~1.0"
    },
    "require-dev": {
        "phpunit/phpunit": "~4.0",
        "fzaninotto/faker": "~1.0"
    },
    "autoload": {
        "psr-4": {
            "App\\": "app/"
        },
        "classmap": [
            "database/"
        ]
    },
    "autoload-dev": {
        "classmap": [
            "tests/"
        ]
    },
    "config": {
        "preferred-install": "dist"
    }
}

autoloadの項目を見る限りappディレクトリ以下を見るようになっているので、そこに置けば良さそうです。
app/Hoge/Foo.phpというファイルを置いてみました。

<?php

namespace App\Hoge;

class Foo {
    public static function hello() {
        return "hello namespace";
    }
}

app/Http/routes.phpを編集して動くか確認してみます。

$cat app/Http/routes.php
<?php

/*
|--------------------------------------------------------------------------
| Application Routes
|--------------------------------------------------------------------------
|
| Here is where you can register all of the routes for an application.
| It is a breeze. Simply tell Lumen the URIs it should respond to
| and give it the Closure to call when that URI is requested.
|
*/

$app->get('/', function () use ($app) {
    $m = \App\Hoge\Foo::hello();
    var_dump($m);
});
$php artisan serve &
[1] 43243
Lumen development server started on http://localhost:8000/

$curl localhost:8000
string(15) "hello namespace"

呼べている様子でした。

まとめ

Lumen使ってみて、なんか困ったことをまとめてみました。
.envファイルデフォルトで読みにいかないんかいとかconfigディレクトリ作らないといけないんかいとか思ったりしましたが、そこまでやりたいならLaravel使えよってメッセージなんですかね。
Laravelの方はあまり触ってないので、そちらの方も触っていきたいなーと思った日でした。