トップ 差分 一覧 ソース 検索 ヘルプ PDF RSS ログイン

ハマるとなかなか気づかないワナ_XOOPS

ハマるとなかなか気づかないワナ

きちんとPHPでXOOPSのモジュールを作っているのにページが表示されなかったり、表示がおかしくなる、ということが起こることがあります。

実際に起こりうる問題とその回避策を書き記します。

ページが表示されない、エラーが出て回避できない

PHPソースファイルをEUCコードで保存していない(すべてのファイルをEUCで保存すること)

ヘッダ・テンプレート・フッタの呼び出し順番が異なっている

// ヘッダファイルの参照
require('header.php');

// テンプレートの設定
$xoopsOption['template_main'] = 'simplemodule_view.html';

// XOOPSヘッダの設定
include(XOOPS_ROOT_PATH.'/header.php');

// テンプレートにデータを設定する
$xoopsTpl->assign('lang_title', _MD_TITLE);
$xoopsTpl->assign('lang_mes', _MD_MES);

// XOOPSフッタの設定
include(XOOPS_ROOT_PATH.'/footer.php');

プログラムが複雑になると、うっかりXOOPSヘッダを呼ばずに「$xoopsTpl->assign」してしまった、なんてことが起こってしまうことがあります。

テンプレートを「$xoopsOption['template_main']」に指定しているが、「xoops_version.php」の$modversion['templates']に指定していない。

ソースファイルの先頭に空白の行が入ってしまう

ちょっと分かりにくいですが、WebブラウザからHTMLソースを見たときに、先頭行がカラ行になっている、という現象に出くわすことがあります(ありました)。

   
<!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">
<head>

ページ自身は何も不都合がないので(空白行が画面に出るわけではないので)問題ない、と思われるかもしれません。実際、問題ないのですが・・・・・1回だけ、ページが空白になってしまい、モジュールをアップデートしても一度ログアウトしてからログインしてもダメだった、ということがありました。

この出力するHTMLの先頭のカラ行をなくすため、何が原因か追ってみました。

print("\n");

みたいに故意に改行しない限りはこうはならないだろう、と思ったのですが1点だけ盲点がありました。

プログラム部であるPHPソースではなく、文字列リソース側の[main.php]にて以下のようにしている箇所がありました。

<?php

define('_MD_TITLE', '簡単なモジュール');
define('_MD_MES', 'Hello World!!');

?>
  

さて、何が原因か分かりますでしょうか(上記じゃ非常に分かりにくいのですが)?「<?php 〜 ?>」で囲まれた部分は、PHPのソースを記述します。これはいいですよね、しかし、すぐその下にカラ行を入れてしまってます。私は、ソースの終端(EOF)までの間に複数行のカラ行を入れるクセがありましたので これがそのままHTMLとして出力されてしまった、というのが原因でした。「<?php 〜 ?>」以外のところは、HTMLに表示される部分です。「?>」でPHPの処理部分を閉じた後はすぐにEOFにしないといけないですね。

なぜかページが表示されていなかったとき、これをすべてのPHPファイルにて修正し再度モジュールをアップデートしたら、正常に動きました。

これはめったに不都合には遭遇しないのですが、確実にこの問題が不正を起こすときがあります。

それは、ページを表示する代わりにファイルをダウンロードさせる場合です。たとえば、CSVファイルをダウンロードさせる例を考えてみましょう。

PHPソースにて、XOOPSのヘッダ類は呼ばずに(<これが大事です!)以下のように記述すると、「test.csv」ファイルをダウンロードするダイアログが表示されます。

header('Pragma: public');
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=test.csv");

print("1,cat,sleep\n");
print("2,dog,sleep\n");

このときに、先ほどのように文字列リソースである「main.php」の末尾に空白行が付いてしまうと、HTMLヘッダが解釈できなくなってしまいます。結果、CSVのダウンロードなのに、ヘッダの記述からCSVの内容までが そのままHTMLとして出力されてしまうことになります。

ということで、教訓としては すべてのPHPファイルにて「<?php 〜 ?>」の後には空白行は入れない、ということですね。

ファイルが二重に呼ばれてしまい、警告される

よく使う処理を別のPHPファイルにおいておき、再利用する(include/requireする)というのはよく使う手段です。

しかし、その別のPHPファイルからさらに別のPHPファイルを参照、とかしていると二重呼び出しが起きてしまうことがあります。そのような場合を考えて、再利用するために分けたPHPファイルでは

include_once('xxx.php');
require_once('xxx.php');

で二重呼び出しが起こらないようにします。

改行コードを入れたのに、改行コードの文字列自身がページに表示されてしまった

画面に

Line1
Line2
Line3

のように表示しようとして、

print('Line1<br>\nLine2<br>\nLine3<br>');

のようにしてしまった経験があります。これを

$str = 'Line1<br>\nLine2<br>\nLine3<br>';

のように変数に入れてもいいです。単に文字列を入れるだけなのでシングルクォーテーションで囲ってます。ですが、表示は

Line1
\nLine2
\nLine3 

のように出てしまいました。

エスケープシーケンスのある文字列は、シングルクォーテーション内ではエスケープシーケンスとは解釈されていません。たとえ変数が文字列中になくても、ダブルクォーテーションでくくりましょう。

print("Line1<br>\nLine2<br>\nLine3<br>");

画面に表示されているのならすぐに分かるのですが、文字列検索や文字列置換でうっかりシングルクォーテーション内でエスケープシーケンスの文字を条件に加えてしまうと、意図した処理ができなくなります。

円マークを出したいのにバックスペース表記になっている

XOOPSデフォルトでは、以下のような文字列をブラウザに表示(テンプレートの変数に代入)すると、円マーク(¥)ではなくてバックスペースで表示されてしまいます。

$xoopsTpl->assign('lang_mes', "d:\\user\\hoehoe.txt");

これは、テーマのCSS(themesディレクトリ内のカレントテーマのstyle.css)にて

table td {padding: 0; border-width: 0; vertical-align: top;
   font-family: Verdana, Arial, Helvetica, sans-serif;}

のようになっている部分の「font-family: Verdana, Arial, Helvetica, sans-serif;」が原因です。これを削除すると、きっちり円マークにはなります。

フォントが小さくなるし、もうちょっと賢いやり方はあると思います・・・。モジュール自身はtableタグ内に埋め込まれていますので、上記のCSSのように「table td」の変更が効いているわけですね。

Future's Laboratory 技術格納庫 2004-2013 Yutaka Yoshisaka.