PHP strftime() のwindows サポート

PHPドキュメント内に、標記関数の全formatパラメータのサポート状況を調査するような事例が記載されています。
これを、windows7 xampp(PHP 5.6.30) とレンタルサーバ(lolipop php:5.4.45)の双方で実行してみた。

format lolipop windows
‘%’
‘A’
‘a’
‘B’
‘b’
‘C’ ×
‘c’
‘D’ ×
‘d’
‘E’ ×
‘e’ ×
‘F’ ×
‘f’ ×
‘G’ ×
‘g’ ×
‘h’ ×
‘H’
‘i’ ×
‘I’
‘J’ ×
‘j’
‘K’ ×
‘k’ ×
‘L’ ×
‘l’ ×
‘M’
‘m’
‘N’ ×
‘n’ ×
‘O’ ×
‘o’ ×
‘P’ ×
‘p’
‘Q’ ×
‘q’ ×
‘R’ ×
‘r’ ×
‘s’ ×
‘S’
‘T’ ×
‘t’ ×
‘u’ ×
‘U’
‘V’ ×
‘v’ ×
‘W’
‘w’
‘X’
‘x’
‘Y’
‘y’
‘Z’
‘z’

○:Known format
×:Unknown format

この他、’z’(タイムゾーンオフセット)と’Z’(タイムゾーン略称)の戻り値が
不正(?)のため、文字化けのような値が表示されるようなものもあります。

以上から、windowsでは未実装な部分が意外に多いことが分かりました。

PHP ISO-8601 週番号

PHPの日付関数をちらちら調べていたところ、標記の問題に直面した。
問題個所は、strftimeformatパラメータ内”%V”の
説明文です。この文を引用してみると、
「ISO-8601:1988 で規定された、指定した年の週番号。週の開始日は月曜日で、第1週は少なくとも4日はあることになる」
文の前段に問題はないが、後段がどうしても理解できない。
週の開始日は月曜日」とすると、何故「第1週は少なくとも4日はある」となるのか?
意地の悪い意見を言わせてもらえば、「第1週に限らず、週は常に7日に決まっている」はずです。

原文は、次の通り。
「ISO-8601:1988 week number of the given year, starting with the first week of the year with at least 4 weekdays, with Monday being the start of the week」
英語は苦手なので、Googleさんに翻訳してもらいました。
「ISO-8601:特定の年の1988年の週番号。少なくとも週4日の週の最初の週から始まり、月曜日は週の開始日」
いろいろ怪しい部分もありますが、こちらの方が表現的には正しいのではないか?
言葉で表現すると難しいので、表にして説明してみる。

ケース
1 1日 2日 3日 4日 5日 6日 7日
2 1日 2日 3日 4日 5日 6日
3 1日 2日 3日 4日 5日
4 1日 2日 3日 4日
5 1日 2日 3日
6 1日 2日
7 1日

「週4日」とは、年初からの日数で、週内に4日以上ある最初の週が、その年の第1週に
成るということです。つまり、上の表でいうと
(1)ケース1~ケース4:その年の第1週
(2)ケース5~ケース7:前年の第53週
ということになります。

PHPのドキュメントは、誰もが認める素晴らしいものです。
批判するつもりでこれを書いたのではなく、コンタクト方法が分からないので
関係者が偶然これを見て修正して戴ければとの思いで公開するものです。ご了承願います。

phpでhtml要素の一部を取得する

phpのDOMを使用してhtml要素(<tag>~</tag>)を取得するのが意外と難しい。
tagNameやnodeValueの取出し方は、多くの事例があるので探せば直ぐに見つかるのだが
タグそのものを表示する例はほとんど皆無に近い。

キーワードをいろいろ変えながら探した結果が次のもの。

この解決策は、DOMElement クラス内の
「User Contributed Notes」にある「63」と「15」がヒントになる。
例を見た方が手っ取り早いので、下に例を示す。

(1) サンプルとして次の sample.html を使用する

<!DOCTYPE html>
<html lang="ja">
<head>
<title>テストデータ</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<h1>テストデータ</h1>
<p>&lt;table> の全要素を表示します。</p>
<table id="test" class="table">
	<tr class="tr"><th>Header1</th><th>Header2</th></tr>
	<tr><td class="td">Data1</td><td>Data2</td></td>
</table>
<div id="main">
	<p>test1</p>
	<p>test2</p>
	<a href="*">Link1</a>
	<div id="sub">
		<p>sub1</p>
		<p>sub2</p>
	</div>
</div>
</body>
</html>

(2) table内の全要素を取得する場合

<?php
header("Content-Type: text/html; charset=UTF-8");
// innerHTML形式で要素を出力する例
// 結果は「ページのソース」で確認のこと
function DOMinnerHTML(DOMNode $element) { 
    $innerHTML = ""; 
    $children  = $element->childNodes;

    foreach ($children as $child) 
    { 
        $innerHTML .= $element->ownerDocument->saveHTML($child);
    }

    return $innerHTML; 
}

$dom= new DOMDocument(); 
$html = "sample.html";
@$dom->loadHTMLFile($html);
// xpathを使用しない場合
//$domTables = $dom->getElementsByTagName("table"); 
$xpath = new DOMXpath($dom);
$domTables = $xpath->query("//table");
if (!is_null($domTables)) {
	// Iterate over DOMNodeList (Implements Traversable)
	foreach ($domTables as $table){ 
		echo DOMinnerHTML($table); 
	} 
}else{
	echo "一致するデータがありません!";
}
?>

(3)id=”main”であるdiv要素内の全要素を取得する

<?php
header("Content-Type: text/html; charset=UTF-8");
// innerHTML形式で要素を出力する例
// 結果は「ページのソース」で確認のこと
function DOMinnerHTML(DOMNode $element) { 
    $innerHTML = ""; 
    $children  = $element->childNodes;

    foreach ($children as $child) 
    { 
        $innerHTML .= $element->ownerDocument->saveHTML($child);
    }

    return $innerHTML; 
}

$dom= new DOMDocument(); 
$html = "sample.html";
@$dom->loadHTMLFile($html);
$xpath = new DOMXpath($dom);
$domTables = $xpath->query("//div[@id='main']");
if (!is_null($domTables)) {
	// Iterate over DOMNodeList (Implements Traversable)
	foreach ($domTables as $table){ 
		echo DOMinnerHTML($table); 
	} 
}else{
	echo "一致するデータがありません!";
}
?>

(注)結果は、ブラウザの画面を右クリックして、「ページのソースを表示」(Firefoxの場合)で確認してください。

xamppへのXdebugのインストールと設定

諸般の都合でXdebugが必要になった。
インストールしようと、いろいろググってみると
大半の情報が、\xampp\php\extにxdebug.dllが存在し
php.iniにもその指定がコメントで記述してあること
を前提としたもの。
つい最近、phpを5.6.30にv-upした所為なのだろうか、
私の環境にはそれが無いし、
php.iniにもそのような記述がない。

とは言え、あちこち調べて朧げに分かったことは、
Xdebugのインストールとは、次の内容の作業ことを
言うらしいとのこと。
(1)Xdebugをダウンロードする。
(2)ダウンロードした dll を\xampp\php\extに配置する。
(3)php.ini にxdebug 情報を追記する。
(このことは、GitHubに端的に記述してありました。)

今回は、こちらから「PHP 5.6 VC11 TS (32 bit) 」をダウンロードしました。
xampp phpのv-upで、64bit版のインストールができなかったので
32bit版をダウンロードしています。

これを(2)にコピーして、php.iniの最下部に次の行を追加します。

[XDebug]
zend_extension = "c:\xampp\php\ext\php_xdebug-2.5.0-5.6-vc11.dll"
xdebug.remote_autostart = 1
xdebug.profiler_append = 0
xdebug.profiler_enable = 0
xdebug.profiler_enable_trigger = 0
xdebug.profiler_output_dir = "c:\xampp\tmp"
;xdebug.profiler_output_name = "cachegrind.out.%t-%s"
xdebug.remote_enable = 1
xdebug.remote_handler = "dbgp"
xdebug.remote_host = "127.0.0.1"
xdebug.remote_log="c:\xampp\tmp\xdebug.txt"
xdebug.remote_port = 9000
xdebug.trace_output_dir = "c:\xampp\tmp"
; 3600 (1 hour), 36000 = 10h
xdebug.remote_cookie_expire_time = 36000

なお、

zend_extension = "c:\xampp\php\ext\php_xdebug-2.5.0-5.6-vc11.dll"

の部分は、自分の環境やダウンロードしたXdebugに基づいて変更する
必要があります。

変更したphp.iniを保存後は、xamppコントロール・パネルから
Apacheを、stop→start としてphp.iniの変更を反映させます。

PHP loadHTMLFile に再びハマる

PHP DOM操作における文字化けで1回既にハマっていたのに、今回また同じ様にハマってしまった。
しかも、2日がかりで。
悔しいので、今回気付いた点を纏めておきたい。

(1)UTF-8Nで書いたソースは何にエンコードされるのか?

UTF-8(BOMあり)にエンコードされるようです。
試しに、sample.htmlをUTF-8(BOMあり)で保存して実行すると
文字化けをせず、正しく表示されます。

(2)loadHTMLFile()以外の場合は?

$sou = file_get_contents(./sample.html);
echo &sou;

として確認してみると、文字化けはしません。
と言うことは

$dom = new DOMDocument();  // ①
@$dom->loadHTML($sou);     // ②

②の中で、HTMLのmeta情報に基づいてコードが変換される
と言うことなのでしょう。

(3)php.iniとの関連は?

本件に関しては、、全く関連なしでした。
原因が(2)にあるので、当然と言えば当然です。
いろいろと、2日間ももがき苦しんだ中で、php.iniのmbstringの設定が
推奨されなく成っている所が何点かあるのが分かりました。

対策ついでに、PHP-5.4.7からPHP-5.6.30にバージョンアップも
行いましたが、php.iniのmbstringの設定を以下の通り変更しています。

名前 設定値 説明
mbstring.language Japanese コメントを外しただけです
mbstring.encoding_translation Off コメントを外しました

mbstring.http_input,mbstring.http_output,mbstring.internal_encoding
は、5.6.0以降は非推奨とのことなので、コメントのままにしてあります。

印刷用語

用語の羅列のみ
1.合字(リガチャ:Ligature)
2.字形(グリフ:Glyph)
3.約物(Punctuation)句読点等々
4.圏点、傍点、脇点
5.書体(Font)
6.踊り字(約物にほぼ同じ)

PHP DOM操作における文字化け

PHPで、次のHTMLを読み込んで、title の
テキストノードを取得し表示するものとします。

(1) HTMLコード(sample.html)

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>HTMLの練習</title>
  </head>
  <body>
    こんにちは
  </body>
</html>

(2) PHPコード(sample.php)

$sou = file_get_contents(./sample.html);
$dom = new DOMDocument();
@$dom->loadHTML($sou);
// <title>タグの値を取得する
$title = $dom->getElementsByTagName('title')->item(0)->nodeValue;
print "$title\n";

プログラムのソースは共に utf-8 で格納しており、php.ini の設定も utf-8 にしている
ので問題ないはずなんですが・・・・

なんと「HTMLの練習」が正しく表示されない!
文字化けします。

その原因は?
私にゃ分からないので、Gooleさんにお願いしてみると、
素晴らしいご託宣がここにありました。
かいつまんで言うと、

<meta charset="utf-8">

この書き方では、文字コードの判定できないらしく

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

のように書かなければならないとのことである。

お陰様で問題が解決しました。
が、他にも同じような問題があったような???
HTMLのバージョンがアップしても、PHPが追随してないようなイヤ~な感じがします。

Scoutが動かない

標記のソフトをインスト-ルしようとするとエラーが発生する。
インストールに失敗したのかと思いきや、java.exe の位置が探せずに起動でき
ことが原因でした。
< /gecko >に対策が書いてあります。
大変お世話になり感謝申し上げます。

少々手間取った点をメモします。
(1) インストール(解凍したものをコピーしただけのよう見えますが)先の、
C:\Program Files (x86)\Scout\javascripts\app\フォルダ内にある process_interaction.js を開きます。
(2) 秀丸では、更新不可のメッセージが出るので、一旦別フォルダ(デスクトップなど)へコピーしてから開いた方が良いでしょう。
(3) < /gecko >さんのページでは95行目とありましたが、最新のものでは108行目を変更します。

function javaDir() {
  if(air.Capabilities.os.match(/Windows/)) {
    path = air.File.applicationDirectory.resolvePath("C:\\Program Files\\Java\\jre1.8.0_77\\bin\\java.exe");
    // (以下略)

以上です。
jreにバージョンが付いているけど大丈夫なのかな?
自分の環境変数が不安になってしまう・・・。
(追)
環境変数:C:\ProgramData\Oracle\Java\javapath
このフォルダ内に、java.exe へのシンボリックリンクが張られているので
v-up 時には、このリンクを張り替えているようですので心配は無用でした。

EnterキーによりSubmitされるのを防ぐ方法

Bootstrapを使用して、次のような簡単なフォームを作成した。


<form class="form-inline" role="form">

<div class="form-group">
    <input class="form-control" id="yy" type="text">
    <label for="yy">年</label>
    <button type="button" class="btn btn-success" id="run">実行</button>
  </div>

</form>

ここで想定外の問題発生。
入力フィールドに、数値(年)を入力して Enter キーを押すと
何事も起きていないのに、入力値がスーッと消えてしまうのです。

先ずは。Bootstrap を疑ってググって色々調べてみると、Bootstrapとは無関係
で、原因はブラウザのデフォルト動作で

Enter キー押下 = Submit

になり、送信データを受信するプログラムがないためらしい。

受信用のプログラムがないので、対策として、以下のように Enter キーを無効に
することで暫定対策。

$("input"). keydown(function(e) {
  if ((e.which && e.which === 13) || (e.keyCode && e.keyCode === 13)) {
    return false;
  } else {
    return true;
  }
});

これだと、Enter キーを無効にはできるが、

数値を入力 → 右手をマウスに持ち換え → ボタンをクリック

との一連の動作が、如何にも面倒。

数値を入力 → Enter キー押下

とできれば、入力がかなり改善される。
と言うことで、Enter キーを無効にすることをやめて
次のようなコードに変更。

$("#yy").keydown(function(e){
  if(e.keyCode=='13'){
    var year = $("#yy").val();
    dispData(year);  // データ表示
  }
});

ここで、またまた問題が・・・・
データは、一瞬表示されるが直ぐに消えてしまうような現象が発生。

これは、「Enter キー」のSubmit 機能が活きているため、データを
一旦表示した後に、フォームが送信されてしまうことが原因。
(この原因を掴むのに、随分苦労しました。)

送信機能を無効にするため、最後に、false を返す一文を
するだけで、上の問題が解決できました。

$("#yy").keydown(function(e){
  if(e.keyCode=='13'){
    var year = $("#yy").val();
    dispData(year);  // データ表示
    return false;    // Submitを無効に
  }
});

Google Map に Bootstrap を適用する

見映えの問題で、標記のことについて実施しているところですが
問題が発生しました。
例えば

<html lang="ja">
<head>
<meta charset="UTF-8">
<title>GoogleMap Test</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- GoogleMaps API -->
<script src="http://maps.google.com/maps/api/js?sensor=false&language=ja"></script>
<!-- jQuery -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
<!-- Bootstrap -->
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
<style>
  #map_canvas { height: 100% }
</style>
<script>
$(function(){
  var latlng = new google.maps.LatLng(35.66, 139.69);
  var options = {
    zoom: 15,
    center: latlng,
    mapTypeId: google.maps.MapTypeId.ROADMAP
  };
  var map = new google.maps.Map($('#map_canvas').get(0), options);
});
</script>
</head>
<body>
  <div class="container-fluid">
    <div class="row">
      <div id="map_canvas"></div>
    </div>
  </div>
</body>
</html>

は、正しくMapが表示されます。
このソースの先頭に

<!DOCTYPE html>

を追加すると、途端に表示されなくなります。
色々調べて行くと、原因は行の高さにあるらしい。

<style>
  #map_canvas { height: 500px }
</style>

のように、明示的に高さを指定すると確かに表示されるようになります。
でも、これじゃBootstrapを使用する意味がないではないか!
と言うことで、再び「%」に戻すため「height %」でググり、cssの勉強し直し。
“height 100%” が有効になるためには、親要素全てが “height 100%” で
なけれならないとのこと。されば、

<style>
  html,body,body > div,body > div > div { height: 100%; }
  #map_canvas { height: 100%;}
</style>

としたところ、見事表示されました。
先ずは、目出度し目出度しと言いたいところだが
Bootstrapを使用すると、どうしてもコンテナの階層が深くなるので
これを適用するのが良いのか悪いのか?
悩ましい問題ではあります。

なお、指定をもっと簡単にしようと

<style>
  html,body,body div { height: 100%; }
  #map_canvas { height: 100%;}
</style>

等とすると、map_canvas 内に設定された要素(Google Map)にまで
影響が出るので、丁寧に map_canvas の親要素のみを指定する必要
があります。