タグ別アーカイブ: XHTML

WordPressテーマ変更に伴う記事のルート見出しレベルの変動を吸収するプラグイン WP hn Convert

随分前に愚痴った、WordPressのテーマを変更すると記事のルート見出しレベルが変動し、過去記事資産が活かせないという問題。この問題がまだ根本的解決に至っておらず、古いWordPressサイトを新しいテーマに移行する際には常に悩まされている。
公式がTwenty Twelveを出してきて以降は、テーマ制作者の暗黙の了解として記事タイトルがh1、記事内で最もレベルの高い見出しがh2というように揃えてきているように思う。これは記事に対してHTML5のセマンティックを結びつける場合、記事部分で新しくセクショニングコンテンツ(article)を始めるというのが合理的だからであろう。あるいは、SEO対応を売りにするWordPressテーマなどでは、single.phpにおける最初のh1を記事タイトルに充てているため、不都合なく記事資産を共有できるようになっているのである。

the_content()をラッピングする方法

一方、記事を出力するタイミングで見出しにテキスト処理を噛ませるという方法があり、こちらはWP hn Convertというプラグインを配布されている方がいる
このプラグインを導入し、テーマ中のthe_content()の記述部分を全てthe_hn_converted_content(数字)とすると、数字で指定した分だけ見出しレベルを移動してくれる。たとえば記事タイトルをh2にして書かれたテーマをh1からにするには、the_hn_converted_content(-1)のようにすると、以下の見出しh3をh2、h4をh3というように全体的な見出しレベルに変動を与えてくれるのである。

でも根本的な解決ではない

このプラグインで対処することも可能なのだが、そうすると記事を書く側としてはルート見出しレベルをこれまで通りのレベルにし続けなければならない。
また、試していないので何とも言えないのだが、たとえばコードスニペット中に書かれたhtmlの見出しレベルにも適用されてしまうのではという危惧もある。通常の日記ブログなどでは問題が無いだろうが、技術系のブログにとっては大きな問題となってしまうのではないか。
ということで、上手い解決法がないかと依然悩んでいる。データベースを直接たたいて置換というのも、怖い話だなあ。


Safari、Chromeで動くJavaScriptがFirefoxで動かない→宣言部、ヘッダ部を疑いましょう

JavaScriptが満載のWEBページを制作していて、ページの一部の機能がSafari、Chromeでチェックした際には動作するのに、Firefoxでは全く動作しないという状況に遭遇しました。
具体的には、ナビゲーションボタンのマウスホバー時の挙動として、透明度の指定をjQueryで行った箇所と、画像のLightBox的挙動のためjQuery.lightboxを使った箇所です。

マウスホバーの部分については、ホバー状態が終了する際に、FirebugのコンソールにremoveAttribute is not a functionというエラーが表示されます。lightboxのエラーは、画像が拡大表示された後ページに戻る事ができず背景が暗いままという不具合で、こちらは特にコンソールに表示はありません。

これはjQueryの動作に問題があるのだろうとあたりをつけ、様々な手段を使ってチェックを行いました。

ホバー部分のコードについては、以下のようなものでした。

<script>
$(function(){
$(".hover").hover(
function(){
$(this).fadeTo(0,0.5);
},function(){
$(this).fadeTo(0,1.0);
});
</script>

hoverメソッドは引数に関数を二つ取り、それぞれホバー時と終了時の処理を書く事ができます。処理の部分で、fadeToではなくcssメソッドを使ってopacityを指定するも動作せず。しかしながら、cssメソッドでwidthなどの他の値を指定する場合は動作します。つまり透明度関係の指定が上手く行っていないということが予想できます。
そこでブラウザのopacityの実装の違いではないかと考え、Firefoxについてのリファレンスを漁ったり、懐かしの-moz-opacityを引っ張り出してきたりと、色々と試みるも挙動が変わる事はありません。
次にプラグイン同士の相性を疑い、抜き差し抜き差しするも効果なし。jQueryのファイル名やヴァージョンの変更を行うも駄目。この時点で既に大量の時間を原因の究明に費やしています。

戯れに同じコードを別の製作中のページに貼付けてみると、ちゃんと動作しました。そのページはXHTMLではないHTML5のページだったので、jQueryやlightboxプラグインのドキュメントをあたり必須要件がHTML5なのかチェック、しかしながら特に指定はありません。

結局不具合の原因が何だったのかというと、

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja" dir="ltr">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="Content-Style-Type" content="text/css;" />
<meta http-equiv="Content-Style-Type" content="text/javascript;" />

こんなに単純な事でした。本来Content-Script-Typeでtext/javascriptを指定しなければならないところを、上のcssの指定をコピーしてそのまま、Content-Style-Typeとしていたわけですね。
何故HTML5で無事に動いたのかというと、これらの部分が省略可だからでした。

つまりトラブルを一般化すると、SafariやChromeで動くJavaScriptがFirefoxで動かない場合、間違ったXHTMLの記述に対する、ブラウザの解釈の違いが原因である場合があるということです。
一字一句間違えてはならないDOCTYPE宣言についても、思わぬエラーの原因になりそうなものです。実際標準モードと互換モードでcssの解釈が異なるので、意図せず互換モードが呼び出され、jQueryでの表示不具合に直結している可能性があるのではないでしょうか。

毎度の事ですが、ニッチなエラーに足を取られ易い私の失敗談が、誰かの役に立てば幸いです。


clearfixのささやかな覚え書き

複数カラムのブログテンプレートなどを作成するとき、一般的にはCSSのfloatプロパティを使ってレイアウトを行います。たとえば2カラムで左にサイドメニュー、右に記事本文というレイアウトは、以下のようなhtml&CSSになるでしょう。

HTML部
<div class="wrapper">
<div class="sidebar">
//サイドメニューエリア本文
</div>
<div class="articlearea">
//記事本文
</div>
</div>
 
CSS
.sidebar{
float : left;
}
.articlearea{
float : right;
}

カラムを包括する親ボックスの大きさが指定されており、各カラムが親ボックスの高さの値を超えないときには、特にレイアウト上の問題は起こりません。しかしながら、ブログのようにカラムの本文が可変長で親ボックスの高さを超えるケースが考えられるときには、カラムが親ボックスをはみ出て表示されてしまい、レイアウトが崩壊してしまいます。

はみ出たカラム

これは、ボックス内でfloat指定されている要素の大きさが親ボックスの大きさを決める際に参照されないという特性によるものです。したがって最も仕様に適った解決は、floatさせた要素の後にclearプロパティでfloat解除した要素を設けることです。空のdiv要素やvisibilityプロパティをhiddenにしたhr要素、br要素がよく使われます。

HTML部
<div class="wrapper">
<div class="sidebar">
//サイドメニューエリア本文
</div>
<div class="articlearea">
//記事本文
</div>
 
//空divの場合
<div style="clear : both"></div>
 
//非表示にしたhrまたはbr
<hr class="clearfix" />
<br class="clearfix" />
</div>
 
CSS
.sidebar{
float : left;
}
.articlearea{
float : right;
}
.clearfix{
visibility : hidden;
clear : both;
}

この方法はシンプルですが、ページのセマンティック(意味)としてはデザイン修正の為だけの無意味な要素をhtmlに加える事になるので好ましくありません。
そこで、無駄な要素を加えることなくレイアウト修正を行う、名前もそのまま”clearfix”というテクニックが開発されました。

HTML部
<div class="wrapper">
<div class="sidebar">
//サイドメニューエリア本文
</div>
<div class="articlearea">
//記事本文
</div>
</div>
 
CSS
//clearfixの追加部分
.wrapper:after{
content : "";
display : block;
clear : both;
}
//IE6,7用
.wrapper{
zoom : 1;
}
 
.sidebar{
float : left;
}
.articlearea{
float : right;
}

CSSのafter疑似要素を使って、floatを解除する要素を無理矢理埋め込むという形です。この方法ならば、検索エンジンやアプリケーションがページのhtmlのみを取得する場合に、解釈の混乱をひきおこす無駄な要素が発生しません。IE用の追加部分については、独自仕様のhasLayoutというプロパティがtrueであれば子要素のfloatを親ボックスのサイズ計算に含めるという特性を利用しています。無害なレイアウト指定(zoom:1;やwidth:100%;など)であれば何でも良いのですが、ソースの意図を明確にする為にzoom:1;の指定をしている場合が多いようです。

ここまでがclearfixの説明です。先に述べた通り、floatを解除する要素を最後に加えるという解決方法ですね。

それに対して、親ボックスのoverflowプロパティを明示的にhiddenと指定することで、親ボックスのサイズ計算方法を変えるというテクニックもあります。overflowプロパティとは、ボックス内の要素がボックスのサイズを超えてしまった際の表示方法についての指定で、何も指定しない状態はvisible、つまりはみ出た部分も表示する指定になります。これをhiddenと指定した場合、はみ出す部分のみ非表示となると同時に、ボックスの高さの計算式にfloatさせた要素も含まれるようになります。

HTML部
<div class="wrapper">
<div class="sidebar">
//サイドメニューエリア本文
</div>
<div class="articlearea">
//記事本文
</div>
</div>
 
CSS
.wrapper{
overflow : hidden;
//IE6,7用
zoom : 1;
}
.sidebar{
float : left;
}
.articlearea{
float : right;
}

場当たり的な対応ではありますが、セマンティックを汚染せずさらに簡単なので、こちらをバカの一つ覚えのように使ってしまって良いかもしれません。


フォーム入力のサニタイジングを行う(PHP編)

ユーザの入力をフォームで受け付けWEBページに出力する処理を含んだプログラムでは、入力値のサニタイジング(無害化)が必要です。WEBブラウザは表示内容にhtmlタグが含まれているとこれを自動的に解釈して反映してしまうため、悪意あるユーザがタグを混入させた入力を行えば、表示出力段階で設計者の想定外の処理が行われてしまうからです。
実例を見てみましょう。たとえば以下のような簡単なプログラムがあったとします。

<html>
<head>
<title>sample.php</title>
</head>
<body>
<?php
echo $_POST["userin"];
?>
フォームへの入力値を表示する
<form action="sample.php" method="post">
<input type="text" name="userin"></input>
<input type="submit" value="送信"></input>
</form>
</body>
</html>

このプログラムのユーザ入力に、<h1>このページの内容は嘘八百である</h1>というタグ付きテキストを渡してみます。するとh1タグが解釈され、目立って大きなテキストとして表示されてしまいます。たとえば掲示板プログラムなど、ユーザ入力が残り続けるページの場合にはこの「このページの内容は嘘八百である」という文言が残り続け、h1タグが付いているため検索エンジンにもこれがページの主要内容と誤解されてしまいます。さらに掲示板の背景色と同じ文字色をタグで指定すれば、管理者にも容易に気付かれずこの文言が残り続けることになります。

また、タグが解釈されてしまうということはscriptタグに挟んだ任意のスクリプトも実行できてしまうということです。ユーザの情報をクッキーに保存しているサイトで、<script>alert(document.cookie);</script>と入力すれば、scriptタグ中のjavascriptが処理され、クッキーに保存されたユーザ情報にアクセスできてしまいます。
この脆弱性と、アドレスにフォームへの入力内容を付加できるという特性を利用して行われるのがXSS(クロスサイトスクリプティング)です。この場合攻撃者(Aとします)は攻撃対象サイト(B)のアドレスにフォーム入力内容を加えたリンクを、悪意の無いユーザ(C)に踏ませます。クッキーに格納されたユーザ(C)の情報はスクリプトにより攻撃者(A)に取得され、たとえばそれがパスワードであった場合には不正アクセスが可能になってしまいます。さらにクッキーに保存された情報の種類によっては、もっと深刻な個人情報の漏洩にもなり得ます。

このような攻撃への対策として行われるのがサニタイジングです。htmlタグを示す<や>といった文字をエスケープして他の文字列を充てるという処理で、PHPにはそれを行う関数が幾つか存在します。以下それらの関数個別の説明を行います。

strip_tags関数

この関数はその名の通り、htmlとPHPのタグを文字列から取り除きます。また2番目の引数として特定のタグを与えることで、そのタグは取り除かないといった指定もできます。一見便利そうですが、タグであるとの判定が<と>に囲まれているということなので、ユーザ入力として閉じてないタグ(例:<script)を与えられると、遥か先に存在する>を探し出してそこまでの文字列を全て取り除いてしまうという可能性があり諸刃の剣です。

addslashes関数

この関数がエスケープするのはタグを構成する文字ではなく、シングルクォート、ダブルクォート、スラッシュといったデータベース操作のSQL文を構成する要素です。これはSQLインジェクションという攻撃への対策であり、このエントリの内容からは外れるのですが、ここで言及するのはこの機能をデフォルトでオンにしているレンタルサーバが多いからです。
正確にはPHP設定のmagic_quotes_gpcという項目名のもので、これがonになっていると自動的にフォーム入力値にaddslashes関数が実行されるというものです。先程のフォーム入力表示プログラムにエスケープ対象になる文字列を入力して、バックスラッシュや¥マークが付加されて表示される場合はこれが有効になっています。ある意味この自動エスケープも入力内容の予期せぬ改変を引き起こすと言えなくもなく、またSQLインジェクションへの対策という点から見てもこの機能は不完全ですので、PHPの最新ヴァージョンでmagic_quote_gpcが廃止されるなどの動きもあるようです。この辺りの話はまたSQLインジェクションについてのエントリを立てて説明します。

htmlspecialchars関数

この関数は、htmlタグを構成する<と>、&、設定によってはシングルクォートとダブルクォート、以上の5種類に対しエスケープを行ってくれる関数です。&に何故エスケープが必要かというと、この文字はエスケープ変換後の文字列の先頭に現れエスケープの表明になるからです。たとえば<をエスケープすると&lt;という文字列になります。シングルクォート、ダブルクォートについても、CSSでの値指定で使われる文字で、これを利用した攻撃方法が存在するのでエスケープの必要があります。デフォルトではダブルクォートのみエスケープという指定になっているので、この関数を利用する際には引数を与えシングルクォートのエスケープも有効にしなければなりません。以下は書式です。

htmlspecialchars(引数1,引数2,引数3);
/*
引数1:変換対象文字列
引数2:(省略可)クォートの扱い。0〜3の整数値または定数で指定。
定数ENT_QUOTESを与えると両方変換する。
引数3:(省略可)文字コード。UTF-8など明示的に指定しておいた方が良い。
*/

この関数を常に使うのが有効な対策です。

htmlentities関数

htmlspecialchars関数と同じく文字列を&lt;のようにエスケープしてくれるのですが、対象文字がエスケープ可能な全ての文字にわたります。ウムラウト付き文字やギリシャ文字、記号類が主な対象です。全てのリストは、htmlの特殊文字などで検索して調べて下さい。
この関数をhtmlspecialchars関数の代わりに使うこともできます。ただやはりクォートのエスケープのデフォルト値はダブルクォートのみなので、第二引数にENT_QUOTESを与えて下さい。

ユーザからの入力を表示するプログラムにサニタイジングが必要ということは、前回作成したようなファイルアップロードを受け付けるプログラムでも適切なエスケープが必要になります。ファイルから読み込んで表示する部分にエスケープするのは勿論ですが、$_FILES変数の$_FILES[][‘type’]、$_FILES[][‘name’]などについても、ユーザが任意の値を設定できるため、エスケープするべきです。

以上がPHPでのサニタイジングです。サニタイジング以外にも、ファイル構成や入力チェックなどでセキュリティを上げることが可能ですので、その方面での対策と常にセットで考えておきましょう。


プログラム・設定ファイルのコメント書式一覧

個人的によく使うプログラミング言語・設定ファイルのコメント書式を、まとめてメモしておこうと思います。

コメント書式一覧
言語・設定名 コメントの書式 備考
XHTML(HTML)・HTML5 <!‐‐ ここにコメントを書く ‐‐> 複数行も可能です。コメント中の連続したハイフン(‐‐)の使用は禁止されています。
CSS /* ここにコメントを書く */ 複数行も可能です。
PHP // ここにコメントを書く 一行のコメント。複数行はダメ。C++形式。
#ここにコメントを書く 一行のコメント。複数行はダメ。ShellやPerl形式。
/* ここにコメントを書く */ 複数行も可能です。
JavaScript・ActionScript // ここにコメントを書く 一行のコメント。複数行はダメ。C++形式。
/* ここにコメントを書く */ 複数行も可能です。
Objective-C・Swift // ここにコメントを書く 一行のコメント。複数行はダメ。C++形式。
/* ここにコメントを書く */ 複数行も可能です。
SQL ‐‐ ここにコメントを書く 一行のコメント。複数行はダメ。
/* ここにコメントを書く */ 複数行も可能です。
php.ini(PHPの設定ファイル) ; ここにコメントを書く 一行のコメント。複数行はダメ。
.htaccess(サーバアプリケーションの設定ファイル) # ここにコメントを書く 一行のコメント。複数行はダメ。

これからもうちょっと複雑なWEB制作を始めたら、表の項目が増えていく可能性もあります。そして、間違っている箇所を発見したら指摘していただけると非常に助かります。