PHP で JSON を出力する

保守しているサーバーの PHP は、なんとバージョン 5.2.2 という生きる化石のようなシロモノでした。
一応 json_encode 関数はあるのですが、JSON_PRITTY_PRINT や JSON_UNESCAPED_UNICODE オプションが使えないため、とても人間が読みやすいものは出力できません。

じゃあ、どうしようか?
まぁ1時間ぐらいで自作出来るんじゃないの?

と、作ったわずか40行程の関数です。

よかったら使って下さい。

function json_print( $data, $indent=0, $next='' ) {
	if ( ! is_array( $data ) ) {
		if ( is_bool( $data ) ) {
			printf( "%s%s\n", $data ? 'true': 'false', $next );
			return;
		}

		if ( is_numeric( $data ) ) {
			printf( "%s%s\n", $data, $next );
			return;
		}

		printf( "\"%s\"%s\n", preg_replace( '/\\n/', '\\n', preg_replace( '/"/', '\\"', $data ) ), $next );
		return;
	}

	if ( array_values( $data ) === $data ) {
		printf( "[\n" );

		for ( $n = 0; $n < count( $data ); $n++ ) {
			printf( str_repeat( ' ', ( $indent  + 1 ) * 4 ) );
			json_print( $val, $indent + 1, ( $n == ( count( $data ) - 1 ) ) ? '' : ',' );
		}

		printf( "%s]%s\n", str_repeat( ' ', $indent * 4 ), $next );
		return;
	}

	printf( "{\n", str_repeat( ' ', $indent * 4 ) );

	$keys = array_keys( $data );

	for ( $n = 0; $n < count( $keys ); $n++ ) {
		printf( "%s\"%s\" : ", str_repeat( ' ', ( $indent  + 1 ) * 4 ), $keys[ $n ] );
		json_print( $data[ $keys[ $n ] ], $indent + 1, ( $n == ( count( $keys ) - 1 ) ) ? '' : ',' );
	}

	printf( "%s}%s\n", str_repeat( ' ', $indent * 4 ), $next );
}

使い方はこれだけです。

json_print( $data );

Xubuntu 16.04 + xrdp 0.9.1-7 + VS Code 1.11 でカーソルキーが使えなかった対応

Xubuntu 16.04 + xrdp 0.9.1-7 に、Windows のリモートデスクトップでログインして VS Code を使っていたのですが、1.11 にアップデートしたところ、カーソルキーが使えませんでした。

ほぼ常に使用しているので、すごく焦りました。
とりあえずは 1.10 にダウングレードすることで対応できました。

その後調べた結果、リモートデスクトップの場合に発生する現象であることが判明し、VS Code の設定に以下を追加して対応できました。

"keyboard.dispatch": "keyCode"

助かりました。

参考 : Delete, Insert, Home, End, PgUp, PgDn, and arrow keys no longer work editor in 1.11 #24107

Xubuntu 16.04 で xrdp_0.9.1-6 をビルドした

Ubuntu 17.04 向けの xrdp パッケージが 0.9.1-4 から 0.9.1-6 へ更新されていたので、16.04 向けにビルドしてみました。

sudo apt-get install build-essential devscripts
mkdir build
cd build/
dget -u https://launchpad.net/ubuntu/+archive/primary/+files/xrdp_0.9.1-6.dsc
cd xrdp-0.9.1/
vi debian/control
- devhelper (>= 10),
+ devhelper (>= 9.2),
dpkg-buildpackage -r -uc -b
cd ..
sudo dpkg -i xrdp_0.9.1-6_amd64.deb xorgxrdp_0.9.1-6_amd64.deb

これで大丈夫でした。
システムを reboot しても大丈夫。
ついでに日本語キーボードが正しく検出されない問題も解決していました。

Ubuntu 16.04 で xrdp_0.9.1-4 をビルドした

Ubuntu 17.04 向けの xrdp パッケージの更新が行われていたので、16.04 向けにビルドしてみました。

sudo apt-get install build-essential devscripts
mkdir build
cd build/
dget -u https://launchpad.net/ubuntu/+archive/primary/+files/xrdp_0.9.1-4.dsc
cd xrdp-0.9.1/
vi debian/control
- devhelper (>= 10),
+ devhelper (>= 9.2),
dpkg-buildpackage -r -uc -b
cd ..
sudo dpkg -i xrdp_0.9.1-4_amd64.deb xorgxrdp_0.9.1-4_amd64.deb
sudo systemctl restart xrdp.service

これで大丈夫かと思ったのですが、システムを reboot すると xrdp が起動されていませんでした。
サービスを起動しようとするとエラーが発生していました。

Feb  2 01:16:17 taniguchi-home systemd[1]: Failed to start xrdp session manager.
Feb  2 01:16:17 taniguchi-home systemd[1]: Dependency failed for xrdp daemon.
Feb  2 01:16:17 taniguchi-home systemd[1]: xrdp.service: Job xrdp.service/start failed with result 'dependency'.
Feb  2 01:16:17 taniguchi-home systemd[1]: xrdp-sesman.service: Unit entered failed state.
Feb  2 01:16:17 taniguchi-home systemd[1]: xrdp-sesman.service: Failed with result 'resources'.
Feb  2 01:16:24 taniguchi-home systemd[1]: Stopped xrdp daemon.

調べてみたところ、/lib/systemd/system/xrdp.service に以下が追加されていたため、先に xrdp-sesman を起動しようとします。

Requires=xrdp-sesman.service
After=network.target xrdp-sesman.service

しかし、再起動時に xrdp-sesman を実行する時点では /run/xrdp/ が存在しないため、起動できません。
結局、以下の2行を /lib/systemd/system/xrdp.service から /lib/systemd/system/xrdp-sesman.service へ移動しました。

PermissionsStartOnly=true
ExecStartPre=/bin/sh /usr/share/xrdp/socksetup

これで大丈夫かと思ったのですが、再起動してみると xrdp が立ち上がっていません。
なぜか以下のコマンドの実行も必要でした。

sudo systemctl enable xrdp.service
sudo systemctl enable xrdp-sesman.service
sudo systemctl start xrdp.service

なんか、パッケージのテストが不十分で残念ですね。

xrdp の devel ブランチをビルドする

X11RDP-o-Matic を使って xrdp の devel ブランチをビルドしようとしましたが、エラーでビルド出来ません。
色々調べたけどわからず、github で質問してみました。

Can not build XRDP debel branch.

自作の rootless ブランチを使ったら出来るよーとの事だったので、やってみたけどエラー。
再度質問してみました。

Can not build XRDP debel branch. — metalefty/X11RDP-o-Matic rootless branch.

“–branch devel” オプションが抜けてたらしい。ありがとー。

以下の手順で成功しました。

$ git clone --depth 1 -b rootless https://github.com/metalefty/X11RDP-o-Matic.git
$ cd X11RDP-o-Matic/
$ ./X11rdp-o-matic.sh --branch devel --justdoit

Raspberry Pi 3 Model B で 5GHz の Wi-Fi を使う

Raspberry Pi 3 Model B ネタです。

電源さえあれば使えるように無線 LAN を使いたいのですが、残念ながら内蔵無線 LAN は 2.4GHz のみで 5GHz が使えません。
我が家では電子レンジや付近の干渉が多いため、5GHz じゃないと使いものになりません。
このため、以前購入していた ELECOM WDC-433DU2HBK を使うことにしました。

まず、ネットで検索してみると WDC-433DU2HBK のチップセットは RTL8811AU らしいのですが、Raspberry Pi の標準のカーネルモジュールには含まれていないようです。RTL8812AU 用のモジュールで対応できるようです。

通常の Xubuntu であれば、linux-headers をインストールすれば、簡単にモジュールをビルドするためのファイルがインストールできるのですが、Raspberry Pi ではちょっと手間をかける必要があるようです。

参考 : カーネルモジュールのコンパイル – RTL8812AUとMT7610U (Raspberry Pi) [メモ]
参考 : Ubuntu 16.04 LTSで、BUFFALO WI-U3-866D を使う

最新のファームウェアとカーネルに更新

$ sudo apt-get update; sudo apt-get upgrade -y
$ sudo apt-get install -y rpi-update
$ sudo rpi-update
$ sudo reboot

カーネルソースを取得

$ sudo apt-get install curl build-essential bc git
$ FIRMWARE_REV=`cat /boot/.firmware_revision`
$ KERNEL_REV=`curl -L https://github.com/Hexxeh/rpi-firmware/raw/${FIRMWARE_REV}/git_hash`
$ echo Firmware Rev: ${FIRMWARE_REV}
$ echo kernel Rev  : ${KERNEL_REV}
$ curl -L https://github.com/Hexxeh/rpi-firmware/raw/${FIRMWARE_REV}/Module.symvers >Module.symvers
$ curl -L https://github.com/Hexxeh/rpi-firmware/raw/${FIRMWARE_REV}/Module7.symvers >Module7.symvers
$ curl -L https://github.com/raspberrypi/linux/archive/${KERNEL_REV}.tar.gz >rpi-linux.tar.gz
$ sudo -s
# HOME=$(pwd)
# cd /usr/src
# mkdir rpi-linux
# cd rpi-linux
# tar --strip-components 1 -xf ${HOME}/rpi-linux.tar.gz
# modprobe configs
# gunzip -c /proc/config.gz >.config
# cp $HOME/Module7.symvers Module.symvers
# time make modules_prepare
# ln -sv /usr/src/rpi-linux /lib/modules/$(uname -r)/build

モジュールをビルド・インストール

# cd /usr/src
# git clone https://github.com/gnab/rtl8812au.git
# cd rtl8812au/
# sed -i 's/\(CONFIG_PLATFORM_I386_PC = \)y/\1n/' Makefile
# sed -i 's/\(CONFIG_PLATFORM_ARM_RPI = \)n/\1y/' Makefile
# make
# make install
# echo 8812au> /etc/modules-load.d/8812au.conf
# echo "options 8192cu rtw_power_mgnt=0 rtw_enusbss=1 rtw_ips_mode=1"> /etc/modprobe.d/8812au.conf
# reboot

PHP の isset() と array_key_exists()

以下の様な変数で、入力値の初期値を設定しようとしました。

var $field = array(
    array( "name" => "date", "input" => "text", "default" => null )
);

$field[ $n ][ ‘default’ ] が設定されていたら初期値として使おうとしたのですが、isset( $field[ $n ][ “default” ] ) とすると、null が設定されている場合に false となってしまいます。
色々調べたのですが、こういう場合は array_key_exists( $field[ $n ][ “default” ] ) とすれば良いようです。

XRDP で「変換」キーが入力できるように対応した — その後

前の記事の「XRDP で「変換」キーが入力できるように対応した」では、キーボードレイアウトのデータを変更して対応しました。
ですが、恒久的に対応するには xkeyboard-config に修正をマージしてもらう必要があります。
さて、どうしようかなと考えていたのですが、なんとバージョン 2.11.1 から対応済みであることが判明しました。
xkeyboard-config 2.12 でビルドした /usr/share/X11/xkb 以下をコピーしても大丈夫と思われます。

Ubuntu 16.04 では xkb-data 2.16 ですので、次の LTS では何もしなくても大丈夫です。

XRDP で「変換」キーが入力できるように対応した

※ 「XRDP で「変換」キーが入力できるように対応した — その後」へ続きます。

あきらは Xubuntu 14.04 に X11RDP-o-Matic で XRDP 導入して Windows 10 のリモートデスクトップ接続で操作しています。

Microsoft の RDCMan だと、リモートデスクトップ接続で高 DPI 環境に対応できそうだとの情報を掴んだので、Surface Pro 3 で試したところ、表示は対応出来たのですが、「変換キー」が入力できませんでした。自分は漢字入力を Mac 風のキーバインドにしているため、変換・無変換キーが使えないと不便でしかたありません。

2日ほど色々調べて、設定ファイルを修正するだけで対応できることが判明しました。
原因は xkeyboard の base ルールの pc105 で、XF86AudioMedia が Henkan を上書きしてしまう事でした。
現在では evdev ルールが主流で、そちらでは同様の問題は無いため何年も放置されているようです。

以下、X11RDP-o-Matic で XRDP を導入している場合の修正内容です。その他の方は参考にして下さい。

/etc/xrdp/xrdp_keyboard.ini

--- xrdp_keyboard.ini.orig	2016-06-24 17:51:44.169447686 +0900
+++ xrdp_keyboard.ini	2016-06-24 07:44:47.317894018 +0900
@@ -98,7 +98,6 @@ layouts_map=rdp_layouts_map_mac
 [rdp_keyboard_jp]
 keyboard_type=7
 keyboard_subtype=2
-model=jp106
 rdp_layouts=default_rdp_layouts
 layouts_map=default_layouts_map
 

/usr/share/X11/xkb/rules/base

--- base.orig	2016-06-24 02:17:08.041738858 +0900
+++ base	2016-06-24 02:02:05.621268995 +0900
@@ -954,13 +954,16 @@
   tm2030USB-106 =       +inet(media_nav_acpi_common)
   trust_slimline =      +inet(media_nav_acpi_common)
   vsonku306     =       +inet(microsoftprooem)
-  $inetkbds     =       +inet(%m)
   $maclaptop    =       +inet(apple)+level3(enter_switch)
   $applealu     =       +inet(apple)
   $macs	        =       +inet(apple)
   sun_type7_jp_usb	=	+sun_vndr/solaris(defaults_type7jp)
   $sun			=		+sun_vndr/solaris(defaults)
 
+! model		layout		=	symbols
+  $inetkbds     jp              =       +inet(jp109)
+  $inetkbds     *               =       +inet(%m)
+
 ! layout	variant		=	compat
   de		neo			=	+caps(caps_lock)+misc(assign_shift_left_action)+level5(level5_lock)
   jp        $sun_compat =   complete+japan(kana_lock)

/usr/share/X11/xkb/symbols/inet

--- inet.orig	2016-06-24 16:47:59.730480262 +0900
+++ inet	2016-06-24 07:49:02.387162449 +0900
@@ -1846,6 +1846,12 @@ xkb_symbols "pc105" {
     include "inet(media_nav_acpi_common)"
 };
 
+partial alphanumeric_keys
+xkb_symbols "jp109" {
+    include "inet(media_nav_acpi_common)"
+    key  { [ Henkan ] };
+};
+
 //Intelligent Keyboard K04
 partial alphanumeric_keys
 xkb_symbols "intelligent_keyboard_k04" {

/opt/X11rdp/share/X11/xkb/rules/base

--- base.orig	2016-06-24 02:13:19.832611586 +0900
+++ base	2016-06-24 07:50:04.619465134 +0900
@@ -1012,11 +1012,14 @@
   tm2030USB-106 =       +inet(media_nav_acpi_common)
   trust_slimline =      +inet(media_nav_acpi_common)
   vsonku306     =       +inet(microsoftprooem)
-  $inetkbds     =       +inet(%m)
   $maclaptop    =       +inet(apple)+level3(enter_switch)
   $applealu     =       +inet(apple)
   $macs	        =       +inet(apple)
 
+! model		layout		=	symbols
+  $inetkbds     jp              =       +inet(jp109)
+  $inetkbds     *               =       +inet(%m)
+
 ! layout	variant		=	compat
   de		neo			=	+caps(caps_lock)+misc(assign_shift_left_action)+level5(level5_lock)
 

/opt/X11rdp/share/X11/xkb/symbols/inet

--- inet.orig	2016-06-24 02:14:02.548823251 +0900
+++ inet	2016-06-24 00:36:19.415751019 +0900
@@ -1825,3 +1825,9 @@ partial alphanumeric_keys
 xkb_symbols "pc105" {
     include "inet(media_nav_acpi_common)"
 };
+
+partial alphanumeric_keys
+xkb_symbols "jp109" {
+    include "inet(media_nav_acpi_common)"
+    key  { [ Henkan ] };
+};

※ 「XRDP で「変換」キーが入力できるように対応した — その後」へ続きます。