Nucleus(JP)フォーラム

NucleusCMS日本語版ユーザーのためのサポートフォーラムです。疑問が生じたらまずは記事検索をご利用ください。

ログインしていません。

#1 2011-04-04 12:09:02

Mocchi
メンバー
登録日: 2006-11-19
投稿: 438

Re: NP_MediaUtils

Mocchiです。

NP_MediaUtilsを公開します。最新版は0.9.6 (RC2)です。ファイル表示/管理/処理系プラグインのベータテストにご協力下さいでベータテストを行っていたものです。画像だけではなくファイル一般を扱うことができます。

このプラグインは、以下のメディアファイル管理プラグインのためのライブラリとして機能します。
NP_Thumbnail (ver.3.9.6以上)
NP_Attach
NP_ImageLimitSize (ver.0.9.6以上)
NP_ImprovedMedia (ver.3.9.6以上) 開発中

詳細はWikiの記事に書いておきますが、これは主にプラグイン開発者向けの情報となります。

Nucleus CMSのバージョン3.40以上、PHPのバージョン5以上が推奨環境となります。

なお、Mediumオブジェクトのリサンプリングメソッドは、PHPで標準的に利用できるGD (Graphics Draw) Libraryのバインディングを利用しています。サーバ環境によっては機能に制限が出るかもしれません。


Attachments:
zip NP_MediaUtils(ver.0.9.6).zip, Size: 7.19 KiB, Downloads: 750

オフライン

#2 2011-04-05 14:25:12

Mocchi
メンバー
登録日: 2006-11-19
投稿: 438

Re: NP_MediaUtils

これは主に開発者向けの情報となるかと思います。

問題点

PHPで大きな画像をGDバインディングで処理する際、「Fatal error: Allowed memory size of XX bytes exhausted (tried to allocate XX bytes) in XXXX」が発生することがあります。これは、リサンプリングに必要なメモリ消費量に対して、サーバからPHPに割り当てられているメモリ量が少ないために発生します。

原因

通常、PHPのGDバインディングで画像をリサンプリングするには、以下の2つのデータ用にサーバ上でメモリを確保する必要があります。
1. 元画像をGDフォーマットに展開したデータ
2. リサンプリング画像の雛形となるGDフォーマットデータ

1.で確保したGDフォーマットのデータからリサンプリング後のピクセルを算出して2.の雛形に流し込むことで、リサンプリングを行っています。もし画像が大きすぎる場合は、1.の途中でメモリを使い切ることになります。エラーの原因はこれです。

標準的な対策

現在一般的に対策とされているのは、スクリプトに「ini_set("memory_limit", "(任意の数値)M");」を記述することで、そのスクリプトの実行セッション限定で、PHPへの割り当てメモリ量を増やす方法です。さっとググってみた限り、たいていは128Mや256Mが設定されているようです。

付録 > php.ini ディレクティブ > コア php.ini ディレクティブに関する説明 > リソース制限 @ php.net

名前 デフォルト 変更の可否 変更履歴
memory_limit "128M" PHP_INI_ALL PHP 5.2.0 より前は "8M"、PHP 5.2.0 では "16M"

以下に設定ディレクティブに関する簡単な説明を示します。

memory_limit integer
スクリプトが確保できる最大メモリをバイト数で指定します。この命令は、 正しく書かれていないスクリプトがサーバーのメモリを食いつぶすことを防止するのに役立ちます。 もし、使用可能メモリに制限を設けたくない場合は、 ここに -1 を指定してください。

PHP 5.2.1 より前のバージョンでは、このディレクティブを使うためには、 コンパイル時に configure で --enable-memory-limit を指定しなければなりません。 このコンパイルフラグは、関数 memory_get_usage() および memory_get_peak_usage() を 5.2.1 より前のバージョンで使う際にも必要となります。
integerを使用する際、その値はバイト単位で測られます。 この FAQ に記載された短縮表記を使用することも可能です。

なお、以下を参照すると、PHP_INI_ALLはどこででも設定できることを意味するようです。そのため、ini_set() でも設定できるようです。ini_setを制限するような設定はなさそうなので、たぶんどんなサーバでも有効かと思います。
インストールと設定 > 実行時設定 > どこで設定を行うのか @ php.net

なお、PHP5.3以降は128MBが標準となるようなので、このエラーにお目にかかることはまずなくなるかと思います。

今回の対策

さて、今回はこの対策は使っていません。エラーの直接的な回避方法をMediumオブジェクトのリサンプリングメソッド「getResamplerBinary」に実装してみました。

これは、リサンプリングにおいて消費しそうなメモリーの量を前もって計算することで、サーバにおいてPHPに割り当てられているメモリサイズでリサンプリング可能かどうか判定し、超過しそうな場合は処理を中止するというものです。あまりにも大きな画像ファイルはリサンプリングされないようになっています。

/nucleus/plugins/mediautils/Medium.php 153行目から168行目
(計算式はバイトオーダー)

// check current available memory
$memorymax = trim(ini_get("memory_limit"));
switch (strtolower ($memorymax[strlen($memorymax)-1])) {
	case 'g':
		$memorymax *= 1024;
	case 'm':
		$memorymax *= 1024;
	case 'k':
		$memorymax *= 1024;
}
		
// these codes are based on analyzing gd.c in php source code
// if you can read C/C++, please check these elements and notify us if you have some ideas
if ((memory_get_usage()
 + ($this->resampledwidth * $this->resampledheight * 5 + $this->resampledheight * 24 + 10000)
 + ($this->width * $this->height * 5 + $this->height * 24 + 10000))
 > $memorymax) {
	return FALSE;
}

なお、この計算式はきゃしゃさんとkatsumiさんの協力のもとで求めました。

サーバ環境においては、PHPとは別なプロセスで起動したGDライブラリに処理を投げるようになっているものがあります(Debian系のPHPパッケージがこんな感じ)。この場合はPHPがメモリ管理を行わないため、どんなサイズの画像もリサンプリング出来る能力があります。

しかしこの場合も、先述のメモリ超過判定によって処理が中止されます。これは、GDライブラリが別プロセスかどうかを判定する方法を、私が知らないためです。そのため、このようなサーバ環境の場合は、サーバの能力をフルに発揮できないこととなります。

メモリーの予想使用量は、PHPのソースコードからgdに関するものを参照して求めました。メモリブロックなどの計算に不慣れなので、現在は実メモリ消費量を計算式に反映しました。

将来的には別プロセスなGDライブラリに処理を投げるのが主流となるだろうと思いますので、ひょっとしたら近い将来、この判定式は必要なくなるかもしれません。というか、そうなったらいいなぁ程度なんですけどね。。。

たぶんそれなりに妥当な計算式となっているかと思います。が、もし先述のメモリ超過エラーが発生した場合は、報告してくださると助かります。計算式の見直しをします。

オフライン

#3 2011-04-05 16:00:56

Mocchi
メンバー
登録日: 2006-11-19
投稿: 438

Re: NP_MediaUtils

また、リサンプリングをバッチ処理するにあたり、スクリプト実行時間の問題もありました。リサンプリングは結構重い処理なので、それなりに時間がかかります。スクリプトの実行時間制限が来てもバッチ処理が終わらない可能性があります。

これに関しては、リサンプリング処理を実行する度に、スクリプトの実行時間をリセットするようにしてあります。

/nucleus/plugins/mediautils/Medium.php 199行目

set_time_limit(ini_get('max_execution_time'));

関数「set_time_limit」はセーフモードでは使うことができませんので、セーフモードを有効にしたPHPで動作している場合、NP_Thumbnailのリサンプリングのバッチ処理の途中で実行時間超過エラーが発生する可能性があります。

関数リファレンス > set_time_limit @ php.net

なお、セーフモードはPHP5.3.0で非推奨に、次期バージョンであるPHP6では削除されます。

機能 > セーフモード @ php.net

オフライン

#4 2011-04-05 16:27:17

Mocchi
メンバー
登録日: 2006-11-19
投稿: 438

Re: NP_MediaUtils

PHP側の実行時間制限は上記で設定できますが、今度はウェブブラウザ側のHTTP接続時間制限を考慮する必要があります。

Internet Explorerに関しては、以下のドキュメントが参考になります。

Internet Explorer エラー「接続がタイムアウトしました」がいつサーバー応答しません。 @ support.microsoft.com

  5 分 Internet Explorer 4.0 および Internet Explorer 4.01
60 分 Internet Explorer 5およびInternet Explorer 6
60 分 Internet Explorer 7 および Internet Explorer 8

Safariは60秒のようです。

Safari FAQ > 10. Safariはどのようにしてサーバのタイムアウトを処理しているのですか? @ developer.apple.com

Firefoxではそのような設定は見つかりませんでした。

Mozilla networking preferences > HTTP @ developer.mozilla.org

さっとググって見た限り、HTTP1.1のKeep Alive設定を変更するようなものが多く見つかりました。個人的には、ブラウザのリクエストタイムアウトとHTTP通信におけるKeep-Alive設定は別なものじゃないのかなと思ったりしてます。

Keep-AliveとInternet Explorerに関しては以下。

Internet Explorer のデフォルトの Keep-Alive タイムアウト値を変更する方法 @ support.microsoft.com

おそらくFirefoxでは、Keep-aliveを短めにして、一回のコネクションとkeep-aliveの持続時間を同じように扱っているのかと。昔と比べると1つのウェブページが要求するHTTP通信が非常に多くなったので、こういう実装になっているのかなぁと思いました。(となると、リクエストタイムアウトはIEなどブラウザベンダーの独自拡張になる?)

各社こんな感じなので、ブラウザのタイムアウト防止のために、実行時間が長くなることが予想されるPHPスクリプトは、スクリプト側で関数「flush」や関数「ob_flush」を実装して、適当にブラウザ向けにパケット送出してあげる必要ありかなと、今書いてて思いました。NP_Thumbnailの次期バージョン(ver.4.0.0かな?)で実装することにします。

# Microsoftは情報がちゃんと整理されていていいなぁ。

オフライン

#5 2011-04-06 10:40:55

Mocchi
メンバー
登録日: 2006-11-19
投稿: 438

Re: NP_MediaUtils

ver.0.9.6 (RC2)ではウェブログIDをブラウザに保存するため、InitSkinParse、PostAuthentication、PreSendContentTypeの各イベントでクッキーを設定していました。が、昨日風呂に入りながら考えていたら、これはおかしいことに気づきました。

ネットワーク 関数 > setcookie @ php.net

クッキーの設定タイミングは、HTTPヘッダー以外の出力がなされる前です。ウェブサーバからブラウザに送信されるHTTPヘッダーの中でクッキーが送信されます。そのため、PreSendContentTypeイベントで送信しておくだけで十分でした。

時期バージョンであるver.1.0.0はこのように変更します。なお、この変更によって、システム全体から見たスクリプトの役割が変化することはありません。多少効率がよくなるくらいです。

オフライン

#6 2011-04-06 14:15:56

Mocchi
メンバー
登録日: 2006-11-19
投稿: 438

Re: NP_MediaUtils

これは、画像処理にちょっとこだわりたい方向けの情報です

JPEGやTIFFには、カラーマネジメントのためのプロファイルが埋め込まれることがあります。

カメラやスキャナなどでは、ハードウェアが取得できる色の幅が、装置によって決まっています。この色の幅は「色空間(カラースペース)」と呼ばれます。デジタルカメラやスキャナの中には、取得したデータに、色空間に関する情報、すなわちカラーマネジメントのためのプロファイルを埋め込むものがあります。

このプロファイルは、インターナショナル・カラー・コンソーシアムという標準化団体が規格を出していて、この規格に沿ったものは頭文字を取ってICCプロファイルと呼ばれたりします。

映像を取得する側もそうですが、映像を映し出すディスプレイや、映像を印刷するプリンタもこのプロファイルを持っています。特にプリンタは、光学的な3要素(赤・緑・青、RGB)を塗料の4要素(シアン・マゼンダ・イエロー、キーカラー=ブラック)に変換する必要から、このプロファイルを個別に持っています。たいていはプリンタドライバがこのプロファイルをシステムにインストールするようになってます。

さて、NP_MediaUtilsで利用しているPHPのGDライブラリ・バインディングは、PHPで標準的に使うことが出来る画像処理系です。が、画像からカラープロファイルを取り出す、画像にカラープロファイルを埋め込むといった操作ができません。

画像処理および作成 > 画像処理 (GD)  php.net

そのため、MediumオブジェクトのgetResampledBinary関数でリサンプリングした画像は、元の画像のプロファイルを維持できませんし、隣接ピクセル間からリサンプリング後のピクセル値を算出する際に、カラープロファイルを考慮した計算ができません。

この性質は、NP_MediaUtilsに画像処理を依存しているNP_ImageLimitSizeに影響します。このプラグインは、アップロードされた画像をリサンプリングして保存しますが、前述のとおり、カラープロファイルやExif情報をカットします。そのため、リサンプリング後のデータを表示する場合、ブラウザがカラー・マネジメント・プロファイルに対応していても、色空間は標準的に使われているもの、おそらくsRGBが適用されてシステムの表示系に回されるかと思います。

なお、JPEGにはExif情報を含むものもありますが、PHPの処理系では、このExif情報を読み取ることは出来るものの、再設定することが出来ないようでした。そのため、リサンプリング後の画像にもExif情報を埋め込むというのは、PHPの標準的な設定では不可能です。

画像処理および作成 > Exif 関数 @ php.net

色空間の正確な再現やExif情報の埋め込みを望む方は、NP_ImageLimitSizeは使わずに、リサンプリングなどの処理をちゃんとしたデスクトップアプリケーションで行い、アップロードすることをおすすめします。

PHPの画像処理系には、GDライブラリバインディングの他に、ImageMagickライブラリ・バインディングやGmagickライブラリ・バインディング、Cairoライブラリ・バインディングが使えます。どれも強力な処理系ですが、PHPの標準的な設定では利用できません。そのため、このプラグインでの実装は見送っています。

画像処理および作成 @ php.net

オフライン

#7 2011-04-08 17:48:59

Mocchi
メンバー
登録日: 2006-11-19
投稿: 438

Re: NP_MediaUtils

Mediumクラスのコンストラクタで、プロパティ$medium->mimeにファイルのMIME型を設定するように作ってあります。

MIME型の検出は以下のプロセスで実装してあります。
1. 全てのファイルでgetimagesizeを実行。画像ファイルならそのMIME型(image/pngなど)が入り、画像でなければ「application/octet-stream」が設定されます。
画像処理および作成 > getimagesize @ php.net

2. PHP5.3.0以降であればPHPのlibmagicライブラリ・バインディングであるFileinfo関数を標準で利用することができます。この関数が利用可能で、$medium->mimeに「application/octet-stream」が設定されていたら、Fileinfo関数による検出をします。
ファイルシステム > Fileinfo @ php.net

こんな感じなので、PHPの古いバージョンでも、画像を処理する上では適切なMIME型を利用することができると思います。

MIME型を使利用するとファイルタイプを一意に扱えるため、便利です。MIME型はRFCで定められているので、PHPだけではなく処理系一般で一意となります。
(本来はmultipart/form-dataやメールメッセージへの添付ファイルを実装するために定められました)

オフライン

#8 2011-04-08 18:12:57

Mocchi
メンバー
登録日: 2006-11-19
投稿: 438

Re: NP_MediaUtils

PHPのGDライブラリ・バインディングでは、BMPフォーマット(正式にはMicrosoft Windows Bitmap Image)を扱うことが出来ません。

BMPフォーマットは、現在はMicrosoft社が仕様を公開しています。元々はIBM社と共同で策定したフォーマットでしたが、OS/2とWindowsの2つのオペレーティングシステムで異なるフォーマットが使われだし、OS/2が下火になった今、Microsoft社のフォーマットが主流になっているといった感じです。

Bitmaps (Windows) @ msdn.microsoft.com

GDライブラリで画像を扱う場合、一度、画像ファイルからGDフォーマットのデータを作ります(デコード)。そのデータに対して処理をした後、GDフォーマットから画像データに変換します(エンコード)。PNGやJPEG、GIFなどはこのデコード/エンコードのどちらも可能なのですが(gd_info関数でチェック可能)、BMPフォーマットの処理系は実装されていません。

まぁWWW上でBMPフォーマットの画像を使う機会はあまり、というかほとんどないんですが、私が関係しているプロジェクト「Jeans CMS」でPHPのBMPフォーマット画像処理系を書いたので、GPLライセンスのもと、NP_MediaUtilsのバージョン1.0.0にBMP画像処理系を含めようかなと考えています。

ただし今のところ、色深度が24ビットまでの非圧縮なものしか処理できず、また、デコードする処理系しか書いていないという体たらく。しかも8ビットと16ビットはバグが報告されてます。まぁ、せっかく書いたので、デバッグとメンテナンスがてら同梱してしまいたいなぁ、と。。。

オフライン

#9 2011-09-22 17:56:46

dan
メンバー
登録日: 2007-08-14
投稿: 73

Re: NP_MediaUtils

皆さん、いつもお世話になっています。

「NP_MediaUtils」についてご報告です。

「NP_ImageLimitSize」を使いたくて、まずは「NP_MediaUtils」をインストールしようとしたのですが、
インストールを実行したら、画面が真っ白になりました。
リロードしても真っ白画面から戻らないので、いったんFTPクライアントでプラグインを削除してみました。

すると、プラグインリストの最下部に以下のエラーが表示されました。

エラー: プラグインファイル NP_MediaUtils.php を読み込めませんでした。ファイルが存在しない、もくは使用中の Nucleus 上で動作させるために必要な機能がプラグインでサポートされていません。(管理操作履歴に詳細があります。)

それで管理履歴を見ますと、

Plugin NP_MediaUtils was not loaded (File not found)

と出ていました。

アップロードすべきファイルが欠けているのではないかと思い、ZIPファイルを解凍し直してみて、
何度かやり直したのですが結果は同じでした。

このような経過で、プラグインがインストールできない状況です。

▼ZIPファイルを解凍してできたファイル
=====
NP_MediaUtils.php
[mediautils]dir
┣MediaUtils.php
┗Medium.php
=====

▼環境は以下の通りです。
=====
Nucleus のバージョン  3.64(v3.64)
PHP のバージョン  5.2.17
MySQL のバージョン  5.1.34-log (5.0.45)
レンタルサーバ ロリポップ
=====

オフライン

#10 2011-09-22 19:56:31

Mocchi
メンバー
登録日: 2006-11-19
投稿: 438

Re: NP_MediaUtils

danさん

不具合報告どうもありがとうございます。

バグを作りこんでしまっているようなので、ちょっと確認してみますね。

とりあえずはプラグインロードできないエラーをなくす方法をお伝えします。プラグインリストの画面でNP_MediaUtilsを削除していただければたぶん大丈夫です。

オフライン

#11 2011-09-23 00:07:04

dan
メンバー
登録日: 2007-08-14
投稿: 73

Re: NP_MediaUtils

Mocchiさん、ありがとうございます。

Mocchi さんの発言:

とりあえずはプラグインロードできないエラーをなくす方法をお伝えします。プラグインリストの画面でNP_MediaUtilsを削除していただければたぶん大丈夫です。

その方法で、プラグイン管理画面は通常に戻りました。

なお、「plugins」ディレクトリに問題のあるプラグインファイルが存在したままだと(FTP経由で削除しないと)、
「プラグイン管理画面」自体が正常に表示されないので、プラグインをアンインストールしたくても
できないということは、今回初めて知りました。

・問題が起きたらまずFTPクライアントでプラグインを削除する

・プラグイン管理画面でアンインストールする

と、こんな手順になるのですね。

今後の参考にしたいと思います。

オフライン

#12 2012-06-24 16:59:27

mooh-fr
メンバー
登録日: 2007-10-06
投稿: 28

Re: NP_MediaUtils

NP_MediaUtilsでのエラー報告です。

public_html/ここにニュークリアス設置
         /EXEMPLE/ここに別のニュークリアスを設置/

このような場合に階層化EXEMPLEのニュークリアスでメディアをアップロードしようとすると

XML パースエラー: 整形式になっていません。
URL: http・www.ABCD.com/EXEMPLE/nucleus/media.php
行番号: 33, 列番号: 67:    <p><a href="media.php" onclick='history.back(); return false;">戻る</a></p>
-------------------------------------------------------------------------^
と言うエラーが出ます。
/nucleus/が追加されてしまうようです。

そしてImageLimitSize Version 0.9.6 (1.0 RC2) for PHP5
をさらにプラグインインストールしても同じエラーが当然にでます。

アンインストールすれば正常にもどります。
ご確認いただければと報告させていただきました。
挨拶省略失礼します。

オフライン

#13 2012-06-24 21:41:40

Mocchi
メンバー
登録日: 2006-11-19
投稿: 438

Re: NP_MediaUtils

mooh-fr さんの発言:

XML パースエラー: 整形式になっていません。
URL: http・www.ABCD.com/EXEMPLE/nucleus/media.php
行番号: 33, 列番号: 67: <p><a href="media.php" onclick='history.back(); return false;">戻る</a></p>
-------------------------------------------------------------------------^

「http・www.ABCD.com/EXEMPLE/nucleus/media.php」はNucleus CMSのデフォルトのメディア管理機能です。そのためこのエラーは、NP_MediaUtilsをインストールしている、いないに関わらず発生するように思います。再度確認していただけますでしょうか?

オフライン

#14 2012-06-24 22:44:56

mooh-fr
メンバー
登録日: 2007-10-06
投稿: 28

Re: NP_MediaUtils

ありがとうございます
すいません、
これを報告する前の現象で、
①一度アップロードが可能だった
②その後プラグインをインストールしエラー
③そして、プラグインアンイストールごアップロード可能
④エラー確認の為に
⑤再度プラグインインストールしてエラー
⑥そしてアンストールしアップロード
を確認してから、書いたのですが、

今確かめた所、アンイストールした状態でエラーが出ていました。

Nucleus v3.62
XREAサーバーを使用しております。
PHP    5.2.5
RUBY    1.8.5
MySQL    5.1.17
PostgreSQL    8.1.9
====================追記======
ニュークリアスをインストールし直し(v3.64)
画像アップロード 成功
プラグインをインストール
画像アップロード エラー
プラグインアンインストール
プラウザ再立ち上げ
画像アップロード エラー
と言う現象です。
再度プラウザ立ち上げ直し
画像アップロード 小 成功
小 成功
設定超過さいず 表示のエラー がでます

画像サイズが設定(1048576BYTE)より大きいものはこのエラーが表示されているのかもしれません

オフライン

Board footer