おじゃまぷよ系エンジニアメモ

アプリエンジニアからサーバーとインフラエンジニアに転身しました

kotlinのjavascirptで非同期で取得したデータをDOMにバインドするサンプル

kotlinがAndroidに公式サポートされて盛り上がっておりますね。
一応Androidエンジニアやっている?いた?のでkotlinは少し追っていたのですが、今ではWebエンジニアとしての方が強くなってきたので
あえてkotlinでjavascriptやってみよう思い立ってDelegate.Observableを使って、非同期で取得したデータをhtmlのDOMにバインドできないかなぁと思ってやってみたら楽しくなってきたのでメモ

kotlinでjavascriptの準備

チュートリアルにそって準備しました kotlinlang.org

適当にhtmlを用意

<!DOCTYPE html>
<html lang="en">
<head>
    <script src="../kjs/out/production/kjs/lib/kotlin.js"></script>
    <script src="../kjs/out/production/kjs/kjs.js"></script>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div>
    <input id="sampleText" type="text" value="text" title="sampleText">
    <input id="sampleCheckBox" type="checkbox" title="checkBox">
    <button id="sampleButton">sampleButton</button>
</div>
<script>
    new kjs.SampleRequest().request();
</script>
</body>
</html>

divタグの中のDOMのvalueやらcheckboxのdisableの切り替えをAPIを叩いて帰ってきたJSONレスポンスをdata classに変換してバインドする
みたいなものを想定しています。無邪気にid指定しているのは許してください。nameでもclassでも取得できるのでそこは後でお好みで変換してください。 scriptタグ内のkjs.SampleRequest().request()で非同期でGETリクエストを投げてJSONを受けってデータバインドします

バインドするdata class

data class SampleEntity(val inputText: String, val disabled: Boolean, val buttonText: String)

inputTextをDOMのtextのvalueに
buttonTextをDOMのButtonのtextContentに
disableをcheckBoxのdisableに バインドする想定のdata class

バインドするDOMのテンプレートクラス

object SampleTemplate {
    var entity by Delegates.observable<SampleEntity?>(null) {
        _, _, new ->
        new?.let {
            inputText.value = new.inputText
            checkBox.disabled = new.disabled
            button.textContent = new.buttonText
        }
    }
    val inputText: HTMLInputElement = document.getElementById("sampleText") as HTMLInputElement
    val checkBox: HTMLInputElement = document.getElementById("sampleCheckBox") as HTMLInputElement
    val button: HTMLButtonElement = document.getElementById("sampleButton") as HTMLButtonElement
}

それぞれのDOMの情報をメンバ変数に持って
Delegate.observableを利用してSampleEntityがsetされたらDOMに値を入れるようにしています

GETのRequestを投げるクラス

class SampleRequest {
    fun request(){
        val req = XMLHttpRequest()
        req.onloadend = fun(event:Event){
            SampleTemplate.entity = JSON.parse<SampleEntity>(req.responseText)
        }
        req.open("GET","http://localhost:63342/kjs/json_text.txt",true)
        req.send()
    }
}

XMLHttpRequestで非同期でGETリクエストを投げて、取得したJSONをSampleEntityに変換してSampleTemplateのentityにセットしています。

適当なJSONのファイル用意します

{"inputText":"テキストはいる","disabled":true,"buttonText":"hoge"}

buildしてブラウザでチェックします

ディレクトリ構成はこんな感じですごく適当においてます f:id:masahide318:20170606235740p:plain

IntelliJからindex.htmlをopenすると「http://localhost:63342/kjs/index.html」みたいなURLで開きます

すると
f:id:masahide318:20170606234207p:plain
から
f:id:masahide318:20170606234312p:plain

にtextの内容やcheckboxがdisable状態になったりと、データが反映されます。
今回は恐らく最小の構成?でバーっと書いてみましたが、案外使えそうな気がしています。

おまけ

f:id:masahide318:20170606235313p:plain

チュートリアルにあるようにdebugの設定をすると、kotlinのソース上でちゃんとブレイクポイント貼れるのでかなりデバッグが助かります。 vue.jsやほかのjsのライブラリとうまく組み合わせたパターンなど色々と試してみたいですね。

phpのSlim3をコマンドラインから実行して使う

月1ペースを目標に更新したかったけど、全然更新してなかった ということでphpの軽量フレームワークSlim3を最近使うことが多く、以前コマンドラインから実行するバッチ専用のシステムとして作ったのでその時の情報をメモです。

github.com

Slim3でプロジェクトを作る

www.slimframework.com

公式ドキュメントを元に空のプロジェクトを作ります。
今回は「batch-sample」というプロジェクト名で作成します。

index.phpファイルを修正する

batch-sample/public/index.php

<?php

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

$settings = require __DIR__ . '/../src/settings.php';

$commandName = $GLOBALS['argv'][1];


$settings['environment'] = \Slim\Http\Environment::mock(
    [
        'REQUEST_URI' => '/' . $commandName,
    ]
);
$app = new \Slim\App($settings);

require __DIR__ . '/../src/dependencies.php';

require __DIR__ . '/../src/middleware.php';

require __DIR__ . '/../src/routes.php';

$app->run();

ここが恐らく一番のポイントです。 \Slim\Http\Environment::mockでコマンドラインから受け取ったコマンド名をURIに設定して、それに対応するルーティングの処理を呼び出すようにします。 Enviroment:mockはUnitTestのときに、Httpリクエストのmockとして使われます。それをそのまま流用してコマンドラインから実行したときにコマンド名からmockのリクエストを作って実行するという流れです。

バッチの主処理を記述するクラスを作る

batch-sample/src/Action/SampleAction

<?php

use Psr\Container\ContainerInterface;
use Slim\Http\Request;
use Slim\Http\Response;

class SampleAction {

    private $container;

    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
    }

    public function __invoke(Request $request, Response $response, $args)
    {
        $response->write("hello world");
        return $response;
    }
}

ルーティングでこのActionをバインドする

batch-sample/src/route.php

<?php

require_once __DIR__.'/Action/SampleAction.php';

$app->get("/sample_command", SampleAction::class);

とりあえず実行する

ここまで作ったらとりあえず実行してみます。 実行方法はbatch-sampleディレクトリで「php public/index sample_command」です。 実行してみるとコンソール上に「hello world」が出力されます。
非常に簡単ですね。

もう少し改良する

例えばWebからもフックできるようにindex.phpをいじります。 WebApplicationとCliApplicationクラスのようなものを作って、PHP_SAPIを見てどちらのApplicationクラスを実行するか分岐させます

batch-sample/src/Application/CliApplication.php

<?php
//コマンドラインから起動されたとき甩のクラス
class CliApplication
{
    public function run()
    {
        $settings = require __DIR__ . '/../../src/settings.php';

        array_shift($GLOBALS['argv']);
        $commandName = $GLOBALS['argv'][0];

        $settings['environment'] = \Slim\Http\Environment::mock(
            [
                'REQUEST_URI' => '/' . $commandName,
            ]
        );
        $app = new \Slim\App($settings);

        require __DIR__ . '/../../src/dependencies.php';

        require __DIR__ . '/../../src/middleware.php';

        require __DIR__ . '/../../src/routes.php';

        $app->run();
    }
}

batch-sample/src/Application/WebApplication.php

//Webからフックされたとき用のクラス
<?php
class WebApplication
{
    public function run()
    {
        if (PHP_SAPI == 'cli-server') {
            // To help the built-in PHP dev server, check if the request was actually for
            // something which should probably be served as a static file
            $url = parse_url($_SERVER['REQUEST_URI']);
            $file = __DIR__ . $url['path'];
            if (is_file($file)) {
                return false;
            }
        }

        $settings = require __DIR__ . '/../../src/settings.php';
        $app = new \Slim\App($settings);

        require __DIR__ . '/../../src/dependencies.php';

        require __DIR__ . '/../../src/middleware.php';

        require __DIR__ . '/../../src/routes.php';

        $app->run();
    }
}

batch-sample/public/index.php

<?php

date_default_timezone_set('Asia/Tokyo');
require __DIR__ . '/../vendor/autoload.php';

use Batch\Sample\Application\CliApplication;
use Batch\Sample\Application\WebApplication;


if(PHP_SAPI == "cli"){
    (new CliApplication())->run();
}else{
    (new WebApplication())->run();
}

これでビルトインサーバーを起動して「http://localhost:8090/sample_command」にアクセスすれば同じバッチ処理が起動します。

さいごに

さらっとした説明はここまでにして、その他にも多重起動防止や実際にDBを操作する処理も含めたものはgithubにあげておきます。 サブシステムとして特定のバッチ処理をしたいというときにもしかしたら使えるかもしれませんね。

github.com

githubに上げてる方はクラス設計がここのサンプルとはだいぶ変わっています。といってもActionクラスがServiceクラスを決定し、Serviceクラスはバッチ処理を行うための複数のModelを使用する…ってだけですが、適度に分割されてると思いますしテストコードも問題なく書けるはずです。 Slim3は軽量なフレームワークなだけあってクラス設計がフルスタックよりも楽しいです。
APIサーバー用のフレームワークとしてもかなりアリだと思うので今作ってるアプリのサーバー側はSlim3にしようかと思っているところ。
Slim3は最近すごくお気に入りなので、APIサーバーを作ってまた何か知見を得られれば何か書きたいです。

phpのsession_decodeはarray_mergeされる

あるときphpでscript書いてるときにハマった。 session_decode()したら$_SESSIONに配列がまるっと置き換えられると思ってたらどうも違ったらしい

<?php
session_start();
$_SESSION = ['a' => 'b'];
$data1 = session_encode();
$_SESSION = ['c' => 'd'];
$data2 = session_encode();

$_SESSION = [];
session_decode($data1);
session_decode($data2);
print_r($_SESSION);

session_decodeをした結果

(  
    [c] => d  
)  

こうなると思ってたら実際は

(  
    [a] => b  
    [c] => d  
)  

こうなった。

<?php
session_start();
$_SESSION = ['a' => 'b'];
$data1 = session_encode();
$_SESSION = ['a' => 'd'];
$data2 = session_encode();

$_SESSION = [];
session_decode($data1);
session_decode($data2);
print_r($_SESSION);

同じキーを入れると

(  
    [a] => d  
)  

こうなって見事にキーの中身がbからdに上書きされた。
これは騙される。完全にまるっと置き換えられると思ってたけど、そうじゃなかった。

今年一年のエンジニアライフを振り返ってみる

歳を取るたびに1年が短くなっていくというのどうやら本当のようで、振り返れば1年があっという間にすぎさってしまっています。
そんな短い1年で自分が一体エンジニアとしてどういうことができたのかちょっと振り返ってみたくなったので何をやったのかバーっと思い出してみます。

初のiOSアプリのリリース

masahide318.hatenablog.jp

Icros

Icros

  • Masahide Takahata
  • Social Networking
  • Free

今年一番まともなアウトプットってこれだけかもしれないです……
まだこれをやっていたころはswift2なのでswift3で何かiOSアプリを改めて作りたい。
またクラス構造も最近流行りのMVVMの構造とかは無関係にViewControllerにすべてのロジックを詰め込んでいるのでもはや何書いてるのかわからないレベル。

kotlinでAndroidアプリ作る

github.com

play.google.com

retrofitとRxJavaを使いたかったから無理やり作った。
tokenのリフレッシュ周りがクソ実装のまま放置してしまった。時間があったら直すは結局直さない。仕事でも同じで確実に技術的負債を積んでいく。ただこれは負債を返すより早くリリースすることを目標にしてたので正しい判断だったのだ……。
kotlinでAndroid開発するのは個人的にアリだとは思うが、Instant Runやkapt周りが怪しいので変にハマったときに解決する、もしくは便利なライブラリを諦める覚悟がない場合は素直にJavaでやるほうがいいかな。 個人の開発であってもクラス設計などしっかり考えて技術的負債を残さず開発するクセつけないと、実務でついえいやで実装してしまうので注意する。

kotlinでDIライブラリ書く

github.com phpのDIライブラリのpimpleの模倣版。AndroidのApplicationクラスで必要なサービスクラスの生成をコンテナにつめて使ってみる妄想をしたが、まだ実際に使ってない。Dagger2あるし…
ただkotlinで何か書いてみたかった欲を発散させたなにかになった。

Webエンジニアしてphpフレームワークさわる

具体的なアウトプットはないが、仕事上ネイティブアプリとしての仕事がまわってこなくなりWebの開発がメインになったので真面目にWebの基礎からやろうと勉強した。 もともとあるソースにつきたしするのは出来たが一からフレームワークの動きを追うっていう機会があまりなかったのでLaravelとSlim3とdietcakeをVagrant上に構築して軽く動かすことだけした。 Slim3は実務でも使うことがあり、軽量でなかなか使いやすい。
そもそもnginxの設定やmysqlやRedisのインストールも怪しかったのでAnsibleを使ってそれらもろもろ一発で入るようにした
deploy方法にcapistrano入れて実際にさくらサーバーにdeployしてみたりと、Webアプリケーションエンジニアとしての基礎を改めて学んだ。
これらの基礎を改めて学んで何か実務でも障害が起こったときに問題の切り分けなど判断がスムーズにできるようになった気がする。
ネイティブアプリのAPIを作るときもさくっとサンプル作ったりできるようになったので本当に色々と立ち回りやすくなった。

品質や設計、テストについて考えるようになった

このあたりについてはまた別の機会に書いてみようかな。
今まで品質がいいとはバグが少ないことではない。テストコードはただ書けばいいというものではないと改めて考えされた。
テストで何を保証したいのかなどテストを設計しないと,、意味もなくただカバレッジ100%にするってだけではただ開発の足かせにしかならないなと学んだ。
最近はソフトウェアの品質やテスト計画など、ソフトウェアの品質はいかにして高めるのかという本ばかり読んでる。
このあたりはまだ自分も勉強中なのでしっかり身につけて、個人の開発というよりチームの開発につなげていきたい。

まとめ

広く浅く色んな技術に触れた1年だった。 ひっそりと個人でネイティブアプリをやりつつ、仕事ではWebアプリをやるという少し前に流行ったフルスタックエンジニア(笑)になりつつある。自分の軸となる技術を確立されせて、あの技術はこの人ってなれるぐらい成長したい。 とりあえずswift3で何かリリースするぞ!Vue.jsもさわりたいし!やりたいことが多すぎるっ!

後仕事でもネイティブアプリやりたいなぁ……

来年の抱負

  • swift3でiOSアプリ作る
  • Androidアプリ何か作る
  • 英語のドキュメントちゃんと読めるように英語もっと勉強する
  • 健康診断でオールAをとる

これら頑張っていきたい。エンジニアとして周りの人に負けないように研鑽を積んでいく一年にする。

phpでRedisのlRangeがPhakeで差し替えられない罠

ある日phpのRedisをPhakeでmockにしてテストしていたときにlRangeがなぜか差し替えられない状況に陥った。
ソースコードは以下のような感じ

<?php
class HogeTest extends \PHPUnit_Framework_TestCase{
    /** @var  \Redis */
    private $target;

    public function setUp(){
        $this->target = \Phake::mock(\Redis::class);
    }

    public function testHoge(){
        \Phake::when($this->target)->get("key")->thenReturn("value");
        $this->assertEquals("value", $this->target->get("key")); //OK
    }

    public function testLGet(){
        \Phake::when($this->target)->lRange("key", 0, -1)->thenReturn(["a","b"]);
        $this->assertEquals(["a","b"],$this->target->lRange("key", 0, -1) ); // NG
    }
}

functionのgetは期待通り差し替えられているのにlRangeだけはどうしてもnullが帰ってきてしまう。
phpredisを調べてみると、

github.com

このソースを見るとlRangeはlGetRangeのエイリアスとして存在しているらしい。
つまりlRangeは本来存在しないfunction…
ということでlGetRangeに置き換えてみると無事にfunctionを差し替えることが出来ました

<?php
class HogeTest extends \PHPUnit_Framework_TestCase{
    /** @var  \Redis */
    private $target;

    public function setUp(){
        $this->target = \Phake::mock(\Redis::class);
    }

    public function testLGetRange(){
        \Phake::when($this->target)->lGetRange("key", 0, -1)->thenReturn(["a","b"]);
        $this->assertEquals(["a","b"],$this->target->lGetRange("key", 0, -1) ); //OK
    }
}

phpのエクステンションでエイリアスとして存在するfunctionは置き換えられないということに気をつけて、次もしPhakeで差し替わらないfunctionあったときはエイリアスを疑おう

モジュール結合度について復習した

プリンシプルオブプログラミング読んでなんとなく思い立ってモジュール結合度について考え直した
昔、基本情報技術者試験受けたときに勉強したときはただ暗記しただけだったけど改めて結合度について学んでみると「なるほどな…」って思うことが多かったので実際にクラスとか書いてまとめてみる

モジュール結合度とは

モジュール同士の関係の密接さを表す尺度……
と書いてあるがちょっと意味が難しい。クラス同士の影響度と言ったほうがわかりやすい。クラスの処理や値を変更すると他のクラスに影響を及ぼすものが結合度が高いということだろう。 モジュール結合度には以下の6種類があり、レベルが高いほど結合度が低い。

  • レベル6データ結合
  • レベル5 スタンプ結合
  • レベル4 制御結合
  • レベル3 外部結合
  • レベル2 共通結合
  • レベル1 内容結合

レベル6データ結合

スカラー型のデータを引数として渡す結合。

<?php
class ModuleA {
    public function add($a,$b){
        return $a + $b;
    }
}

class ModuleB{
    public function doService(){
        $moduleA= new ModuleA();
        $result = $moduleA->add(1,2); //データ結合
        // doSomething
    }
}

ModuleAもModuleBもお互いに内部の実装に干渉しない(ブラックボックス化されている)ので、安心してプログラムの中を変更できる。
結合度が低いと言える。

ModuleAはModuleBとデータ結合してる状態。

レベル5 スタンプ結合

共通域にないデータ構造を受け渡しするような結合形態。
スカラー型ではなく、オブジェクトを引数として渡すと解釈して良さそう。

<?php
class User{

    private $id;
    private $name;

    public function __construct($id, $name) {
        $this->id = $id;
        $this->name = $name;
    }

    public function getId() {
        return $this->id;
    }

    public function setId($id) {
        $this->id = $id;
    }

    public function getName() {
        return $this->name;
    }

    public function setName($name) {
        $this->name = $name;
    }


}

class ModuleA {
    /**
     * @param $user User
     * @return string
     */
    public function doService($user){
        return " name : ".$user->getName();
    }
}

class ModuleB{
    public function doService(){
        $user = new User(1,"masahide");
        $moduleA = new ModuleA();
        $result = $moduleA->doService($user);
        // doSomething
    }
}

ModuleAもModuleBもお互いに内部の実装に干渉しない。
スタンプ結合の場合受け渡すデータの一部を使用しないことがある。
Userのnameは使うけどidは使わないというような状態。

レベル4 制御結合

呼び出し側のモジュールが、呼び出し先のモジュールの制御を指示するデータをパラメーターとして渡す方式。
よくある引数にflgとかtypeとかstatusを渡して呼び出し先の処理を制御するパターンと解釈してよさそう。

<?php
class ModuleA {
    public function doHoge($type){
        if($type === 1){
            //doSomething
        }elseif ($type === 2){
            //doSomething
        }elseif ($type === 3){
            //doSomething
        }else{
            //doSomething
        }
    }
}

class ModuleB{
    public function doService(){
        $moduleA = new ModuleA();
        $moduleA->doHoge(2);
        // doSomething
    }
}

ModuleBがModuleAを使用するときに、typeを渡すことによって内部の処理を制御してる。
データ結合や、スタンプ結合と違いモジュールの使用側が使用するモジュールの内部の実装を知っている必要があるので結合度が高くなると解釈した。

レベル3 外部結合

外部宣言したデータを共有したモジュール間の結合形式。
書籍や記事によってはグローバル変数のことであったり、publicな変数であったりと少し表現が違っている。
基本情報技術者試験に則って、グローバル変数の値を参照するパターンを外部結合としてみる。

<?php

$GLOBALS['hoge'] = "hoge";

class ModuleA {
    public function doService(){
        echo "moduleA : ".$GLOBALS['hoge'];
    }
}

class ModuleB{
    public function doService(){
        echo "moduleB : ".$GLOBALS['hoge'];
    }
}

こんな感じかな… グローバル変数なのでどこで書き換えれるかわからず、書き換えられるとModuleA,Bともに影響を受けるので結合度は高い。

レベル2 共通結合

これもグローバル変数をモジュール間で共有するパターンだが、外部結合との違いは、データ結合とスタンプ結合の違いと同じように
データ構造を共有して不必要な値までも共有しているということ

<?php

$GLOBALS['user'] = new User(1,"masahide");

class User{
    private $id;
    private $name;

    public function __construct($id, $name) {
        $this->id = $id;
        $this->name = $name;
    }

    public function getId() {
        return $this->id;
    }
    public function setId($id) {
        $this->id = $id;
    }
    public function getName() {
        return $this->name;
    }
    public function setName($name) {
        $this->name = $name;
    }
}

class ModuleA {
    public function doService(){
        echo "moduleA : ".$GLOBALS['user']->getName();
    }
}

class ModuleB{
    public function doService(){
        echo "moduleB : ".$GLOBALS['user']->getName();
    }
}

これもグローバル変数を共有しているのでどこで書き換えれるかわからず、さらに本来不必要なデータまで共有している分外部結合よりさらに高くなる

レベル1 内容結合

モジュール同士の命令の一部を共有したり、外部宣言していないデータを直接参照したりしている状態
カプセル化できてないクラスや、リフレクション使って無理やり命令の一部を使っている状態と言ってよさそう

queryパラメーターをPHPで暗号化して渡してJavaで復元したい

とあるPHPで書かれたWebサービスAから、とあるJavaで書かれたWebサービスBにパラメーターを暗号化してqueryパラメーターで渡したいときがあったのでその時のメモ

PHP側の暗号・復号化を行うクラス

<?php
class MyCipher {
    const SECRET_KEY = "1234567890123456"; //Javaと共通の秘密鍵。ランダウな文字列16桁
    const IV_PARAMETER = "1234567890123456"; //Javaと共通のIV。ランダムな文字列16桁
    const METHOD = "AES-128-CBC"; //256のほうが安全だが、Java側がデフォルトで256使えないので128にしてる

    /**
     * 受け取った文字列を暗号化しBase64+URLエンコードして返す
     * @param $originalStr
     * @return string
     */
    public static function encrypt($originalStr) {
        return urlencode(openssl_encrypt($originalStr, self::METHOD, self::SECRET_KEY, false, self::IV_PARAMETER));
    }

    /**
     * Base64+URLEncodeされている暗号化文字列を元の文字列に復号する
     * @param $encryptStr
     * @return string
     */
    public static function decrypt($encryptStr){
        return openssl_decrypt(urldecode($encryptStr), self::METHOD, self::SECRET_KEY, false, self::IV_PARAMETER);
    }
}

$encrypt = MyCipher::encrypt("abcdef"); //JxdRLkrOq5SDY9YMcUSUhg%3D%3D
$decrypt = MyCipher::decrypt($encrypt); //abcdef
echo $decrypt === "abcdef"; //復号される

Javaの暗号・復号化を行うクラス

public final class MyCipher {

    private static final String SECRET_KEY = "1234567890123456";// 秘密鍵は16文字で。PHP側と同じものを指定する
    private static final byte[] IV_Parameter = "1234567890123456".getBytes();//IVの値。PHP側と同じものを指定する
    private static final String ALGORITHM = "AES/CBC/PKCS5Padding";// 暗号化方式

    /**
     * 文字列を16文字の秘密鍵でAES暗号化してBase64+URLEncodeした文字列で返す
     */
    public static String encrypt(String originalSource) throws Exception {
        Cipher cipher = initCipher(Cipher.ENCRYPT_MODE);
        //文字列をバイト列に変換
        byte[] originalBytes = originalSource.getBytes();
        //暗号化後のバイト列取得
        byte[] encryptBytes = cipher.doFinal(originalBytes);
        //バイト列を文字列にして返す
        return URLEncoder.encode(Base64.getEncoder().encodeToString(encryptBytes),"UTF-8");
    }

    /**
     * Base64+URLEncodeされたAES暗号化文字列を元の文字列に復元する
     */
    public static String decrypt(String encryptStr) throws Exception {

        //暗号化されたmd文字列からバイト列を取得
        //JavaのUrlDecoderは「+」を半角スペースに変えてしまうので、「%2B」に置換する
        byte[] encryptBytes = Base64.getDecoder().decode(URLDecoder.decode(encryptStr.replace("+", "%2B"),"UTF-8"));
        Cipher cipher = initCipher(Cipher.DECRYPT_MODE);
        //復号化後にバイト列取得
        byte[] originalBytes = cipher.doFinal(encryptBytes);
        //文字列にして返却
        return new String(originalBytes);
    }

    private static Cipher initCipher(int method) throws InvalidAlgorithmParameterException, InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException {
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(method,new SecretKeySpec(SECRET_KEY.getBytes(),"AES"),new IvParameterSpec(IV_Parameter));
        return cipher;
    }
}
public class Sample {
    public static void main(String[] args) throws Exception {
        String encrypt = MyCipher.encrypt("abcdef");
        System.out.println(encrypt); //JxdRLkrOq5SDY9YMcUSUhg%3D%3D
        System.out.println(MyCipher.decrypt(encrypt)); //abcdef
        //復号化されてる
    }
}

これでPHPJavaで相互に値を受け渡しできるようになりました。 秘密鍵と初期ベクトルが外部に漏れない限りは復号できないと思われるので、まぁ十分に安全かと思います。
ただ不安はつきものなのであまり重要なデータは別の方法で受け渡ししたほうが良いかもしれない。

参考URL : stackoverflow.com

http://itmemo.net-luck.com/java-aes/

日々是妄想 : 初期化ベクトルってなに?(解決編)