Archive

Posts Tagged ‘PHP’

WordPress の SQLite 対応

現在、データベースソフトには PostgreSQL を使っているのですが、MovableType と違って、WordPress は MySQL しか対応していません。

わざわざ、WordPress のためだけに MySQL をインストールしてデーモンプロセスを増やすのも嫌だったので、他のデータベースに対応するプラグインなどは無いものかと、探していたらありました。

(続きを読む…)

変数の評価

これは気づかないとかなりハマるし、アプリにバグを埋め込むことになります。

フォームから来た変数で 0 を値に持つ変数を空文字列かどうか評価したら空として認識してる気がしたのでテストコードを書いてみました。

以下のコードを実行

$i = 0;
print_r(’$i: ‘ . $i . “\n”);
print_r(’$i == null: ‘ . ($i == null) . “\n”);
print_r(’$i == false: ‘ . ($i == false) . “\n”);
print_r(’$i == “”: ‘ . ($i == “”) . “\n”);

以下が結果

$i: 0
$i == null: 1
$i == false: 1
$i == “”: 1

null の評価については今更何も言うまい。
確かに空文字列か評価したら true を返しています。0 という値が入ってるのに。最初に $i を integer として定義してるので型変換が起きてるのだろうと思って、型キャストして評価してみました。

コード

print_r(’(string) $i == “”: ‘ . ((string) $i == “”) . “\n”);

結果

(string) $i == “”:

一応期待した動作になりましたが Perl に慣れていると気持ち悪いです。
慣れるべきなのかも知れませんが、明らかに文字列として評価を試みてるのだから、そこでも型の自動変換をして欲しいものです。

今回は、フォームから来た時点では string でしたが、-= で減算処理をしていたため、その時点で integer に自動変換され、文字列的には空でないのに、”" オペランドを integer として評価したために、0 == “” が true になったもののと思われます。

自動型変換の演算子とオペランドの関係については、下記参照。
http://jp.php.net/manual/ja/language.types.type-juggling.php

常に厳密比較を使った方が楽かも知れません。
http://jp.php.net/manual/ja/types.comparisons.php

post_max_size

POST されたデータが post_max_size を超えた場合に、フォームから送信されたパラメーターが上手く取れない現象にあいました。

それは至って当然な反応ですが、プロセス自体は死なないので、パラメーターに応じてヴァリデーションをかけてる場合はそれをすり抜けてしまいます。

その場合の $_REQUEST 変数の挙動を調べていないので、バッファオーバーフローのような攻撃を受けた場合に、中途半端に $_REQUEST に格納されてたりするとセキュリティホールになりえます。

PHP のイメージ関数の注意点

今日、ファイルアップロードした画像のサムネイルやらを作って書き出す機能が正常に動作しない場合があるという不具合を見つけました。

デバッグしていくと、原因は imagecreatefromjpeg() だと分かったのですが、Apache もエラーを吐いていなくて、ブラウザもレスポンスコードを受け取っていないようだったので、恐らくプロセスが途中で死んでいるようでした。

ググってみると、他に数人レンタルサーバーで同現象を体験している人がいて、やはりメモリの問題じゃないかとつっこまれていました。

ウチでは、Apache を djb の softlimit 経由で 32MB のメモリ制限を設けて起動しているので、それを 64MB にしたら正常に動作するようになりました。

問題の現象は、アップロードした JPEG 画像が 800*600 ピクセルでは起きなかったのですが、1600*1200 だと起きました。この問題は、ファイルサイズよりも、ピクセルサイズの方が重要になるようです。ちなみに問題のファイルは 214KB (1600*1200) でした。

恐らく、softlimit を使わないで Apace の httpd.conf 側でメモリ制限をしていた場合はちゃんとログにエラーを吐いて、ブラウザにもレスポンスを返してくれていたのでしょう。

参考:
◇ [PHP-users 25728] Re: ImageCreateFromJPEG が正常に動かない
https://www.drive.ne.jp/iMA/showmail.pl?PHP-users=25728

PHP 配列の振る舞い

色々テストしてみました。

#####
print_r($a);
—->
(出力なし)

#####
$a = array();
print_r($a);
—–>
Array ( )

#####
print_r(count($a));
—->
0

#####
$a = array();
print_r(count($a));
—->
0

一応、前もって $a = array(); と配列型を宣言しておけば、

if (count($a)) {

としても PHP Notice も出ない。
is_array() だと宣言してないと Notice 出る。
isset() だと宣言していなくても Notice 出ないが、配列が空でも true が返るので意図したこととは違うでしょう。

メール関数が機能しない

もの凄いハマりました。

mb_send_mail() でメールを送りたかったのですが、テスト環境で問題なかったプログラムを本番環境にアップして走らせたのですが動かない。

とりあえず、メーラーから送受信チェック。OK
phpinfo() をチェック。sendmail_path が none だったので、php.ini を編集。/usr/sbin/sendmail が表示された。OK
実際に /usr/sbin/sendmail を使って送信チェック。OK

しかし、PHP からは一向にメールが送れない。MTA のログにも何も表示されない。頭を抱えてうんうん唸る。念のため、mail() でもテスト。送れない。

PHP マニュアルを確認。なにかそれっぽい記述を発見。

メール関数を使用可能にするには、PHP のコンパイル時点でシステム上の sendmail バイナリにアクセスできなければなりません。 postfix や qmail など他のメールプログラムを使用してる場合には、 それらのソフトに付随する適当な sendmail ラッパを使用するように 気をつけてください。 PHP は sendmail を探す際にまず PATH を見ます。次に /usr/bin:/usr/sbin:/usr/etc:/etc:/usr/ucblib:/usr/lib の順で探します。PATH を通して sendmail を使用可能な 状態にしておくことが強く推奨されます。 また、コンパイルされた PHP が sendmail バイナリにアクセスできる権限を 持っていなければなりません。

そういえば、web 周りは一番最初に入れたからなぁ。
PHP をコンパイルし直してインストールしたが、相変わらず送れない。気を取り直して、

# make distclean

してから、もう一回再インストール。

やっと送れるようになりました。

比較演算子の困った仕様

以前から分かってたことなのですが、比較演算子の仕様がかなり不便です。何が不便かっていうと、0 と null の扱い。

$v = 0 で
$v == null が true

$v = null で
$v == 0 も true

なので、

同じ $v = 0 でも、
if ($v == 0) {
} elseif ($v == null) {
}

と、

if ($v == null) {
} elseif ($v == 0) {
}

で結果が違ったりする。勿論 Smarty の {if,elseif,else} 関数でも一緒。

結局、思った通りに動作させるには、PHP4 以上という縛りで、
$v === 0 と、型までチェックするようにするしかない。

しかし、Smarty の {if,elseif,else} は、=== 演算子をサポートしていないので、結局 $v == 0 より $v == null を先に評価させるしかない。