macOSで動くFileMaker Server 2024でPHP

FileMaker ServerにはPHPが付属しなくなって久しいのですが、現状、特にFileMaker Serverで動かなくても不便はなく、PHPの処理が欲しい場合は別途サーバを立てるのが最善策なのはいうまでもありません。しかしながら、「どうしても動かしたい」という声が後を絶たず、ここでとりあえず動かす方法をまとめておきます。そもそも、Clarisからの文書として「FileMaker ServerインストーラへのPHP添付の廃止について」があるのですが、内容が非常に込み入っていて、しかも何をしているのかわかりにくいこともあって、PHPを動かすことに躊躇している人も多いかもしれません。この文書は、FileMaker API for PHPという懐かしいライブラリを利用するための方法まで書いてありますが、今時のPHPのバージョンでこのライブラリが無事に動くとは考えづらく、その方法までは不要なのが一般的ではないかと思われます。

以下の方法が成功したのは、macOS Sequoia上のFileMaker Server 2024の場合です。これは対応OSではないのに成功したということです。また、Sequioa上ではFileMaker Server 2023でも成功しました。これも対応OSではありません(2024版はSequioa対応かどうかは公表されていないですね)。一方、macOS Ventura上のFileMaker Server 2023ではエラーになってうまくいきませんでした。これは対応OSであるのに上手くいかなかった組み合わせです。macOS内蔵のApache2に、外部からインストールするphpのモジュールという組み合わせの相性があるようなので、上手くいかない場合もあるという覚悟で進めましょう。

macOSへのFileMaker Serverのインストールはすでにインストールされているものとします。これにHomebrewをインストールします。インストール方法はサイトに記載されているので、それに応じてインストールしてください。インストール後、以下のようなコマンドを叩いて、phpをインストールします。執筆時点では、8.1以降は@をつけるので良いのですが、7.4はタップというサードパーティによるモジュール提供になっているので、コマンドの入れ方が変わります。コマンドラインでphpのバージョンを切り替えるには、unlink/linkを使います。

//最新版のPHPのインストール(執筆時点では8.3)
brew install php
//特定版のインストール
brew install php@8.1
//PHP 7.4のインストール
brew tap shivammathur/php
brew install shivammathur/php/php@7.4
//バージョンの切り替え
brew unlink php
brew link php@7.4

ちなみに、通常は最新版を使うけど、PHPのモジュールとしては古いものを使うということもアリです。以下、自分の使いたいバージョンのパスを確認してください。原則、/opt/homebrew/Cellerというディレクトリ以下にありますが、状況によって違うので、見つからない場合はいろいろ情報を探ってください。

次にコード署名を行います。コード署名とは、秘密鍵/公開鍵を使った暗号化の仕組みの応用で、ざっくり言うと「誰が作ったコードかわかる仕組み」です。iPhoneのアプリケーションでは当初より署名必須となっており、Appleが発行する証明書を利用して署名されていないと、App Storeへの登録ができなくなっています。この手法はmacOSにもかなり浸透してきており、macOSに付属しているApache2のバイナリhttpdも当初よりコード署名がなされています。

PHPはApache2用のモジュール(拡張子.so)を利用します。このモジュールは、httpdと同じプロセス空間で動きます。イメージ的にはhttpdがphpのモジュールを読み込むと思えば良いでしょう。しかし、macOSの制限により、httpdが署名されている場合は、読み込むモジュールも署名されていないといけません。homebrewで得られるモジュールは署名されていないので、そのままではモジュールとして読み込んで実行ができないのです。そこで、brewで得られたphpのモジュールに署名して、httpdが読み込んで利用できるようにする必要があります。

証明書を作る方法はいろいろあるのですが、「キーチェーンアクセス」アプリケーションを利用して、いかような手順で進めて作成される自己署名証明書で大丈夫です。ポイントは、証明書のタイプを「コード署名」にすることと、指定した名前を忘れないようにすることです。この証明書はキーチェーンに入ります。

キーチェーンにコード署名用の証明書を作ったら、コマンド入力を進めます。まず、/opt/homebrew/Celler以下にあるPHPのパスを探って、phpのモジュールを探します。バージョン等でパスの形式が違う場合がありますが、特定バージョンのphpのフォルダには.soファイルは1つだけなので、それをともかく探せば良いでしょう。そして、codesignコマンドで署名を行います。ちなみに、証明書を作ったユーザでログインしてターミナルで作業する範囲では、codesignコマンドはキーチェーンと同一のデータを使うので、コマンドにキーチェーンの場所を指定する必要はありません。コード署名をしたら、署名を読み出してみて、証明書の名前がAuthorityキーの値に見えることを確認しましょう。

モジュールを特定する(以下、「モジュールのパス」と記載)
/opt/homebrew/Cellar/php/8.3.12_1/lib/httpd/modules/libphp.so
コード署名する
codesign -f --options runtime --timestamp -s "msyk-test" モジュールのパス
//コード署名を表示する',
codesign -d -vvv モジュールのパス
//以下、表示結果Authorityの部分が、証明書の名前(作成時に指定したものとなっている)
Executable=/opt/homebrew/Cellar/php@7.4/7.4.33_6/...
Identifier=libphp7
Format=Mach-O thin (arm64)
   :
Authority=msyk-test

続いて、Apache2の設定ファイルを編集します。設定ファイルは、/Library/FileMaker Server/HTTPServer/conf以下にあります。ファイルはhttpd.confなのですが、以下のように、さらに2.4という拡張子が増えているファイルがあります。これを-iをつけたlsコマンドで見ると、1列目にi-nodeが見えています。i-nodeはファイルシステムでのファイルの中身を特定する番号を思ってください。よく見ると、httpd.confとhttpd.conf.2.4は同じi-node番号です。つまり、1つのファイルの実態にファイル名が2つ割り当てられているという状況で、これらは「ハードリンク」という状態であると呼ばれます。つまり、同じ中身なのです。

% ls -l -i
total 424
158411791 drwxrwxr-x  32 fmserver  fmsadmin   1024 10  9 10:19 extra
158417655 -rwxrwxr-x@  1 fmserver  fmsadmin  18175 10  8 13:32 httpd.conf
158417655 -rwxrwxr-x@  2 fmserver  fmsadmin  18144 10  8 11:57 httpd.conf.2.4
158412007 -rwxrwxr-x   2 fmserver  fmsadmin  13077  1 25  2024 magic
158412007 -rwxrwxr-x   2 fmserver  fmsadmin  13077  1 25  2024 magic.2.4

ここで普通にファイルを変更してもいいのですが、2.4が付いた方がバックアップと売れば、httpd.confは別ファイルとして変更したいような気がするので、たとえば次のようにコマンドを入れて、http.confとhttpd.conf.2.4を別物にしてしまうという手はあります。2つ目でhttpd.confは消えるのですが、中身は別のリンクhttpd.conf.2.4から参照できる状態なので、事実上ファイルは消えません。

cd /Library/FileMaker Server/HTTPServer/conf
rm httpd.conf
cp http.conf.2.4 httpd.conf

ということで、設定ファイル/Library/FileMaker Server/HTTPServer/conf/httpd.confを修正します。以下に、元の状態とその範囲の修正結果を示します。ページ内で、phpというキーワードを探せばすぐに元の範囲は特定できます。その前にLoadModule、そしてFileMatchディレクティブの中にSetHeaderを定義します。モジュールのパスや証明書の名前は、もちろん、前に示したものを指定します。

//元の状態',
<FilesMatch "\.php$">
    Require all denied
</FilesMatch>
//修正した状態',
LoadModule php_module モジュールのパス 証明書の名前
<FilesMatch "\.php$">
    SetHandler application/x-httpd-php
</FilesMatch>

なお、ここで、LoadModuleディレクティブは、通常は証明書の名前は設定できません。Apacheのサイトでもこんな引数はありません。おそらく、macOSに搭載されているhttpdは特別にこのような設定を入れることができるようになっていると思われます。

ちなみに、Apache2のエラーログなどを見ると、正しい状態でもこのようなnoticeメッセージが出てきます。パスが違っていたり、署名されていなかったり、名前が違ったりすと別のエラーメッセージになり、Apache自体が起動しません。

[Tue Oct 08 12:44:50.253541 2024] [so:notice] [pid 17129] AH06662: Allowing module loading process to continue for module at /opt/homebrew/opt/php/lib/httpd/modules/libphp.so because module signature matches authority "Developer ID Application: Nii Masayuki (W3WVRUYJRT)" specified in LoadModule directive

ということで、お決まりの、phpinfo()関数の結果は以下のとおりです。Darwin OS内で動いているのが見えます。もう、HomebrewのPHPは、Sequoia対応になっていますが、この時はSonoma対応の段階でしたけど、ちゃんと動いていました。

そういうわけで、FMDataAPIについても動作確認しました。一連の作業は、自分の普段使いのMacで確認したので、HomebrewによるPHPはいろんなものが最初から入っているため一発で動きましたが(というか、その環境でFMDataAPIを開発している)、足りないモジュールがあればbrew install モジュール名 等でインストールしましょう。

一連の作業で面白い動作を発見しました。codesignコマンドなのですが、SSH経由でログインをしてコード署名を行うと、adhocという名前が出てくる、おそらくはちゃんとしてない署名になります。Authorityは設定されないので、ApacheのPHPモジュールに署名しても稼働はしません。つまり、codesignコマンドは、macOSにログインをして、その上でターミナルから起動して署名しないといけないのです。セキュリティ的な理由なのか、あるいはキーチェーンの扱いなんかがあるのかもしれませんが、ともかく、ログイン方法でコマンドの動作が違って場合によっては正く署名されないというのは落とし穴かもしれません。プロバイダにあるMacや、鍵のかかったサーバルームにあるMacなんかの場合はよく注意をしましょう。

そういうわけで、HomebrewがインストールしたPHPのモジュール、macOSに内蔵されているApache2のhttpdを使うということで、コード署名が必要になるということだったのですが、ちなみに、Homebrewのアップデート(brew update/brew upgradeコマンド)を行うと、場合によってはバイナリが置き換わります。上記のような手順の場合、PHP 8.3の新しいマイナーバージョンの登場で古いものは消されるので、つまりはアップデートがあればその都度コード署名をしなければならないという、面倒かつ、実運用では危険な状態でもある点に注意を払う必要があります。

ちなみに、FileMaker Serverは入れておきたいけど、PHPでも開発作業等をしたい場合、つまり、それぞれ別々に利用するのが一般的な場合は、ここにあるような作業をしなくても、phpを-Sオプションをつけて、サーバモードで動かすのが普通です。公開ディレクトリをカレントディレクトリにして、php -S localhost:9000などとコマンドを入れて、ブラウザから「http://localhost:9000」に接続します。ということで、やっぱりFileMaker ServerのApache2上でPHPを動かす必要性って限られるんですよね。

macOSでPHPのバージョン管理

普段、最新のPHPでの検証が多いのですが、久々に、古いアプリケーションのメンテのために、8.2.0がカレントバージョンの今、7.4を使う必要が出ました。そのアプリが8.2で動いてくれればいいのですが、Warningが出るので7.4にしたいですね。当然、phpはhomebrewを使っているのですが、標準ではカレントバージョンしかサポートしていないらしく、あちこちに掲載されている「brew install php@7.4」がエラーになって動かないのです。こんな感じ。

% brew install php@7.4
Error: php@7.4 has been disabled because it is a versioned formula!

こういう場合は、上記2行目のエラーメッセージを、そのままGoogle検索窓にコピペして検索します。やはり、StackoverflowにError: php@7.3 has been disabled because it is a versioned formulaという記事が見つかりました。

ということで、標準以外のバージョンをインストールできるTapがあるということで、以下のようにコマンドを入れれば、無事にphp 7.4がカレントになりました。

brew tap shivammathur/php
brew install shivammathur/php/php@7.4

この後に、brew link …とすればいいかと思うのですが、現行バージョンのver.8.2をunlinkする前だと、–overwriteをつけろとメッセージが出てきます。以下の流れだと、–overwriteは不要かもしれませんが、エラーの時には試してみましょう。

% brew unlink php@8.2
% brew link --overwrite php@7.4
Linking /usr/local/Cellar/php@7.4/7.4.33... 25 symlinks created.

If you need to have this software first in your PATH instead consider running:
  echo 'export PATH="/usr/local/opt/php@7.4/bin:$PATH"' >> ~/.zshrc
  echo 'export PATH="/usr/local/opt/php@7.4/sbin:$PATH"' >> ~/.zshrc
% php -v                       
PHP 7.4.33 (cli) (built: Dec  8 2022 21:39:37) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
    with Zend OPcache v7.4.33, Copyright (c), by Zend Technologies

そういうわけで、PHPの各バージョンは、こちらのレポジトリのようにしっかり古いものからより新しいものまでキープしてくれていることに感謝です。

Catalinaで使えなくなったRealtekのEthernetのドライバが出たけどダメだった話

私は、MacBookにNOVOOと書かれたEthernet端子付きのアダプタを自宅で使っているのですが、CatalinaになってEthernetが使えなくなりました。ドライバの問題なのは明らです。「システム情報」ではドライバそのものを認識しているのに対して、「ネットワーク」システム環境設定では赤いボールが見えていて、接続できません。もちろん、ケーブルはちゃんと接続してあります。

それで、どうやらCatalina対応版のドライバが出た模様です。Ver.1.0.20だそうです。とは言え、どうやらインストールが簡単ではないようです。そもそも、ドライバが動かなくなった理由は、おそらくはmacOSのセキュリティ要件が厳しくなったからと言うのもあると思われますが、その結果、機能拡張系は簡単にはインストールできない状態になったと思われます。そう言うわけでいろんな関門を潜り抜ける必要があるようです。

インストーラーの中のpkgファイルをダブルクリックして、まずはいきなり起動できません。署名はしてあり有効なもののようなのに、これが出るんですね。システム環境設定の「セキュリティとプライバシー」で「このまま開く」にしたら、もちろん起動してインストールはできます。

延々と待たされます。すると、インストーラーから「許可が必要になった」みたいなメッセージが出てきて、やはり「システム環境設定」のセキュリティとプライバシーを見ると、カギを解除しないといけませんが、みたこともない「いくつかのシステムソフトウェアの読み込みがブロックされました。」といったメッセージが出ています。「許可」をクリックします。

すると、ブロックされたソフトウェアがリストアップされるので、チェックを入れてOKをクリックしました。

この後待たされたのですが、最後の最後でエラーでインストールできないと言われました。えー。もう一度やったら成功したので再起動したのですが、やはり認識してくれません。「システム情報」上は以前と同じのようです。アップデートされていないとしか思えないです。

次に試したのはアンインストールです。ドライバのインストーラに、.commandファイルであるので、説明に従ってインストールして動かし、再起動してインストールしたのですが、再起動後にドライバがもはや見えない状態になっていました。

インストーラの文書を見ると、それでもダメならSIPをオフにしろと書いてあります。手順に従って、Command+R起動、csrutil disable、再起動してインストールしましたが、再起動後、「システム情報」にドライバ情報が登場しません。やはりダメです。

と言うことで、ダメでした。ググったのですが、できたと言う人もいればダメだと言う人もいると言う状況です。何か手順がいるのかも知れませんけど、macOSは順調にシステムに手を入れることを困難にしてセキュリティ確保を画策している模様です。

SwiftUIのビューをUIViewControllerに配置する

Xcode 11.2.1が最新版です。ちょっと思い立って、SwiftUIの画面ショットが必要になり、おなじみのAppleのチュートリアルを開いてみました。あれ?すでにこの通りにならない。半年くらい前に動きの悪いXcodeで必死に追っかけたチュートリアルですが、数ヶ月でその通りでなくなっています。手順通り、プロジェクトを作成する時にiOSのSingle View Appを選択すれば、その次に「Swift UI」のチェックボックスがあるはずなのですが、なくなっています。

快技庵 高橋政明@houheiさんに指摘いただきましたが、User Interfaceのところで、Storyboardではなく、SwiftUIを選択すると、以前のSwiftUIのチェックボックスを選択したのと同じ状態のプロジェクトが作れます。(2019-12-8 21:20)

仕方ないので、そのまま進みます。作ったプロジェクトにはSwiftUIのファイルはありません。この先、SwiftUIのビューを定義するにはどうするかと言うと、FileメニューのNewからFileを選択するなどして、ファイルの追加を行い、SwiftUI Viewの項目を選択して新たにファイルを作ります。この方法でファイルを開いた時、右側にプレビューのCanvasが出ないなら、EditorメニューのCanvasのチェックが入っているかを確認してください。

これで、SwiftUIのビューのコードファイルが用意されているので、作り込んでいくことはできます。なお、現状のXcodeでも、Target Device(プロジェクトアイコンを選択し、アプリケーションを選択して、Generalを選んだところで指定できる)にMacを選択したら、プレビューは動かなくなります。残念!

さて、本題は、こうして作ったアプリケーションを実際にRunさせても真っ白な画面しか出てこないです。つまり、SwiftUIはXcode上のキャンバスでないと動かないわけです。ちなみに、Appleのチュートリアルで作ったものは、ちゃんとRunしても画面に出てくるようになっているのですが、このプロジェクトは、Storyboardは使っていません。SceneDelegateクラスの最初の方に、UIWindowを生成し、UIHostingControllerを生成して、SwiftUIのViewをルートにしています。今後もしかしたら、この手法がメジャーになるのかも知れませんが、今はやはりStoryboardを中心にして作りたいと思いますよね(色々な意見はあるとは思いますが…)。

上記のチュートリアルのコードを見る限りは、UIViewControllerを継承したUIHostingControllerを使えばなんとかなりそうです。あれこれやってみて、こうすれば動くことがわかりました。元々使われているビューコントローラのViewControllerクラスをこのように書き直します。SwiftUIのビューは、既定の名前であるSwiftUIViewのままにしてあります。

import SwiftUI

class ViewController: UIHostingController<SwiftUIView> {

    required init?(coder: NSCoder) {
        super.init(coder: coder, rootView: SwiftUIView())
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }
}

要するにUIHostingControllerを継承しますが、このクラスにはジェネリックが記述されているの、そこにはViewを記述します。しかし、Viewはプロトコルなので、生成可能なクラスか構造体の名前を書く必要があります。ここでは、SwiftUIViewをそのままビューコントローラーのルートにするとして、そのクラス名を記載しました。

これだけではダメで、UIHostingController関するAppleのドキュメントを睨みます。ここで、init?(coder:rootView:)をオーバーライドしてうまくいくかなとあれこれいじっていたら、Xcodeのメッセージで「init?(coder:)を実装して、そこでスーパークラスのinit?(coder:rootView:)を呼び出しなさい」というのに出会いめでたく上記のようなコードにたどり着きました。もちろん、この初期化メソッドはStoryboardの定義に従って生成した時に初期化のために自動的に呼び出されるものです。StoryboardでViewControllerをインスタンス化する時に呼び出すコードの中で、ルートビューのインスタンスを作ります。これで、Runしたアプリケーションで、SwiftUIのビューが動くようになりました。

Storyboardは最初の状態から特に変更はしていません。View Controllerの直下のViewに対するCustom Classの設定でSwiftUIViewクラスを選択できるようになっていれば、上記のようなことは不要なように思うのですが、まだ、Xcodeはそこまで開発は進んでない模様です。SwiftUIのViewは選択できませんし、無理にキータイプして入れてもエラーになってビルドができません。もちろん、Canvasに見えるプレビューは、Storyboardの中では見えません。もうちょい先、つまり、SwiftUIのプレビューをmacOSをターゲットに入れても動くようになってからなのかなと思ったり。

Storyboardの編集機能をいじっていたら、Hositing View Controllerと言うのがあるのに気付きました。しかしながら、メッセージを見ると、その中にいれるSwiftUI Viewについては、プログラムで記述しろとなっているので、このページに書いてある方法でSwiftUIのViewを追加するのが、Xcode 11での方法になります。やはり、Storyboard上ではまだ全ての作業はできないと言うことです。(2019-12-15 10:05)

Apple IDの2要素認証をいつまでも求められる場合の対処

ちょっと話題的には古いのかもしれませんが、Apple DeveloperのApple IDは2要素認証が必須になり、そのような警告メッセージが出ました。で、ある時から、2要素認証を「しないといけない」状況になりました。

そこで、appleid.apple.comで、2要素認証をオンにしてみたのですが、XcodeやDeveloperサイトでの状況は変わりませんでした。Xcodeでは署名のたびにパスワードを求められるのですが、それでも認証が通らなくなってきてなんとかしないといけなくなりました。appleid.apple.comで設定すればいいだけではないというのがポイントです。

で、どうすればいいかといえば、macOSのシステム環境設定にあるiCloudで、そのApple IDを入力します。しばらくすると、警告アイコンが出てきて、更新するみたいな内容のボタンが出てくるので、それをクリックしてしばらくすると、アカウントの情報が更新された模様です。そこまでくると、Xcodeでの認証が通るようになります。

多分、何かの具合で、appleid.apple.comでは更新ができない状態なのでしょうけど、iCloudで普段使っていないアカウントの場合、入力し直しになり、データが消えるみたいなメッセージに対処しないといけないわけですが、データはクラウドにあるので原則問題ないと思います。しかしながら、システム環境設定を変えるのは色々面倒と後の影響がきになるところですが、appleid.apple.comでダメだったら仕方ないので、iCloudでセットアップして、更新処理をmacOS側からやってください。

FileMaker Server 16のREST APIをmacOS上で試用する場合

FileMaker Server 16をまずは手元のMacにインストールして使ってみようという方も多いだろう。ここで、FileMaker Data API(REST API)を使用する場合にPHPのcurlライブラリを使うと、「SSL: CA certificate set, but certificate verification is disabled」というエラーメッセージが返ってくる。httpsでの通信が推奨され、証明書が検証できないと通信をしないということが当然となって来ているが、とはいえ、試用なので自己署名証明書で運用できないかとPHPの様々なパラメータを触ってみたところで、上記のエラーないしは別のエラーが出る。ということで、色々調べてみると、macOSに入っているopensslのバグで、サーバー検証をしないという設定ができないということらしい。homebrewから入れ直す方法など、色々紹介されているが、何をとっても大事になってしまう。

というところで、早速、FileMakerホスティングで有名なエミックの松尾さんが、ルータとなるスクリプトを公開された(一部、修正したい箇所があったので、筆者がフォークしたものもある)。FileMaker ServerのREST APIは、httpで接続してもhttpsにリダイレクトされるが、その背後のNode.jsが開いている3000ポートを目指して接続することで、httpでも処理が進められる。ただ、ヘッダをうまく使って同じホストからの接続しかできないような仕掛けがあるため、「直接3000番ポートに接続する」よりも、ルータスクリプトを使う方が楽である。

ルータは、WebアプリケーションとFileMaker Serverの中間に位置しており、WebアプリケーションがFileMaker ServerへのRESTコールを行う代わりに、ルーターに対して呼び出しを行う。ルーターはhttpsを使わずにFileMaker Serverを呼び出し結果を得て、それをWebアプリケーションに返す。動作としては「プロキシ」であるが、名前がrouterなので、ルーターと呼ぶことにする。

ルーターを利用できるようにするには、ダウンロードしたファイルrouter.phpを、以下のようなコマンドで起動する。ファイルがある場所をカレントディレクトリにして、コマンドを入力する。

php -S 127.0.0.1:8090 router.php

ここで、127.0.0.1は自分自身に接続するIPアドレスであり、コロンに続いてサーバーが利用するポート番号を指定する。他のプロセスが使っていない番号を使う必要がある。なお、使用を止めたい場合は、Terminalの画面でcontrol+Cキーを押す。

筆者が作ったAPIを利用するためのクラスFMDataAPIでルーターを利用したい場合、利用方法のサンプルを示したFMDataAPI_Sample.phpであれば、最初の方にあるインスタンス化している部分を記載のように修正する。パラメータを2つ追加して、8090ポートを使うことと、httpプロトコルを使うように設定すれば良い。他は変更が必要ない。もちろん、8090はルーターを起動する時に指定したポート番号を使う。IPアドレスも、基本的に起動時に設定したものを指定する。

修正前:
$fmdb = new FMDataAPI("TestDB", "web", "password", "127.0.0.1");

修正後:
$fmdb = new FMDataAPI("TestDB", "web", "password", "127.0.0.1", 8090, "http");

一方、FMDataAPITrialにあるスクリプトは、まず、lib.phpファイルにある以下の関数の返り値に、ルータ側のポート番号を指定する。

function targetHost()
{
    return "127.0.0.1:8090";
}

そして、Test2.php以降、プログラムの中のhttpsの記述をhttpに切り替える。callAPI関数の最初の引数が全てhttpsになっているので、httpに書き換える。

$host = targetHost();
$result = callAPI(
    "http://{$host}/fmi/rest/api/auth/TestDB",
    null,
    json_encode(array(
        "user" => "web",
        "password" => "password",
        "layout" => "person_layout",
    )),
    "POST");
resultOutput($result);

なお、phpコマンドで、router.phpを起動する時、127.0.0.1ではなく、localhostで指定した場合、上記の修正箇所のIPアドレスは、全てlocalhostで記述する。127.0.0.1では稼働しないので注意する必要がある。phpコマンドで起動する時に127.0.0.1を指定すると、Webアプリケーション側の設定は、127.0.0.1でもlocalhostでもどちらでも良いようだ。FileMaker Serverはかなり以前からIPv6ベースで動いているのだが、localhostとした場合、どこかで127.0.0.1ではないIPv6のアドレスとして識別しているのではないかと想像できるのだが、詳細は分からない。

ちなみに、FMDataAPIを使ったシステムを運用する時、原則としては正しい証明書でhttpsで運用することが原則だ。もちろん、盗聴されないためというのが大きな理由であるが、ホストを偽ってデータを収集されたり嘘の情報を流されることも防ぐ必要がある。httpsでの運用は、Let’s Encryptで無償で利用できるなど、年々手軽になってきているので、面倒がらずに対応すべきだというのが1つの結論である。

では、PHPを稼働させるWebサーバーとFileMaker Serverが同一のホストであれば、盗聴の心配はないのではないかと言うことになる。Firewallでポートを塞げば、それでいいのではないかと言う話もなくはない。ただ、FileMaker Data APIだけにWebサーバーを使うと言うことはあまりないと思われるので、Firewallの設定はちょっと面倒ではないだろうか。絶対に外部からFileMaker Data APIは利用しないで、サーバー内部に限るのであれば、httpでの運用でも問題はないかもしれないが、必ずサーバーの内部からの利用しかしないと言うことを管理者が人手で保証しないといけなくなる。通常、httpsで運用する手順を踏む方が楽なのではないだろうか。

自己署名証明書の問題も同様だ。サーバー内部に限るのなら、詐称のしようもないと考えることができる。これも、「絶対にサーバーの内部からの利用しかしないと言うことを管理者が人手で保証する」と言うモデルであり、むしろ、そういった人的な縛りよりもhttpsでの運用をする方が問題が発生しにく状況であると言えなくないだろうか?

そう言うことで、httpや自己署名証明書での運用は自己責任が大きいので、FileMaker Data APIでアプリケーションを開発したら、本番はhttpsでの運用を目指すようにすべきである。

なお、筆者の作ったFMDataAPIクラスは、デフォルトは証明書の検証をしない状態で稼働するので、そちらは開発中での利用を想定している。実際に正しい証明書が用意できれば、以下のメソッドを呼び出す。そうすれば、証明書の検証を行うようになる。自己署名でないこと、期限、アクセスしているサーバ名と同一なのかが検証される。

$fm->setCertValidating(true);

すなわち、FMDataAPIクラスは、証明書の検証もメソッドでコントロールできるようになっている。

Xcodeのビルド/バージョン番号をagvtoolで管理

Xcode 8にプロジェクトを変えたところで、あるプロジェクトで、PlistBuddyでバージョン番号をアップしていたのがあるのですが、スクリプトが引き継がれなくなったので、今風のやり方はないかと思って検索したら、agvtoolがあるなということで、使い方を考えてみました。Apple Generic Versioning Toolの略だそうです。ただ、いろいろ調べたり、結構詳しいmanを見て考えました。一番素直な使い方はどんなのだろうか?Xcodeのプロジェクト1つだけの場合と、別のプロジェクトを組み込んだ場合で考えて見ました。

使い方の前に、ここでいうVersioningとは、XcodeのプロジェクトのGeneralの設定にある「バージョン」と「ビルド」です。英語版しか今はないので画面通りに記述すると、IndentityのカテゴリにあるVersionとBuildです。

shot3250x

このうち、Finderで表示されるいわゆるバージョンはここのVersionですが、Buildは一般には参照できません。Finderのバージョン表記に出てくる場合もありますが、それはさらにこれらとは別のバージョン表記です。バージョンに関する情報はアプリケーションバンドルのInfo.plistに記述されますが、次のような関係にあります。

短いバージョン 長いバージョン ビルド番号
Finderの情報ウインドウ バージョン バージョン 非表示
Finderウインドウ内 バージョン 非表示 非表示
WebのApp Store
iOSでのApp Storeアプリ
バージョン  非表示  非表示
Xcodeでの設定 Version Info.plistに設定する Build
Info.plistのキー CFBundleShortVersionString CFBundleGetInfoString CFBundleVersion

Finderの情報ウインドウに見えるバージョンには、Info.plistに長いバージョンつまり、CFBundleGetInfoStringがあればそれを表示しなければ短いバージョンつまり、CFBundleShortVersionStringを表示します。Finderウインドウをカラム表示にした時に右端に表示されるアイコン下の属性は、常に短いバージョンつまりCFBundleShortVersionStringが表示されます。

一方、iOSについては、Web上のApp StoreやiOSでのApp Storeアプリで、短いバージョンすなわちCFBundleShortVersionStringが見えていますが、iTunesでは見えていません。

表の最初の3行は一般ユーザーの目に触れるところで、最後の2行はXcodeやInfo.plistの世界です。つまり、ここではCFBundleShortVersionStringがバージョンで、CFBundleVersionがビルドであるということを認識してください。どっちもキーのキーワードにVersionとあり、一見するとCFBundleVersionがバージョン番号のように思えてしまうところが引っかかるところかと思います。以下、「バージョン」と「ビルド」としてそれぞれの設定を参照します。

agvtoolを使う基本的な設定

プロジェクトのビルド設定にあるBuild Settingsには多数の設定項目があります。そこのVersioningのカテゴリを見てください。Versioning Systemの右側の値が入っているところをクリックすると、ポップアップニュが出てくるので、「Apple Generic」を選択します。まず、この設定を行います。

shot3249

それから、上の図にはありませんが、同じVersioningのカテゴリにあるCurrent Project Versionに何か数字を入れてください。この数字はビルド番号の初期値となります。キー名に「Version」とありますが、このキーはビルドの値をおぼえておくために使われています。なお、その他のキーを見るとPrefixやSuffixなどがあり、ビルド番号を構築する時にこれらの文字列を前後につけることができるようになっています。

他のプロジェクトを読み込んでいないプロジェクト

まず、単純なプロジェクト、つまり、他のプロジェクトを読み込んでいないようなプロジェクトを考えます。この場合、ターゲットは通常は1つであるので、アプリケーションのバージョンはそのターゲットを1箇所変えるだけです。そのために、わざわざコマンドを動かすよりかは、Xcodeの画面上で手作業で変えた方がいいでしょう。ということで、バージョンについては自動化の必要はないと考えました。

一方、ビルドの方は、本当にビルドをした時、あるいはProductメニューからArchiveを選んでアーカイブを作った時など、ある程度自動的に設定をしたいと考えるでしょう。そのためには、タイツルバーのプロジェクト名の見えている部分をクリックして、Edit Schemeを選択します。そして、左側のBuildやArchiveの設定に、以下のようなスクリプトを追加します。Edit Schemeを選択してシートが出てきます。BuildあるいはArchiveのPre-actionsないしはPost-actionsを選択します。おそらく、最初は何もないと思われます。シートの下にある「+」をクリックして、New Run Script Actionを選択すると、以下のような画面になります。ここで、2行のシェルスクリプトを入れると同時に、Provide build settings fromのところで、アプリケーションのターゲットを選択しておきます。

shot3259

cd "${PROJECT_DIR}"
agvtool next-version -all

これでCloseをクリックします。上記の場合だと、command+Bでビルドすると、ビルドの番号がアップするはずです。現在の番号は、Build SettingsにあるCurrent Project Versionの値を取り出してアップして、「ビルド」の枠に設定します。現在、ビルドの枠に見えている数字がアップするのではありません。ちなみに、このagvtoolは、プロジェクトのルートをカレントにして動くようになっており、引数でプロジェクトのディレクトリを設定するようになっていません。そこで、ビルド時に作成される環境変数のPROJECT_DIRを利用してカレントディレクトリを移動し、コマンドを入力しています。agvtoolの引数はプロジェクトや値に関わらず、常にこの通りです。

プロジェクトを読み込んでいるプロジェクト

プロジェクトを分けていて、あるプロジェクトで統合している場合、まず、ビルド番号は前に示したような方法で、各プロジェクトに設定するしかないと思われます。ビルドの数はプロジェクトごとに違うでしょうから、それはそれでいいかと思います。

一方、バージョンの方は、以下のように一気にまとめて設定ができるようになっています。統合したプロジェクトのディレクトリをカレントにして、「agvtool new-marketing-version」に続いてバージョン番号を指定します。このマーケティングバージョンというのが、「バージョン」になるということです。

 

$ agvtool new-marketing-version 5.1
Setting CFBundleShortVersionString of project DLS to: 
    5.1.

Updating CFBundleShortVersionString in Info.plist(s)...

Updated CFBundleShortVersionString in "DLS.xcodeproj/../DLSTests/Info.plist" to 5.1
Updated CFBundleShortVersionString in "DLS.xcodeproj/../DLSUITests/Info.plist" to 5.1
Updated CFBundleShortVersionString in "DLS.xcodeproj/../DLS/Info.plist" to 5.1
Updated CFBundleShortVersionString in "DLS.xcodeproj/../Installer/Info.plist" to 5.1
Updated CFBundleShortVersionString in "DLS.xcodeproj/../Utility/Info.plist" to 5.1

ここで、読み込んでいるプロジェクトのInfo.plistも設定されることをメッセージで確認しましょう。

ただ、いくつか試してみた限りでは、読み込んだプロジェクト側にバージョン番号が反映される場合と反映されない場合がありました。以前から読み込みをしてあったプロジェクトは全てに反映されるのに、新たに作ったプロジェクトはだめでした。また、agvtool next-version -allの呼び出しをPre-actionsに設定すると、読み込み側のプロジェクトのビルドがキャンセルされることも見られたので、その場合はPost-actions側に設定することでビルドは全部流れるようになりました。

この辺りは、理由が分かれば追記しようと思います。

何れにしても、agvtoolのパラーメータは多数ありますが、ここで紹介したように、next-versionのものをプロジェクトにスクリプトとして仕組むことと、バージョンの設定のためにnew-marcketing-versionを使うことで概ねのことは賄えると思います。まずはこの線から始めてみてはどうでしょうか?

FileMaker Serverのアンインストール

FileMaker Serverをどうしてもアンインストールしたい場合があります。インストーラが「先にアンインストールしないといけません」とメッセージを表示して、それ以上進めないとなると、仕方ありません。インストーラのExtraフォルダに前のバージョンのアンインストーラがありますが、こんな場所にも、現在インストールされているFileMaker Serverのアンインストーラがあることを知っていれば、便利かもしれません。

shot3216

ディスクのルートから、ライブラリ>Application Support>FileMaker>FileMaker Serverという場所にも、アンインストーラがあります。ご参考までに。

FileMaker Serverのアップデータがフリーズする理由

FileMaker Server 14.0.4bのアップデータがリリースされました。このところ、アップデートが頻繁にありますが、いざアップデートしようとすると、最初の部分でフリーズしてしまうことがあります。フリーズと言っても、マウスカーソルがレインボーになってしまう現象です(画面ショットではレインボー状態は撮影できないので、以下の図は普通のポインタになっています)。

shot3215

ちなみに、この現象は、14.0.4bのアップデータに限らず、13のアップデータでも発生することがあります。もちろん、いつまで経ってもこのまま進みません。さて、なんででしょうか? アクティビティモニタを見ると、パッチアプリケーションのCPU稼働率が100%近くになっています。ということは、本当にフリーズか、適切でない処理待ちをしていることが考えられます。

そこで、ターミナルを起動して、プロセスを見てみます。パッチアプリケーションのプロセスには「Patch」という特徴的な文字があります。以下のコマンドで、プロセスIDは27530だとわかります。(以下、コマンドラインの出力が長いので折り返して見えるようにしておきますが、見づらい点はご容赦ください。)

$ ps jax|grep Patch
root 27530 1 27523 0 0 S ?? 0:15.60 /Volumes/FileMaker Server 14.0.4b Patch 1/FileMaker Server 14.0.4b Patch.app/Contents/MacOS/FileMaker Server 14.0.4b Patch

次に、このプロセスが別のプロセスを起動していないかをチェックします。すると、以下のように、「/bin/sh /Users/msyk/Library/Application Support/1358455 0」なるプロセスがあります。最後の方の数値は起動ごとに違うものがつけられ、正常終了すると消されているファイルです。

$ ps jax|grep 27530
root 27530 1 27523 0 0 S ?? 0:15.60 /Volumes/FileMaker Server 14.0.4b Patch 1/FileMaker Server 14.0.4b Patch.app/Contents/MacOS/FileMaker Server 14.0.4b Patch
root 27545 27530 27523 0 0 S ?? 0:00.05 /bin/sh /Users/msyk/Library/Application Support/1358455 0

これは/bin/shつまり引数をシェルスクリプトとして実行しているということです。catコマンドで、ファイルパスにスペースがあるのでダブルクォートで囲むなどの対処をして、中身を読んでみます。パッチアプリケーションは、このプロセスが終了するのを、おそらく単なるループで待っているためにフリーズするのでしょう。psコマンドである種のプロセスが存在するかどうかを2秒ごとにチェックし、調べているプロセスがなくなれば、スクリプトを終了します。

$ cat “/Users/msyk/Library/Application Support/1358455”
#!/bin/sh

cd /Library/Application\ Support/FileMaker/FileMaker\ Server
./launcher -stop

while [ “`ps auwwx | grep -e fmserver_helperd -e fmsib -e fmslogtrimmer -e fmxdbc_listener -e fmsased -e httpd | grep -v grep`” ] ; do
sleep 2
done

whileの行を見ると、psコマンドの結果に、fmserver_helperd、fmsib、fmslogtrimmer、fmxdbc_listener、fmsasedという文字列があるかを調べています。つまり、FileMaker Serverの様々なプロセスが起動した状態なのかを調べています。さらに、httpdというプロセスまで存在するかを調べています。アップデートは、FileMaker Serverを停止させて行うようにということで、FileMaker関連のプロセスがなくなっているという条件はまあいいでしょう。ちなみに、FileMaker Serverのプロセスを事前に全部止めておくには、以下のコマンドでできます。

sudo launchctl unload /Library/LaunchDaemons/com.filemaker.fms.plist

しかし、httpdとなると、何らかのきっかけで動かしてしまっているかもしれません。あ!そういえば、Server.appで色々試したぞと思ってチェックすると、Server.appのソフトウエアアップデート、キャッシュ、Xcode Serverあたりがhttpを使っていました。しかし、Server.appは、それらのプロセスをオフにしても、httpdの稼働を止めません。仕方ないので、sudo launchctl unload <plistファイル>で順次落として、やっとFileMaker Serverのアップデータが動くようになりました。ちなみに、こうしたデーモンは、launchctlで起動しているので、killしてもすぐに再起動されます。そこで、/System/Library/LaunchDaemonsや、/Library/LaunchDaemonsに該当するファイルを探すわけですが、Server.appについては、/Applications/Server.app/Contents/ServerRoot以下の、/System/Library/LaunchDaemonsや、/Library/LaunchDaemonsにあるplistファイルを利用してデーモンを起動しています。これらのファイルから該当するhttpdを起動しているものを探して落とさないといけません。チェックすべきplistファイルのある場所は文中に記載しましたが、見づらいでしょうから以下に列挙します。

/System/Library/LaunchDaemons
/Library/LaunchDaemons
/Applications/Server.app/Contents/ServerRoot/System/Library/LaunchDaemons
/Applications/Server.app/Contents/ServerRoot/Library/LaunchDaemons

しかし、一番の問題は、「httpdが起動していたらアップデートをしない」という仕様です。つまり、結果的にFileMaker Server以外のhttpdの起動を許さないという仕様に問題があります。Server.app自体が色々なサービスでhttpdを使うのですが、80番ポートの取り合いになるのは確かにまずいでしょう。しかしながら、FileMaker Serverのインストーラーは、自分自身のhttpdのポート番号を指定することで、他のサービスとの同居の可能性を探っています。しかし、このスクリプトを見る限りは、「FileMaker Serverが起動したhttpd」ではなく、単に「名前がhttpd」のプロセスを探しているにすぎません。つまり、FileMaker Server以外でhttpdを使いっていればトラブルが発生する仕様なのです。これでは仕様の上で矛盾があると言えるでしょう。

もちろん、特定のサーバーではFileMaker Serverしか動かさないという前提でもそれはそれで構わないと思いますが、だったら、LinuxのVMで動かすようにして欲しいというのが総意ではないでしょうか。OS XとWindowsで、アプリケーションみたいなインストーラでセットアップするサーバーはもはや古さを感じます。現在のシステム構築環境にマッチしない仕様を早く改善しないと、先頭集団からさらに引き離されるでしょう。

El Capitanのイチオシ機能はSplit View

年中行事となったOS Xのアップグレードですが、それだけに「大した違いはない」という感想を持ってしまいがちです。しかしながら、2015年10月リリースのEl Capitan(OS X 10.11)のSplit Viewはとても注目できる機能です。一部のiPadでiOS 9により実現していた機能なので、iOSの方が少し先になりましたが、複数のアプリケーションを使い分けるMacでこそ真価が発揮できそうな注目の機能です。

要するにこんなことができます。画面全体に表示されている感じを示すために、画面ショットに外枠も追加してみました。

右は編集中の原稿をJeditで見ているところです。左側はそれをブラウザのChromeで見ているところです。画面にはこの2つのアプリケーションの画面があるだけで、他のアプリケーションはありません。右で入力や変更をして保存、左側をクリックして更新とある程度の操作は必要ですが、ウインドウの大きさは固定であり、スクリールをするだけで、位置を調整したりということしなくても、2つのアプリケーションを並行して快適に利用できます。

shot0001f

こちらは、左がで開発ツールのPHPStromを使い、右側のブラウザ(Chrome)で実行しながらデバッグするという状況です。どちらのアプリケーションもさらにペインに分割されて多数のペインになっていますが、こういう作業でウインドウの前後関係を気にしないで作業できるのは非常に快適です。

shot0002f

使用方法は次の通りです。まず、利用したいウインドウを2つあらかじめ用意しておきます。そして、3本指でトラックパッドを画面方向にスワイプするMission Controlを利用します。すべてのウインドウが画面いっぱいに重ならないように表示されます。そして、1つのウインドウを画面上の「デスクトップ1」などと見えているデスクトップが並ぶ箇所(背景画像がボケて見える箇所)にドラッグします。何もないところにドラッグします。以下の図ではグラフィックス表示していますが、最初は文字のみです。マウスポインタを画面の上の方に移動させれば、グラフィックスも表示されます。

shot2695

デスクトップと同じ大きさのグレーのボックスが表示されます。これが出ることを確認してからトラックパッドの押し込みを放すなどして、ドラッグを終了します。

shot2696

すると次の図のように、もう1つデスクトップが確保されますが、アプリケーション(この場合PHPStorm)が最大化された状態で追加されます。

shot2697

続いて別のウインドウを先ほど新たに作ったデスクトップの上の右半分(あるいは左半分)のあたりにドラッグして追加します。追加される場所が濃いグレーで応答しますので、ドラッグを終了する前に、画面の状況を確認しながら作業をしましょう。

shot2698

こうすれば、2画面に分割したデスクトップが1つ確保されます。Mission Controlの画面でクリックして切り替えてもいいですが、2本指で左右にスワイプして、デスクトップを切り替える方が、快適に切り替わるでしょう。アプリケーションの境界線をドラッグして、左右に移動することもできます。ディスプレイが複数台あれば、それぞれのディスプレイで、内容の異なるSplit Viewを構成することもできます。ちなみに3つのウインドウまではできません。同一アプリケーションの2つのウインドウであれば、Split Viewで表示できます。

Macだと複数のアプリケーションを行き来することはよく行います。マルチウインドウシステムはそうした作業に適合するとはいえ、たくさんのウインドウが折り重なるデスクトップは混乱の元です。切り替わるべきウインドが前面に来るはずが、全然違うウインドウが出てきてがっかりすることも多々あります。作業の上で「それぞれのウインドウを見る」となると、今まではウインドウの位置や大きさをユーザーが調整していたのですが、そういう使い方ではマルチウインドウよりスプリット形式に表示する方が見やすく効率がいいのは、多くのアプリケーションで実証されています。そして、その仕組みをOSがサポートすることで、アプリケーションを超えて1つの画面に集約できる機能がやっと使えるようになったということです。Split ViewはiOSの系譜があるとはいえ、Macにとっては新しいインタフェースを加えるものであり注目できる機能と言えるでしょう。