システム奮闘記:その66

Webファイルマネージャー axlope導入



Tweet

(2008年3月9日に掲載)
  文書や画像を管理するファイルマネージャー。

  Web上でファイルマネージャーができれば、どの端末からでも
ファイルをアップロードして保管したり、必要に応じて
ダウンロードできるから便利だ。

  それらしき物は以前、PHPを使ってプログラムを作った事がある。

  だが、日本語のファイル名が使えない問題があったり、
日本語のファイル名をアップロードできても、ダウンロードの際
文字化けするなどの問題があり、利用者にとって不便だった。

  その上、PostgreSQLの中にファイルを格納する事から、ラージオブジェクトの
バックアップなどに難があったため、管理する側の手間もあった。

  そのため、ほとんど活用される事なく、見事に消え去ったのだ。
  詳しくは「システム奮闘記:その13」をご覧ください。

  ファイルマネージャーではないが、ファイル共有という事で、
Sambaを使っている。
  Sambaの話は「システム奮闘記:その34」をご覧ください。
  だが、各人のデータの保管庫になってしまっているので、
ファイルの雛型や、書類などの掲載には向いていなかった。
  そのため、Webに掲載する状態だった。


  Webにファイルを載せる依頼があると、私がftpを使ったりして
アップロードする手間がかかったりした。
  社内向けのホームページを、Pukiwikiにしてからも、
私が行うため、手間がかかる。


  そこで、誰でも簡単にWeb上にアップロードできるようにしたい。
  だが、ファイルマネージャーを探すが、海外版ばかりで
日本語対応がされていない物ばかりだ。
  英語が読める人ばかりだと問題ないが、そうではないため、
日本語が使えるソフトでないと導入しても、意味がない。

  そんな中、日本語のファイル名でも使えるという
日本発のオープンソース axlopeを見つける。

  axlopeのサイト。
  http://axlope.sourceforge.jp/

  axlopeのダウンロードサイト。
  http://sourceforge.jp/projects/axlope

  そこで今回は日本発のオープンソースのWebファイルマネージャーの
axlopeを取り上げてみる事にしました。

早速、axlopeをダウンロードして使ってみる事にした。 最初は、RedHat9.0で使ってみる事にした。 ちなみに、PHPは5.2.5を使っています。 設定を行う。簡単にできる。 まずは、axlopeはWebを使ったファイルマネージャーなので、 Webコンテンツを置いているディレクトリー上に設置する。 そして、アップロードしたファイルの保管場所を設定する必要がある。 そこでアップロードしたファイルを格納するディレクトリーを 作成する必要がある。
axlopeのディレクトリー構造
ライブラリを格納する「lib」ディレクトリーについては後述しています。

今回は、アップロードしたファイルを格納するディレクトリーとして
「data」という名前のディレクトリーを作成した。

  「data」というディレクトリーを設けた後、設定ファイルに記述する。

lib/conf/conf.inc の中身
<?php
//---------------------------------------------------------------------------
//Charactor set is UTF-8
//漢字コードはUTF−8
//---------------------------------------------------------------------------
$gLang    = 'ja';                                       //メッセージファイル指定  ja , en
//$gRootDir = '/xampp/test';                    //ファイルマネージャーのルートディレクトリ
$gRootDir = '/usr/local/apache/web/axlope/data';  //絶対パス、最後に / を付けてはいけない
//$gRootDir = '/home/user/files';
//---------------------------------------------------------------------------
?>
ピンクの部分がアップロードしたファイルを格納するディレクトリーの指定だ。
絶対パスで設定する必要がある。


  早速、動かしてみるのだが・・・

  文字化けしてるやん (--;;

文字化けの様子

  PHPの内部処理の文字コードの設定等に問題があるのではないか。

  そこで、PHPの設定ファイルの文字コードの設定に左右されないように、
ソースの中で文字コードの設定を行う必要がある。
  axlopeでは、UTF-8を使っているので、以下の部分をindex.phpに埋め込む。

index.php のプログラムの先頭に
文字コードの処理を追加する
追加前
<?php

//---------------------------------------------------------------------------
//Charactor set is UTF-8
//漢字コードはUTF−8
//---------------------------------------------------------------------------
追加後
<?php

mb_language('Japanese');
mb_internal_encoding('UTF-8');
ini_set('mbstring.http_input', 'auto');
mb_http_output('UTF-8');
mb_detect_order('auto');

//---------------------------------------------------------------------------
//Charactor set is UTF-8
//漢字コードはUTF−8
//---------------------------------------------------------------------------
内部処理、出力の文字コードをUTF-8に指定しておく。
これによって、PHP側の設定ファイルの「php.ini」の
文字コードの設定が変更した場合でも影響を受けなくなる。

  そして動かしてみる。すると

文字化けが解消

  これで安心だと思った。
  
  さて、早速、ファイルをアップロードしてみる。
  「アップロード」を選んでみると次の画面が出てきた。

アップロードの画面
Javascriptを使っているため、こんな画面になるのだが、
私はJavascriptが全く読めない・・・ (^^;;

  早速、ファイルのアップロードを行ってみる。

ファイルのアップロード
画面を拡大してみる
まずは、アルファベッドのファイル名から
アップロードの実験を行ってみた。

  「決定」のボタンを押した。
  するとアップロードの成功を知らせる画面が出てきた。

ファイルのアップロードの成功の画面

  本当にアップロードが成功しているのか。
  実際に見てみた。

ファイルのアップロードの成功の画面

  だが、画面表示だけであって、実際にファイルのアップロードが
成功しているかどうかを検証するため、アップロードしたファイルを
ダウンロードしてみる事にした。すると

  見事、成功! (^^)

  問題なくアルファベッドのファイル名のファイルをアップロードする事が
出来る事が確認できた。

  さて、お次ぎは日本語のファイル名のアップロードを行ってみる。

日本語のファイル名のファイルのアップロード

  するとアップロード成功の画面が出てきた。

日本語のファイル名のアップロードの成功の画面
画面を拡大してみる

  一応、アップロード成功の画面が出てきた。
  でも、確かめる必要がある。
  さて、ファイルのリストを見てみる。

日本語のファイル名が載っていた
これを見る限り、問題なく日本語のファイル名でも
アップロードが出来ている感じがする。

  上の図を拡大してみると以下のようになる。

日本語のファイル名が問題なく載っている様子

  さて、実際に、アップロードが出来ているかどうかを確認するため、
「ゆきだるま.gif」をダウンロードしてみる事にした。

  すると・・・

  文字化けが発生したのらー!!

日本語のファイル名のアップロードの成功の画面(拡大)
「雪だるま.gif」のファイル名が文字化けしている様子。
どうやら、おかしな事が起こっているようだ。

  実際に、ダウンロードした後、ダウンロード先のパソコンにある
ファイル名を見てみる。

  すると・・・

  ファイル名が文字化けしてるやん!


日本語のファイル名のアップロードの成功の画面(拡大)
どうやら日本語の処理に問題がありそうだ。

  日本語の処理に問題がありそうな気がした。
  このaxlopeは、ファイルを分類するためのディレクトリーも
設ける事ができるので、日本語のディレクトリー名を設ける事にした。

ディレクトリー作成の画面

  日本語のディレクトリー名を入れてみる。

日本語のディレクトリー名を入れてみる
画面を拡大してみる

  「テスト」という名前のディレクトリー名を作成してみた。
  すると・・・

  やっぱり文字化けしてるやん!

ディレクトリー名が文字化けしている様子
「テスト」を入力したのに、変な文字になっている。
キリル文字かギリシャ文字のような感じだが、調べてみたが
どちらにも該当していないようだ。

  さて、「テスト」が「P」に似た文字になった。
  その「P」に似た文字を選んでみる。すると・・・

  エラーが出た!

エラーの内容
画面を拡大してみる
どうやら「P」に似た文字を正しくディレクトリーと
認識していないようだ。

  うーん、日本語の扱いに難がありそうだ。


  さて、文字化けや日本語処理の問題を見るためにアップロードした
日本語ファイルの削除を行ってみる事にした。

  まずはアルファバッドのファイル名「map.gif」を削除してみる。

ファイルやディレクトリーの一覧(拡大)

  削除を選ぶと以下の画面が出てくる。

「削除」を行って良いのかの画面
これがあれば、誤って消去してしまう事も減るだろう。
なかなか良い。

  もちろん「OK」を選ぶ。
  アルファベッドのファイル名は問題なく削除できた。

アルファベッドのファイル名は問題なく削除できた

  次に、日本語のファイル名の「雪だるま.gif」の削除を行ってみる。

ファイルやディレクトリーの一覧(拡大)
赤く囲んだ部分の「雪だるま.gif」が問題なく
削除できるかどうかを確かめてみる。

  結果は・・・

  エラーが出るやん!

エラーの内容

  画面を拡大してみると

エラーの画面(拡大)
「そんなファイルやディレクトリーはないぞ」とエラーが出ている。
どうやら日本語処理の部分に問題がありそうだ。

  うーん、日本語が絡むと問題が発生している。
  だが、2バイト文字の処理の話や、日本語文字コードに関する知識は
ほとんどないため、この時点で断念してしまう事になった。

どうもうまく動かない。 なので、この時点では「使えないソフトだ」と思った。 だが、数日後、何気なくCentOS4.4で動かしてみた。 ちなみに、PHPは5.2.5です。すると・・・ 問題なく作動した! だった。 ちなみに、OpenSUSE10.2でも動かしてみたら、問題なく作動した。
axlopeとディストリビューションの組合せ
ディストリビューション 動作の有無
RedHat9.0×
CentOS4.4
OpenSUSE10.2

  推測の域を超えないが、Sambaと同じ現象が起こっていると思う。

  Samba-3.0系では、日本語ファイルの変換にiconv()関数を使っている。
  これは、libiconvライブラリを使っている。
  だが、glibcにも大きく影響されている。

  正しく日本語の文字コード変換を行うには、glibc-2.3.3以降が必要で
glibc-2.3.2以下のバージョンではパッチを当てる必要がある。

  Sambaの、たかはしものとぶさんの「Samba 3.0 での日本語」
  http://www.monyo.com/technical/samba/docs/Japanese-HOWTO-3.0.ja.txt


  ところで、PHPの場合、ソースコードを眺めた感じでは、
iconv関数を使っている様子はなかった。
  
  だが、RedHat9.0は初期状態ではglibc-2.3.2が入っている。
  正しく日本語変換ができるのは、glibc-2.3.3以降なので、
glibc-2.3.2の場合はパッチを当てる必要がある。

  なので、PHPは国際化され他言語対応なのだが、コンパイルの際に、
日本語の文字コード変換の部分で支障が出ている可能性は捨てきれない。

  だが、そこまで調査するだけの知識や技術力は、私には持っていない。

  だって事務員だもーん (^^)V

  困った時に使える、説得力のある言い訳なのだ (^^)

  なので、RedHat9.0ではaxlopeは使えない事だけを報告します。

■■■ CentOS4.4で問題なく稼働している様子 ■■■ さて、CentOS4.4、OpenSuSE10.2では問題なく稼働した。 要するに、最近のディストリビューションなら問題なく稼働するようだ。 ただ、プログラムの最初の部分だけ、php.iniに左右されないように 以下のソースを追加しておくのが無難。
index.php のプログラムの先頭に
文字コードの処理を追加する
追加前
<?php

//---------------------------------------------------------------------------
//Charactor set is UTF-8
//漢字コードはUTF−8
//---------------------------------------------------------------------------
追加後
<?php

mb_language('Japanese');
mb_internal_encoding('UTF-8');
ini_set('mbstring.http_input', 'auto');
mb_http_output('UTF-8');
mb_detect_order('auto');

//---------------------------------------------------------------------------
//Charactor set is UTF-8
//漢字コードはUTF−8
//---------------------------------------------------------------------------
内部処理、出力の文字コードをUTF-8に指定しておく。
これによって、PHP側の設定ファイルの「php.ini」の
文字コードの設定が変更した場合でも影響を受けなくなる。

  そして、axlopeの画面を開いてみる。

axlopeの画面
拡大画面
ここからファイルの操作を行う。
Web上なので、複数人が使えるようになっている。

  まずはファイルのアップロードをしてみる。
  もちろん、日本語のファイル名を試してみる。

日本語のファイル名のファイルアップロード

  するとアップロード成功の画面が出てくる。

アップロード成功の表示

  ファイルの表示画面に戻ってみる。

ファイル表示の画面
拡大画面

  問題なく日本語のファイル名が載っている。

  では、掲載したファイルのダウンロードを行ってみる。
  RedHat9の時は、ダウンロードした際、ファイル名が文字化けした。

  早速「雪だるま.gif」のファイルをダウンロードしてみる。

「雪だるま.gif」のファイルをダウンロード
ファイル名が文字化けはしていないようだ

  さて、ダウンロードしてフォルダーに保管された状態を見てみる。

ダウンロードした結果
ファイル名が文字化けはしていないようだ

  日本語のファイル名でも、問題なくダウンロードできる事が確認できた。


  さて、お次は、ディレクトリー名の作成だ。
  RedHat9では、日本語のディレクトリー名を作成した時
文字化けが起こった。

日本語のディレクトリー名の作成

  作成結果を見てみた。

日本語のディレクトリー作成結果
画面拡大
文字化けする事なく、ディレクトリー名が表示された

  色々、触ってみたが、全く文字化けの心配はない。
  なので、最近のディストリビューションで動かすには
全く問題がないと言っても良いと思う。

  もちろん、全てのディストリビューションで検証していませんので
100%の保証はできませんが。


■■■ axlopeの改造 ■■■ オープンソースの魅力は、自由にソースコードを書き換える事だ。 なので、うちの会社の用途に合わせて改造できるのだ。 ■■■ 表示するメッセージの変更 ■■■
ファイルやディレクトリーの一覧
これを見ていると、一般のパソコン利用者には、わかりにくい部分がある。
赤で囲んだ部分で「ディレクトリー」や「ルート」はUNIX用語であって
一般の人は、Windowsを使うので、用語で混乱しそうになる。

  そこで、うちの会社で使うためには、表示の内容を変える必要が出てきた。
  メッセージなどを格納している「lib/msg.ja.inc」を触れば良い

lib/msg.ja.inc を触る
変更前
<?php
//---------------------------------------------------------------------------
//Japanese message definition file
//Charactor set is UTF-8
//漢字コードはUTF−8
//---------------------------------------------------------------------------
$gMsg['keywords']                               = "PHP,File,Manager,Web,ファイル, マネージャー";
$gMsg['description']                    = "axlope:PHPベースのファイル管理ソフト";
$gMsg['title tag']                              = "axlope";
$gMsg['ScanFilesErr']                   = "ディレクトリを見つけることができませんでした
\n";
$gMsg['ScanFilesMsg'] = "現在のディレクトリ:"; $gMsg['footer'] = "axlope : PHP File Manager ver.1.0"; $gMsg['tree'] = "ディレクトリ一覧"; $gMsg['mkdir'] = "ディレクトリ作成"; $gMsg['th_name'] = "名前"; $gMsg['th_size'] = "サイズ"; $gMsg['th_date'] = "更新日"; $gMsg['cp'] = "複写"; $gMsg['mv'] = "移動"; $gMsg['del'] = "削除"; $gMsg['ren'] = "改名"; $gMsg['upload'] = "アップロード"; $gMsg['DirLogMsg'] = "ディレクトリを選んでください"; (以下省略)
変更後
<?php
//---------------------------------------------------------------------------
//Japanese message definition file
//Charactor set is UTF-8
//漢字コードはUTF−8
//---------------------------------------------------------------------------
$gMsg['keywords']                               = "PHP,File,Manager,Web,ファイル, マネージャー";
$gMsg['description']                    = "axlope:PHPベースのファイル管理ソフト";
$gMsg['title tag']                              = "axlope";
$gMsg['ScanFilesErr']                   = "フォルダーを見つけることができませんでした
\n";
$gMsg['ScanFilesMsg'] = "現在のフォルダー:"; $gMsg['footer'] = "axlope : PHP File Manager ver.1.0"; $gMsg['tree'] = "フォルダー一覧"; $gMsg['mkdir'] = "フォルダー作成"; $gMsg['th_name'] = "名前"; $gMsg['th_size'] = "サイズ"; $gMsg['th_date'] = "更新日"; $gMsg['cp'] = "複写"; $gMsg['mv'] = "移動"; $gMsg['del'] = "削除"; $gMsg['ren'] = "改名"; $gMsg['upload'] = "アップロード"; $gMsg['DirLogMsg'] = "フォルダーを選んでください"; $gMsg['RootDir'] = "トップ"; (以下省略)


ファイルやディレクトリーの一覧(変更後)
これだと一般の利用者にも馴染みやすい表示になる。
そもそもWindowsよりもUNIXの方が先に出たのだから、
MSは混乱を避けるため、UNIX用語を使うべきだったと思う。



■■■ 画像の表示 ■■■ さて、うちの会社では商品の画像などを社内向けのWebに載せておけば カタログや資料の作成の際、ダウンロードできれば便利になる。
こんな絵を載せてみたいとする
かわいげのないパンダの絵ですが、絵心のない私が描いているので
突っ込みを入れないでください (^^)

  だが、axlopeの初期状態では、ダウンロードして画像を開かないと
画像の中身が見れないので、確認するのに手間がかかる。

画像ファイルは、ファイル名しか表示されない
gif画像の「panda.gif」が表示されたら、どんな画像かわかるので
便利だなぁと思ったりする。

  そのため、Web上で画像の中身を見る事ができれば、ダウンロードして
確認する手間が省ける。

  そこでファイル名を表示させるライブラリ(lib/axlope01.inc)を
改造してみる事にした。

lib/axlope01.inc の改造
変更前
//ファイル
foreach($files as $key => $val) {
        if($c % 2 == 0) printf("\n<tr class=\"cEvenColor\">\n");
          else          printf("\n<tr class=\"cOddColor\">\n");
        $DecodedFileName = urldecode($val->mName);
        printf("<td><input type=\"checkbox\" name=\"nFiles[]\" value=\"$DecodedFileName\"></td>\n");
        printf("<td><img src=\"{$gImg['file']}\" alt=\"$DecodedFileName\"><span class=\"cPseudLink\" onclick=\"SendCmdForm('download','$DecodedFileName')\">$DecodedFileName</span></td>\n");
        printf("<td style=\"text-align:right;\">$val->mKBSize</td>\n<td style=\"text-align:right;\">$val->mDate</td>\n</tr>\n");
        $c++;
}
変更後
//ファイル
foreach($files as $key => $val) {
        if($c % 2 == 0) printf("\n<tr class=\"cEvenColor\">\n");
          else          printf("\n<tr class=\"cOddColor\">\n");
        $DecodedFileName = urldecode($val->mName);
        printf("<td><input type=\"checkbox\" name=\"nFiles[]\" value=\"$DecodedFileName\"></td>\n");
        printf("<td><img src=\"{$gImg['file']}\" alt=\"$DecodedFileName\"><span class=\"cPseudLink\" onclick=\"SendCmdForm('download','$DecodedFileName')\">$DecodedFileName</span>\n");

        if ( eregi("(gif|jpg|jpeg|png|bmp)$",$val->mName) == 1 )
           {
           print "<img src=\"data$val->mPath/$val->mName\">" ;
           }

        printf("</td>\n");
        printf("<td style=\"text-align:right;\">$val->mKBSize</td>\n<td style=\"text-align:right;\">$val->mDate</td>\n</tr>\n");
        $c++;
}
赤い部分は改造したり追加した部分だ。
ファイル名が画像データと判定した場合、<img>タグで、
画像を表示させるのだ。

  早速、改造した結果を見てみる事にした。
  すると・・・

  見事、画像が表示された!! (^^)V

画像が表示された
かわいげのないパンダの絵が表示されるようになった。
もっと、かわいい絵だったら良いかも (^^)

  さて改造したため、画像の表示が出るようになった。
  画像が表示するのは意外と簡単だなぁと思った。

  だが、その気分も束の間だった。
  日本語のファイル名「雪だるま.gif」をアップロードしてみる事にした。


日本語ファイル名「雪だるま.gif」の画像
くちばしのように赤くて長いのは、ニンジンのつもりです。
木炭を目にして、ニンジンを口にした、昔からある雪だるまを
描きました。でも、あまり、かわいげがないなぁ (^^;;

  なぜなら、ファイル名が日本語の場合だと・・・

  画像が表示できへん (TT)

画像が表示できない様子
拡大版
日本語のファイル名だと表示できない。

  一体、なんでやねんと思いつつ、原因を探る事にした。


  日本語のファイル名に着目した。

  アップロードしたファイルは、日本語のファイル名のままで
保存しているわけではない。
  URLエンコードで、アスキー文字に変換しているのだ。

  ちなみに、この時点では、URLエンコードが何なのかはわからなかった。

保管ディレクトリーを見てみると
[suga@server data]$ ls -l
合計 8
drwxr-xr-x  3 nobody nobody 4096  3月  3 21:58 %E9%9B%AA%E3%81%A0%E3%82%8B%E3%81%BE.gif
[suga@server data]$
「雪だるま.gif」というファイル名をURLエンコードを行っているため
「%E9%9B%AA%E3%81%A0%E3%82%8B%E3%81%BE.gif」に変換される。

日本語でも、文字コードが違う場合は、URLエンコードの結果が
異なるので注意が必要だ。

  そこで、直接、アップロードしたファイルが正しく表示できるか
確かめるため、URLの部分に、直接、URLエンコードで変換された
ファイル名を打ち込む事にした。

  すると・・・

  表示できへんやん (--;;

URLにファイル名を書き込む様子
URLにファイル名を書き込んだ結果
「そんなファイルは存在しない」というエラーが出た。
エラーの内容を見た時、そんなバカなと思ったが、
何か原因があると思った。

  存在しているはずのファイルが、存在しない。
  そこで、URLエンコードとは何かを調べてみる事にした。

  何やら次の記述が見つかった。

「%」の扱いに関する事
URLエンコードでは「%」を「%25」にするという記述だ。
axlopeでは、ファイル名をURLエンコードしているので
重要な部分だと思った。

  そこで、URLを使って、ファイルを見る時、以下のように
「%」を「%25」に置き換えてみる事にした。

ファイル名の中の「%」を「%25」に置き換えてみる

  そこで、ブラウザで「%」を「%25」に置き換えた状態で、
直接、ファイル名を見る事にした。

  すると・・・

  見事、画像が表示された (^^)

URLにファイル名を書き込む様子
URLにファイル名を書き込んだ結果
URLの「%」の部分を「%25」に置き換えた結果、
見事の画像が表示された。

  この時点では「%」を「%25」に置き換えたら良い理由が
わかっていなかったのだが、とりあえず、これで問題ないと思い、
ファイル名を表示させるライブラリ(lib/axlope01.inc)を次のように
改造してみる事にした。

lib/axlope01.inc の改造
初期状態
//ファイル
foreach($files as $key => $val) {
        if($c % 2 == 0) printf("\n<tr class=\"cEvenColor\">\n");
          else          printf("\n<tr class=\"cOddColor\">\n");
        $DecodedFileName = urldecode($val->mName);
        printf("<td><input type=\"checkbox\" name=\"nFiles[]\" value=\"$DecodedFileName\"></td>\n");
        printf("<td><img src=\"{$gImg['file']}\" alt=\"$DecodedFileName\"><span class=\"cPseudLink\" onclick=\"SendCmdForm('download','$DecodedFileName')\">$DecodedFileName</span></td>\n");
        printf("<td style=\"text-align:right;\">$val->mKBSize</td>\n<td style=\"text-align:right;\">$val->mDate</td>\n</tr>\n");
        $c++;
}
変更後
//ファイル
foreach($files as $key => $val) {
        if($c % 2 == 0) printf("\n<tr class=\"cEvenColor\">\n");
          else          printf("\n<tr class=\"cOddColor\">\n");
        $DecodedFileName = urldecode($val->mName);
        printf("<td><input type=\"checkbox\" name=\"nFiles[]\" value=\"$DecodedFileName\"></td>\n");
        printf("<td><img src=\"{$gImg['file']}\" alt=\"$DecodedFileName\"><span class=\"cPseudLink\" onclick=\"SendCmdForm('download','$DecodedFileName')\">$DecodedFileName</span>\n");

        if ( eregi("(gif|jpg|jpeg|png|bmp)$",$val->mName) == 1 )
           {
           $mpath2 = ereg_replace("%","%25",$val->mPath);
           $name2  = ereg_replace("%","%25",$val->mName);
           print "<img src=\"data$mpath2/$name2\">" ;
           }

        printf("</td>\n");
        printf("<td style=\"text-align:right;\">$val->mKBSize</td>\n<td style=\"text-align:right;\">$val->mDate</td>\n</tr>\n");
        $c++;
}
赤と青の色の部分は改造したり追加した部分だ。

青はディレクトリ名とファイル名に「%」文字が含まれている場合
「%25」に置き換えるための処理だ。

そして、ファイル名が画像データと判定した場合、<img>タグで、
画像を表示させるのだ。

  早速、改造した結果を見てみる事にした。
  すると・・・

  見事、画像が表示された!! (^^)V

日本語ファイル名「雪だるま.gif」の画像
どうやら「%」を「%25」に置き換えると、問題なく画像が表示されるようだ。
これで全て解決だと思った。

  これで安心だと思ったのだが、これで終わっては良くない。
  なぜなら・・・

  なんで「%」を「%25」に置き換えたら、うまくいくのかが

  説明できへんからや (^^;;

  そうなのです。
  システム奮闘記の連載初期の頃なら、遠山の金さんの最後のセリフのように
「これにて一件落着」で済ましても良かった。でも、今、それをすると
「アカンやん!」と突っ込まれそうになるからだ。
  
  それに、表示がうまくいかなくなった場合、原因を探る必要があるため、
当てずっぽで成功した事を放置せずに、なぜ、成功しているのかを
キチンと把握しておく必要があると考えた。

  そこで、URLエンコードについて、検索サイトで調べたりした。

URLエンコードとは
URLに関する規定を満たすために行う文字変換の処理だ。

URLはASCIIコードの非予約文字以外では使えない事になっている。
そのため、GET型式で、2バイト文字をURLに付加したい場合は
文字変換を行い、URLの規定を満たすようにする役目を果たす。

  そして、URLの規定については・・・

  RFC3986なのらー!

  日頃から英語嫌いで「鬼畜米英」と叫んでいる私なのだが、
悲しい現実として英語を読まなければならない (--;;

  でも、じっくり読まずに、必要な所を探して見ると「%」について
書いてあった。

  URLでは、直接「%」は使えない事になっている。
  そのため、URLエンコードで「%」の文字を「%25」に変換するのだ。

  そのため、URLでファイル名を指定した場合、「%」を「%25」に置き換えると
問題ない事が、ようやく、わかった (^^)


  調べて行くと、URLエンコードは、空白を文字に置き換えてくれる。
  そのため、ファイル名に半角スペース文字が存在しても、
「%20」に変換してくれる。スキマを補ってくれるのだ。

  axlopeでは、日本語のファイル名をURLエンコードを使って
文字変換を行った上で、サーバーに保管している。

  ファイル名の中には、空白文字が入る場合も考えられる。
  そのため、URLエンコードで変換しているのだと思った。


  ふと思った。
  googleやyahooの検索サイトでも、検索結果を出力した際のページの
URLにもURLエンコードが使われているのではないか!

gogleで「神戸」と「ケーキ」で検索してみる
お馴染みのgoogleの検索画面だ。
これに、検索したいキーワードを入力すれば
関連したホームページが出力される。

  神戸といえば洋菓子。ケーキが美味しい地域だ。
  神戸はケーキ激戦区のため、神戸で生き残れるケーキ屋さんは
全国どこでも通用するのだ。しかも、値段も手頃だ。

  ちなみに、コーヒーショップのドトールでは、神戸でのケーキの売行きが
芳しくないという。
  そりゃ、全国最高水準の神戸の美味しいケーキが手頃に食べれるので、
値段の変わらないトドールのケーキを食べたいとは思わなくなる。

gogleで「神戸」と「ケーキ」で検索した結果
神戸とケーキに関連したホームページのサイトが表示される。
夙川(西宮)〜ハーバーランド(神戸市中央区)辺りまでに
美味しいケーキ屋が多い。

私は勝手に「阪神間・ケーキベルト地帯」と呼んでいる (^^)

  でも、今回は美味しいケーキが目的ではなく、検索した後の
ブラウザのURLに注目したいと思います。

検索した後のブラウザのURL
ピンクで線を引いた所に注目。
なんだかURLエンコードで変換された文字列が続いている。

  このURLの部分を全て表示してみると

検索した後のブラウザのURL
青い線で引っ張った所に、検索キーワードがある。
2バイト文字をURLに付加する場合は、URLエンコードする必要がある。

  こんな事、初めて知った (^^;;

  知らず知らずのうちに、URLエンコードと接していたのだなぁと思った。


  だが、まだ不満が残る。
  表示される画像が大きい場合、見づらくなる。

  例えば、普通にHTML言語を使って、大きな画像を表示させてみる事にする。

普通に画像を掲載するHTML
<html>
<body>

<img src="testpic.jpg">

</body></html>
ただ単純に画像データを、そのまま表示させるだけだ。

  するとブラウザの枠を簡単に、はみだしてしまう。

デカい画像を載せたら、完全に、はみだす
これだと何の画像かわからない。
もちろん、ブラウザのスクロール機能で上下左右を行えば
画像全体を見る事はできるが、スクロールバーを操作するため
一目で、わかる大きさの画像で表示したくなる。

  HTML言語では、画像の表示の大きさを変える事ができる。
  <img>タグで、横幅の大きさの指定「width」を行えば良いのだ。

画像の横の大きさを200ピクセルにして掲載するHTML
<html>
<body>

<img src="testpic.jpg" width="200">

</body></html>

  すると画像が小さく表示(横幅200ピクセル)される。

横幅を200ピクセルにしたらブラウザの枠に収まる
これだと動物園のパンダの画像だとわかる。
北京動物園のパンダです。(2008/1/13撮影)
ちなみに、撮影者は私なので、無断引用ではありません (笑)

  これで画像の表示の大きさの問題が解消されると思う。
  方法の1つではあるが、まだ問題がある。


  何枚も大きな画像ファイルを表示させる時、以下の問題が発生する。
  大きな画像は、画像データ自体も大きいからだ!

もし、大きな画像を表示させた場合
サーバーからクライアントへ画像データを送信するのだが
画像データそのものが大きいため、大量のデータ送信が行われる。

  まだ本社のパソコンで見るなら、高速のLANがあるので、
データの読み込みに時間がかからないので良いのだが、
営業所の場合は、そうはいかない。
  通信データは、通信回線を経由して見る事になるからだ。

営業所で見る場合
インターネットVPNで回線を結んでいるのだが、
画像が大きい物で、1Mとか2Mぐらいの大きさの画像を
何枚も掲載されると、画像を取り込んで表示されるまで
時間がかかるため、閲覧者はイライラする事が予想できる。

インターネットVPNに関しては「システム奮闘記:その35」を
ご覧ください。

  仮に、イライラ感が少なくても、インターネットVPNで結んでいるため、
大量のデータ送信を、公共の場では行うのは、いかがな物かと思う。


  <img>タグの「width」を使わずに、表示する画像を小さくできないか。
  もう1つの方法がある。それは

  表示する画像データそのものをプログラムで加工すれば、ええやないか!

  大阪発のECサイトのオープンソース「EC-CUBE」を導入する際、
プログラム(PHP言語)を眺めていて、画像の大きさの加工処理を行う
プログラムがあり、それで掲載する商品の画像の大きさを加工している。

  イメージ関数と呼ばれる物を使っているのだ。
  なので、EC-CUBEのプログラムを見て初めて

  PHPのイメージ関数の使い方を知ったのだ!

  EC-CUBEについては「システム奮闘記:その65」をご覧ください。


  北京動物園のパンダの写真は「jpg」型式の画像データだ。
  なので、「jpg」型式の画像処理のプログラムを書いてみる事にした。

イメージ関数を使って画像の表示で
横幅を200ピクセルにするプログラム
<?php

//  ヘッダーに表示させるデータをJPGデータを指定
header('Content-type: image/jpeg');

//  パンダの画像の大きさの情報を得る。
$result = getimagesize("testpic.jpg");

//  URLやファイルから画像を生成する関数。
//  ここでは加工したいファイル名を指定する。
//  返り値はイメージIDと呼ばれる物で、
//  加工される画像を識別するIDとなる。
//  「$im」に格納される。
$im = @imagecreatefromjpeg("testpic.jpg");

//  横幅を200ピクセルにした場合、縦の縮尺も合わせるため
//  縦幅のピクセル数を算出する。
//  $result[0] は、元のファイルの横幅の大きさ(ピクセル数)だ。
$width = 200 ;
$per   = $width / $result[0] ;
$height = $result[1] * $per ;

//  新規の画像を作成
//  絵で例えると、白いキャンパスを用意するのと同じだ。
//  白いキャンパスの横幅と縦幅を指定する。
//  返り値は、白いキャンパスを認識するIDだ。
$thumb = imagecreatetruecolor($width, $height);

// 画像のコピーとコピーの時に画像の大きさを変える関数。
// 加工したい画像ID($im)と、横幅($result[0])、縦幅を指定($result[0])。
//  コピー先の画像ID($thumb)と、横幅($width)、縦幅($height)を指定。
imagecopyresized($thumb, $im, 0, 0, 0, 0, 
                 $width, $height, $result[0], $result[1]);

//  上の関数で、元の画像をコピーすると同時に
//  画像の大きさを変える事ができたので
//  その画像をブラウザに出力させる関数
imagejpeg($thumb);

?>
コメント文で、ゴチャゴチャした感じがあるのだが、
関数の説明という意味で書きました。

まぁ、私の知識の整理という意味合いの方が濃厚ですが (^^;;

  早速、実行してみる。
  結果は・・・

  見事、成功 (^^)V

プログラム中で画像データを
横幅200ピクセルに加工して出力した結果
プログラム中で大きさを加工したパンダの画像が表示されている。

これで元のファイルの大きさが、どんなにデカくても
プログラム中で加工してデータ自体も小さくしてくれるため
データの読み込みに時間がかからなくなる上、
通信量も減らす事ができる。

  さて、イメージ関数を使った画像の加工を、axlopeにも適用したい。

  そこで、再びファイルを表示させるライブラリ(lib/axlope01.inc)の
改造を行う事になった。
  そして、画像出力のためのプログラムも追加する事にした。

lib/axlope01.inc の改造
初期状態
//ファイル
foreach($files as $key => $val) {
        if($c % 2 == 0) printf("\n<tr class=\"cEvenColor\">\n");
          else          printf("\n<tr class=\"cOddColor\">\n");
        $DecodedFileName = urldecode($val->mName);
        printf("<td><input type=\"checkbox\" name=\"nFiles[]\" value=\"$DecodedFileName\"></td>\n");
        printf("<td><img src=\"{$gImg['file']}\" alt=\"$DecodedFileName\"><span class=\"cPseudLink\" onclick=\"SendCmdForm('download','$DecodedFileName')\">$DecodedFileName</span></td>\n");
        printf("<td style=\"text-align:right;\">$val->mKBSize</td>\n<td style=\"text-align:right;\">$val->mDate</td>\n</tr>\n");
        $c++;
}
変更後
//ファイル
foreach($files as $key => $val) {
        if($c % 2 == 0) printf("\n<tr class=\"cEvenColor\">\n");
          else          printf("\n<tr class=\"cOddColor\">\n");
        $DecodedFileName = urldecode($val->mName);
        printf("<td><input type=\"checkbox\" name=\"nFiles[]\" value=\"$DecodedFileName\"></td>\n");
        printf("<td><img src=\"{$gImg['file']}\" alt=\"$DecodedFileName\"><span class=\"cPseudLink\" onclick=\"SendCmdForm('download','$DecodedFileName')\">$DecodedFileName</span>\n");

        if ( eregi("(gif|jpg|jpeg|png|bmp)$",$val->mName) == 1 )
           {
           $DirOut = ereg_replace("%","%25",$val->mPath);
           $FileOut = ereg_replace("%","%25",$val->mName);
           print "<br><img src=\"lib/axlope-pic.php?dir={$DirOut}&file={$FileOut}\">\n" ;
           }

        printf("</td>\n");
        printf("<td style=\"text-align:right;\">$val->mKBSize</td>\n<td style=\"text-align:right;\">$val->mDate</td>\n</tr>\n");
        $c++;
}
色を付けた部分は改造した部分だ。

赤い部分はファイル名の拡張子で、ファイルが画像かどうかの判定を行い、
画像ファイルの場合なら、ファイル名、ディレクトリ名の中に
「%」が含まれれば、「%25」に置き換える処理を行う。

青い部分が画像を表示させる<img>タグだ。
<img>タグの部分で、画像を加工・出力させるプログラムを走らせ
画像を表示させる方法にした。

  さて、画像を加工・出力させるプログラムだ。
  これは、axlope01.inc と同じ libディレクトリーに置いておく。

追加したプログラム(lib/axlope-pic.php)
<?php
//---------------------------------------------------------------------------
//Charactor set is UTF-8
//漢字コードはUTF−8
//---------------------------------------------------------------------------

// 画像データの格納されているディレクリ
$dir = $_GET['dir'];  

// 画像データのファイル名
$file = $_GET['file'] ;

//  画像データの拡張子を抽出する。
//  画像型式によって、画像加工に使うイメージ関数が異なるため
eregi("(gif|jpg|jpeg|png|bmp)$",$file , $form) ;

// jpgの場合、拡張子が「jpg」と「jpeg」になっている場合があるので
// 抽出した拡張子の中身を「jpeg」にまとめる。
if ( $form[1] == "jpg" ) $form[1] = "jpeg";
$form[1] = strtolower($form[1]) ;

//  画像データのディレクトリーとファイル名
$file = "../data".$dir."/".$file ;

//  画像データの大きさ
$result = getimagesize($file);

//  加工する画像データを読み込み、画像IDを割り当てる。
//  この際、個々の画像型式別に関数を使い分ける。
if ( $form[1] == "jpeg" )  // jpgの場合
   {
   $im = @imagecreatefromjpeg($file);
   }
else if ( $form[1] == "png" )  // pngの場合
   {
   $im = @imagecreatefrompng($file);
   }
else if ( $form[1] == "gif" ) // gifの場合
   {
   $im = @imagecreatefromgif($file);
   }
else if ( $form[1] == "bmp" ) // bmpの場合
   {
   $im = @imagecreatefromwbmp($file);
   }


if ( $im )
   {
   //  画像IDが割り当てられた場合(加工したデータが読み込めた場合)

   //  横幅を150ピクセルにして、縦の縮尺を合わせる。
   $per   = 150 / $result[0] ;
   $width = 150 ;
   $height = $result[1] * $per ;

   // 加工した画像をコピーする先の画像IDを割り当てる。
   $thumb = imagecreatetruecolor($width, $height);
 

   //  画像データを加工して、それをコピー先にコピーする。
   imagecopyresized($thumb, $im, 0, 0, 0, 0, 
                    $width, $height, $result[0], $result[1]);

   //  画像の出力のためのヘッダー
   header('Content-type: image/$form[1]');


   // 個々の画像型式に合わせて画像の出力
   if ( $form[1] == "jpeg" )
      {
      imagejpeg($thumb);
      }
   else if ( $form[1] == "png" )
      {
      imagepng($thumb);
      }
   else if ( $form[1] == "gif" )
      {
      imagegif($thumb);
      }
   else if ( $form[1] == "bmp" )
      {
      imagewbmp($thumb);
      }

   imagedestroy($im);
   imagedestroy($thumb);
   }
else
   {
   //  画像データが読み込めなかった場合
   //  「読み込めなかった」を表示する画像を作る
   $im = @imagecreate(200, 40);

   //  画像で使う色を指定。色をIDで返す。
   //  ここでは「読めなかった」の文字の色を青に指定
   $textcolor = imagecolorallocate($im, 255 , 0 , 0);

   // 「can't display picture!」という文字列を含んだ画像生成
   imagestring($im, 4, 10, 15, "can't display picture!", $textcolor);


   header('Content-type: image/png');

   //  png型式として画像を出力
   imagepng($im);
   imagedestroy($im);
   }

?>

  早速、動かしてみる。
  さきほど、デカデカ(?)と表示させていた「雪だるま」の画像が

  見事、縮小されて表示されている (^^)V

日本語ファイル名「雪だるま.gif」の画像

  見事に、画像を縮小表示する事ができた。
  これだと本社以外でアップロードされている画像を見る場合でも
営業所でデータを取り込むのに時間がかかって、イライラする問題は
発生しなくなる。


  これで、うちの会社で使う場合での、axlopeの改造は終わった。
  だが、オープンソースなので、用途に合わせて自由に改造できる、

  自由に改造こそオープンソースの醍醐味だ!

  自由に改造する度に、オープンソースの素晴らしさを感じる今日この頃 (^^)

まとめ EC-CUBEに引続き、国産のオープンソース・axlopeを取り上げました。 日本発のWebファイルマネージャーだけに日本語の処理ができる。 axlopeを見つけるまでは、海外のWebファイルマネージャーの導入を 検討しましたが、日本語対応の問題がある上、今の私の実力では とても対応できないため、諦めていました。 そのため、axlopeは、ありがたい存在に思えました。 私は、axlopeを応援したいと思います。 頑張れニッポン! 日出づる国・日本! オープンソースの日(ソフト)が、続々と出てくる事を期待したいと思います。 そして、私も、できる限り、日本発のオープンソースを導入し、 システム奮闘記に取り上げたいと思います (^^)

次章:「セキュリティー入門」を読む
前章:「無料のオープンソースECサイト(EC-CUBE)でネット販売システム構築」を読む
目次:Linux、オープンソースの「システム奮闘記」に戻る