"BOKU"のITな日常

62歳・文系システムエンジニアの”BOKU”は日々勉強を楽しんでます

iframeをコンテンツにあわせて自動サイズ調整&表示・非表示のアクセス制限(備忘)

 

iframe内にコンテンツを表示する際にハマりやすい・・というか自分がハマった・・問題について解決策をメモっておきます。

f:id:arakan_no_boku:20180427232928j:plain

 

静的コンテンツをiframe内で表示する

 

要件は単純です。

PHPでログイン・パスワードでアクセス制限をかけたページ内に、iframeを使って静的HTMLのコンテンツを表示したいだけです。

表示をするだけなら簡単そのもの。

たとえば、静的コンテンツを表示するためのURLはこんな感じを想定します。

https://hogehoge/secchk.php?ct=contents001.html

PHPプログラム自体の処理は大枠でこんな構造。

  1. URLパラメータから表示HTML名を得る(上記ならcontents001.html)
  2. ログイン中であることをチェック。違えば、ログインするように即すエラー画面。
  3. OKなら、contents001.html の本当の置き場所のURLに変換する。
  4. そのURLをiframeにわたして表示する。

ソースでエッセンスだけ抜き出して書くとこんな感じですかね。

//ここまででログインチェックがOKになった前提
if(isset($_GET['ct'])) {
$fname = $_GET['ct'];
}else{
$fname = 'error.html';
}
define("URL_PATH","http://hogedoc/doc/");
$disp_url = URL_PATH.$fname;
print("<iframe src=\"$disp_url\" width=\"100%\" height=\"800px\"></iframe>");

 

一応、これで表示はできます。

でも、2点問題がありました。

  • iframeのサイズが固定でスクロールバーがでてしまう。
  • 静的URLでセキュリティをパスして参照できてしまう

です。

 

iframeのサイズが固定でスクロールバーがでてしまう問題の対策

 

デフォルトのheightよりも長いコンテンツの時は、コンテンツにあわせてiframeの長さがのびてほしい。 

普通はそう思います。 

でも、iframeではそういう指定ができません。 

サイズが固定になって、スクロールバーがでてしまいます。 

これはHTMLだけでは対応できないので、jQueryを使って対応します。

jquery-3.2.1.min.js とjquery.cookie.js を適当にダウンロードして、PHPソースを置くフォルダにjsフォルダを作って置いときます。 

それで、phpプログラムのお尻の方(PHP命令の外。</body>の直前あたり)に以下のような記述を追加します。

<script src="js/jquery-3.2.1.min.js"></script> 
<script src="js/ifexp.js"></script>

 

ifexp.jsは自分で作ります。
中身はこうです。

ifexp.js

('iframe')
.on('load', function(){
try {
$(this).height(0);
if(this.contentWindow.document.documentElement.scrollHeight > 800){
$(this).height(this.contentWindow.document.documentElement.scrollHeight);
}else{
$(this).height(800);
}
} catch (e) {
}
})
.trigger('load');

 

こうしておくと、HTMLをiframe内で表示する時に高さを自動調節してくれます。

 

静的URLでセキュリティをパスして参照できてしまう問題の対策

 

こちらは、ちょっと補足説明します。

ようするに、コンテンツが見える見えない・・は、親画面にあたるPHP側でセキュリティをかけているわけです。

ところが、iframeで表示をしている限り、ブラウザの「ソースの表示」機能で静的URLを確認されてしまいます。
こんな感じです。

<iframe src="https://hogedoc/doc/contents001.html"  width="100%" height="800px"></iframe>


当たり前ですが、静的URLにはセキュリティなんかかかってませんから、フリーパスになってしまいます。

これでは、PHPでアクセス制限をかける意味がありません。

これをふせぐには、URLを直接たたいても表示できない仕掛けが必要です。 

方針は簡単です。 

<body>の中の表示させたくないコンテンツを<div>タグで囲んで、それを非表示(display:none;)にしておくのです。
今回は元々、<div class=out-f></div>で全体を括ってあったので、ここはCSSの変更だけでOKでした。 

そして、表示用のPHPプログラムの中で、ログインOKなら、Cookieにそれを有効期限10秒くらいでセットし、HTML側でそのCookieがあるかどうかをチェックして、OKなら、display:none;を解除してやれば良いわけです。
こうしておけば、PHPプログラムを通してしか表示することができません。 

実際のソースの抜粋です。 

まずPHP側でログインチェックOKになったら、以下のようにcookieを10秒間だけの有効期限で発行します。

 

$expire = time() + 10;
setcookie('5Xa9Dfgt03', '5Xa9Dfgt03', $expire);
 

HTML側に埋め込む表示用のJavaScriptは、こんな感じです。 

Cookieの存在チェックがOKなら、display:noneを解除しています。

if($.cookie('5Xa9Dfgt03')){
$(".out-f").css({'cssText': 'display:block !important;'});
}else{
//エラー処理。エラーページへの遷移とか。
}

 

上記はポイントの部分だけ抜き出してますが、iframeの中で表示させるときは、<script></script>で囲ってあるだけでは実行されません。 

上記を、読み込み時に実行するように、例えば以下で囲っておくことはお忘れなく。

(function(){
   // 上記の処理
}());

 

そして、それを「sec.js」とかで保存したす。 

上記が「即時関数」の形であることに注意してください。 

そして、「sec.js」を置く位置は、bodyの<div class=out-f>の直後です。

<div class=out-f>

<script src="js/sec.js"></script>

 

こうする理由は、InternetExprorer対策です。 

他の位置においたり、即時関数ではなく、よくある「$(function(){ });」の形で囲ったりすると、文末あたりに「2018/05/03追記」で書いた現象に苦しむことになります。 

あ、そうそう。 

</head>の前あたりで必要なライブラリは読み込んでおいてください。

 

<script src="js/jquery-3.2.1.min.js"></script>
<script src="js/jquery.cookie.js"></script>

 

今回は、pythonの使い捨てスクリプトを作って200ファイル一気に埋め込みましたが、HTMLに上記3行を貼り付けるだけなら、HTMLしかさわれなくてもOKですから、今後のメンテナンスの心配もありません。 

やれやれです。

 

2018/05/03追記

>Divタグのdisplayを切り替えて表示した時に、iframeの内容に合わせた高さの自動調節がInternetExprorerで、効かなくなる現象が発生するみたいです。

>それも同じページで発生したりしなかったりです。

Chromeでは何の問題もないのですけれどね。

デバッグしてみたら、IEの場合、iFrameがLoadされた時点で「contentWindow.document.documentElement.scrollHeight」が生成されていない場合があって、そのときに例外が発生してるみたいです。

>只今、対応方法調査中です。

2018/05/08追記

>なんとか、対応方法を見つけました。

>それにあわせて、上記記事を一部修正しました。