2008年1月27日日曜日

PHPでファイルを zipするためのサンプルと 4つの注意点

PHPでzipするサンプルと注意点。


注意点

  • (Windowsの場合) php.iniの、extension=php_zip.dllのコメントアウトを外しておかないと、「Fatal error: Class 'ZipArchive' not found」が出る。
  • zipのopen時に、
    • ZIPARCHIVE::CREATEを指定すると、指定したパスにまだzipが無い場合は新規作成し、既にzipがある場合はそのzipに各ファイルが追加される。
    • ZIPARCHIVE::OVERWRITEを指定すると、常にzipを新規作成する。既存のzipがある場合は、zip自体を上書きする。(2009/03/23訂正:仕様が変わり、既存のZIPが無い場合にOVERWRITEを指定するとopen()に失敗するようになった。対策は下記サンプルコードを参照。)
  • zipを展開するクライアントがWindowsの場合、ファイル名はSJISにしないと文字化けする。
  • zipをダウンロードさせる場合、Content-typeに既知の値("application/zip"や"application/x-zip-compressed")を指定すると、IEでダウンロードするとzipを展開できない。なのでContent-typeには存在しない適当な値を指定する。(未知のContent-typeの場合は拡張子からzipであることを推測しているようだ。)
    ただし7-zipでなら開けたので、正しいContent-typeでもzip自体は正しくできているようだ。


サンプルコード
<?php
$zipPath = './test.zip';

//zipをopenする
$zip = new ZipArchive();
$rtn = $zip->open('./test.zip', ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE);
if ($rtn !== true) {
 exit('zip作成に失敗! エラーコード=' . $rtn);
}

//ファイルをzipに追加する
$zip->addFile('./zip.php', 'zip.php'); //ファイルのパスとzip後のファイル名
$zip->addFile('./zip.php', mb_convert_encoding('このPHPのソースファイル.php', 'SJIS'));

//テキストファイルを動的にzipに追加する
$text = " 動的に書いた \n テキストファイル ";
$zip->addFromString('dynamic.txt', $text); //ファイルのパスとその内容

//zipをcloseする
$zip->close();

//zipファイルを出力する
header('Content-type: application/x-zip-dummy-content-type'); //存在しないtypeにする
$zipName = mb_convert_encoding('zipのテスト.zip', 'SJIS');
header('Content-Disposition: attachment; filename=' . $zipName);
echo file_get_contents($zipPath);

(更新履歴)
2009/03/23 openの第2引数を変更


参考:
 PHP: Zip - Manual
 codeなにがし::ブラウザ上でローカルファイルをZIP圧縮 (文字コードについての参考)
 ZIP (ファイルフォーマット) - Wikipedia (Content-typeについての参考。使えなかったが。)

PHPで 外部プログラム(CUI)と対話的に処理を進める方法

PHPで外部のコマンドラインプログラムを実行し、標準入力によるデータの入力や標準出力からのデータの受取りをしながら、対話的に処理を進める方法。

関数 proc_open() を使う。

<?php
$inout = array(
  0 => array('pipe', 'r') //標準入力 ('pipe' or 'file')
 , 1 => array('pipe', 'w') //標準出力 ('pipe' or 'file')
 , 2 => array('file', '/tmp/proc_open_error.log', 'a') //エラー出力 ('pipe' or 'file')
);

$proc = proc_open('php', $inout, $pipes); //外部プログラムとしてphpを実行する場合

if (is_resource($proc)) {
 fwrite($pipes[0], '<?php echo "Hello proc_open()!"; ?>'); //標準入力として渡す文字列
 fclose($pipes[0]);

 echo stream_get_contents($pipes[1]); //標準出力から受け取る
 fclose($pipes[1]);

 echo 'return value = ' . proc_close($proc);
 //参考:proc_close()の前に全てのpipeを閉じる必要があるらしい
}

参考: PHP: proc_open - Manual

PHPで Content-typeを指定してテキスト以外のファイルを出力する

Web上のPHPにアクセスされた時に、画像ファイル等のテキスト以外のファイルを返す方法。


header()でContent-typeを指定して、echoでバイナリデータを書き出す。
echoの前に既に出力があると、うまくいかない。(エラーメッセージが出力された場合など。)

画像ファイルを出力する場合の例

header('Content-type: image/jpeg');
echo file_get_contents($path);


ファイルをダウンロードして保存する場合にファイル名を指定したい場合は、上記に加えてContent-Dispositionを指定する。
指定しない場合はphpのファイル名がそのままダウンロードしたファイル名になる。(拡張子もそのまま.phpなどとなる。)
クライアントがWindowsの場合、ファイル名はSJISでないと文字化けする。
$fileName = mb_convert_encoding('日本語.ext', 'SJIS');
header('Content-Disposition: attachment; filename=' . $fileName );

Windowsのコマンドプロンプトの文字コードを変える方法

Windowsのコマンドプロンプトでエラーメッセージ等が文字化けすることの原因は文字コードの設定。
コマンドプロンプトのデフォルトの文字コードはShift_JISになっている。
ApacheやSubversionなどUTF-8で出力するアプリをコマンドプロンプトから使うと、メッセージが文字化けすることがある。

下記のようにすれば文字コード設定を変えられる。

chcp 65001

"65001"はUTF-8のコードページ。Shift_JISの場合は"932"。
他の文字コードについては下記リンクのリンク先から調べられる。


参考: UTF-8とコマンドプロンプトとMySQLモニタ | Sarabande

2008/07/08追記:コマンドプロンプトでUTF-8の文字を表示する。 - サンプルコードによる Perl 入門ではフォントの変更についても触れているので参考になるかも。

Visioで「モデリング エンジンの初期化に失敗しました。」

Visio(2003)でデータベースモデル図の既存ファイルを開いたら、「モデリング エンジンの初期化に失敗しました。」というエラーが発生。リレーション(テーブル)内の情報の編集ができなくなった。
原因は以前お試し版のVisio2007をインストール/アンインストールしたこと?

Microsoftのサイトにあるそれらしい解決策 を試したが治らなかった。

「プログラムの追加と削除」から、Visioの「変更」で「再インストール/修復」をやったら治った。(途中でVisioのインストールCDが必要。)

Trac 0.11の ticket-workflow 設定のための参考サイト

ticket-workflowは、trac.iniで定義しているチケットのStatusが辿るフローについての設定。
(TracのWeb画面のAdminからは変更できない。)

シンプルで分かりやすい設定例
 trac 0.11 ワークフローのカスタマイズ — takanory.net

その他の設定例
 Trac-0.11のワークフロー - Do You PHP はてな
 Trac-0.11のワークフローでTICKET_REVIEW権限を使う - Do You PHP はてな
 Trac-0.11のワークフローの実設定例 - Do You PHP はてな (2008/02/02 追加)

上記で言及されている、本家にあるサンプル設定
 enterprise-review-workflow.ini - The Trac Project - Trac

本家のワークフローについての説明
 TracWorkflow - The Trac Project - Trac


(自分がふだんやっている)Roadmapからチケットを見るという操作だとStatusは表示されないので、Statusを追加しても分かりづらいかも。

2008年1月20日日曜日

YUI (Yahoo! User Interface Library)関連のリンク集

YUI関連のサイトのリンク集的メモ。


本家トップページ
The Yahoo! User Interface Library (YUI)

YUIのホスティングの説明
(CSSやJavaScriptのファイルを、YahooのWebサーバから直接インクルードできる)
Serving YUI Files from Yahoo! Servers

YUIのホスティングでのhttpsについてのコメント
(httpsによるアクセスはできないし、今のところサポートする予定もない)
Free Hosting of YUI Files from Yahoo! » Yahoo! User Interface Blog

YUIのJavaScriptライブラリのリファレンス和訳
Yahoo UI Library リファレンス

Grids.css(全体的なレイアウトを整える)用のテンプレートをダウンロードできるサービス
CSS Layouts (<- 2008/02/04追記:リンク切れ?)

Fonts.css(フォント関連の調整)を使った場合のフォントサイズの大きさの変え方の説明
Yahoo! UI Library: Fonts CSS

Grids.cssの構成を簡単に構築できる (2008/02/24追記)
YUI: CSS Grid Builder

特選:画像ジェネレータサービス ベスト5

Webサイトでちょこちょこっと入力するだけで画像を生成してくれるサービスは色々あるけれど、その中でも「痒いところに手の届く」便利なもののリスト。


リボン
Free Website Ribbon Generator - For Your Site Or Blog
(Webページの右上にJavaScriptでリボンを描き出す)

Loading
Ajaxload - Ajax loading gif generator
(Loading中を示す、ぐるぐる回る画像を生成)

タブ
Navigation Tab Menu Generator CSS - Tabs Generator
(メニューとして使えるタブ用の画像を生成)

背景
Background Image Maker
(background用画像を生成。グラデーションもできる)

favicon
favikon
(画像からfaviconを生成)

IE7での :hoverによる表示変更について

IE7ではa要素以外についても:hover擬似要素に対応しているが、これについて発生した問題と解決策のメモ。

やったこと
:hoverでcolorを変える

問題点
hover時に該当要素のbackground-colorが無効になる

解決策
:hoverではcolorだけでなく、他のスタイルも一緒に指定する (今回はborder:noneを指定した)

原因の推測
IE7では、hover時のレンダリングにおいてbackground-colorなど一部のスタイル指定について再レンダリングを行わない。そのため、重なる要素にborder等の再レンダリングを行うスタイルがあるとそちらで上書きされてしまう。

参考:
 我流天性 - がらくた屋 » a:hoverでz-indexを変えて重なりの入れ替えをIEにも対応させてみた
 (z-indexでもbackground-colorと同じ問題が発生するようだ)

PostgreSQLのバックアップとリストア

コマンドラインからやりたい場合。(WindowsのPgAdminIIIから接続できるなら、PgAdminIIIを使った方が楽。)

権限のあるユーザーで実行する。

バックアップ

pg_dump dbname > backup_file_path

リストア
psql dbname < backup_file_path

全てのデータベースをバックアップする場合はpg_dumpallで。
pg_dumpall > backup_file_path

2008年1月14日月曜日

Apache 2.2 でリバースプロキシする設定

httpd.confを編集する。Virtual Hostを使う場合は、URLの記述は該当のVirtualHostのところに記述する。

下記の例では、http://ドメイン/test/へのアクセスをhttp://localhost:3000/test/に振っている。

# 必要なモジュールをロード
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so

# Requestを受けるURLの先頭部分と、振り先のURLを定義する
# ProxyPassとProxyPassReverseの両方を書く(同じ内容でよい)

ProxyPass /test http://localhost:3000/test
ProxyPassReverse /test http://localhost:3000/test

上記の設定により、下記のようにリバースプロキシされる。

  • http://ドメイン/test/ → http://localhost:3000/test/
  • http://ドメイン/test/foo → http://localhost:3000/test/foo
  • https://ドメイン/test/secure → http://localhost:3000/test/secure

httpsでのアクセスの場合、プロキシしているApacheのサーバ証明書が使われる。振った先(ポート3000の方)はhttpsに対応していなくても問題ない。


参考: mod_proxy - Apache HTTP サーバ (本家マニュアル)

Apacheの MaxRequestsPerChildについて

httpd.confのMaxRequestsPerChildについて調べたメモ。

MaxRequestsPerChild を非ゼロに制限することには、二つの利点があります:
  • (偶発的な) メモリーリークが起こった場合に プロセスが消費するメモリの総量を制限できる
  • プロセスに有限のライフタイムを設定することで、 サーバ負荷が下がった時にプロセス数を少なくすることができる

動作しているプログラムのメモリリークバグの量にもよるが、バグが多ければ比較的少ない値を。バグが少なければ大きな値を。
(中略)
また値としてゼロを指定出来るが、その場合はそのプロセスが延々と動き続ける事となり、万が一メモリリークが発生した場合肥大化してサーバをダウンさせる事になる。

Windowsでは、これを0に設定することをお薦めします。0以外の値に設定すると、リクエスト数に達したときに子プロセスが終了し、再作成されます。 その際、子プロセスは構成ファイルを再度読み取ります。そのため、構成ファイルを変更したが、変更を適用するつもりはないという場合に、予期しない処理が 行われる可能性があります。

WindowsではMaxRequestsPerChildをゼロにしていても、なぜか勝手に子プロセスが再起動することがある。(Parent: child process exited with status 3221225477 -- Restarting.)
その時に子プロセスの終了に失敗すると子プロセスを起動できずに親プロセスごと停止してしまうことがある。

対策は...WindowsでないOSを使う?


Apacheの違うバージョンで 同じhttpd.confを使う方法

Apache2.2以降ではmod_version を使うことにより、Apacheのバージョンに応じた設定の適用ができる。

<IfVersion 2.1.0>
  # current httpd version is exactly 2.1.0
</IfVersion>

<IfVersion >= 2.2>
  # use really new features :-)
</IfVersion>

これにより、同じhttpd.conf(または他の設定ファイル)を異なるバージョンのApacheに適用することができる。

2008年1月9日水曜日

Google Reader Broken

昨日(1/8)、Googleリーダーでフィードを見ようとするとページ全体をリロードしてしまってフィードを見られないという問題が発生した。
左上の「全てのアイテム」とか「スター付きアイテム」ではフィードを見られるが、左下のフィード名のリンクをクリックするとこの問題が発生する。

どうやら今日になって解決したらしい。

Google Reader Broken as of 08/01/08 - Something Is Broken | Google グループ

別のバグの修正をした際に埋め込まれたバグらしい。英語版では発生しないので作った人は気づかなかったのか。

2008年1月2日水曜日

MySQLのユーザー追加

GRANT文でユーザーを追加する。

GRANT ALL PRIVILEGES ON *.* TO foo@localhost IDENTIFIED BY 'bar' WITH GRANT OPTION;
GRANT ALL PRIVILEGES ON *.* TO foo@'%' IDENTIFIED BY 'bar' WITH GRANT OPTION;
localhostからも外部からも使いたいユーザーの場合、localhostと'%'と両方grantする必要がある。

ユーザー情報はmysqlデータベースのuserテーブルに格納されている。
SELECT host, user, password FROM user;
このテーブルを直接更新してもユーザー情報を変更できる。


参考: MySQL AB :: MySQL 4.1 リファレンスマニュアル :: 4.4.5 MySQL への新規ユーザの追加

MySQLは 0月や0日を登録できる

0を含んだ日付とMySQLのSQLモード

上記リンク先参照。
誤って0月や0日を登録しないように、設定しておいた方がいいのではという結論。

ブログ アーカイブ

tags