カテゴリの投稿: » PHP

XREAやCORESERVERのsession_start()でエラー

Written in 2010年04月12日 by | コメントする( 0件 )

XREAやCORESRVERのPHPで、モジュール版とCGI版のPHPを合わせて使って、セッションが引き継がれると以下のようなエラーが出る。

Warning: session_start() [function.session-start]: open(/tmp/sess_xxxxxxxxxxxxxxxxxxxxxx, O_RDWR) failed: Permission denied (13) in /virtual/xxxx/public_html/index.php on line xx

これはCGI版では、セッションファイルが、/tmp/にて、FTPユーザー権限で書きこまれ、一方モジュール版ではApacheユーザー権限で書きこまれるからだ。それで、CGI版PHPで作成されたセッションファイルをモジュール版PHPから読み込む際にパーミッションエラーとなるのだ。逆もまたしかり。

  • カテゴリー:
  • PHP

PHPでFTP通信する際の注意

Written in 2010年03月30日 by | コメントする( 0件 )

PHPでftp_put()関数などでFTP通信をする際に、

Warning: ftp_put() [function.ftp-put]: Ok to send data. in /path/to/script.php on line 99

のようなエラーに出くわすことはないだろうか。この場合、PHPが動作しているマシンのiptablesに注意が必要である。FTPログインはできたものの、相手からデータ通信のコネクションが張れないままタイムアウトしているのであろう。

通信相手のFTPサーバがアクティブモードで動作している場合、こちらから相手FTPサーバの21番ポートにコネクトしたのち、相手FTPサーバの20番ポートから、 こちらが通知した1024-65535の間のポートにコネクトしようとしてくる。

なので、こちら(PHPが動作しているマシン)のiptablesのINPUTチェーンで制限を加えている場合、INPUTチェーンでは、 1024-65535の間のポートが空いている必要が出てしまう。
これはあまりにも危険だし、その必要もない。以下のようにする。

iptables -L

を行い、INPUTチェーンに

ACCEPT  all  —  anywhere  anywhere  state RELATED,ESTABLISHED

の行があることを確認する。これは、確立済みのコネクションと、関連するコネクションを許可するものだ。なければ以下のように作る。

iptables -I INPUT 5 -p udp -m state –state ESTABLISHED,RELATED -j ACCEPT

上記、5の部分は挿入するINPUTチェーンの行番号です。

次にiptables関連のカーネルモジュールを確認する。

lsmod

を実行し、ip_conntrack_ftpと、ip_nat_ftpの行があることを確認し、ないものを入れる。それぞれ以下の通り。(多くの場合、ip_conntrack_ftpは入っている。)

modprobe ip_conntrack_ftp
modprobe ip_nat_ftp

これで、アクティブモードのFTPサーバに対して、PHPでFTP通信ができるようになった。

このままではサーバが再起動したら元に戻ってしまう。
/etc/sysconfig/iptables-config
で、使用するモジュールを以下のように設定する。

IPTABLES_MODULES=”ip_nat_ftp”

また、先のiptables設定を保存する。

service iptables save

IPTABLES_MODULES=”ip_nat_ftp

libxml2.7.0 – 2.7.2で、実体参照が消える

Written in 2009年08月21日 by | コメントする( 0件 )

libxml2.7.0以降で、実態参照が消失する不具合があり、これを使ってコンパイルされたPHPでは、XMLをパースする際に問題になる。

■実態参照とは

XML文書内で直接記述できない文字や記号(たとえば、 “<” や “>” など)を表記する際に用いられる記述方法です。以下のようなものがある。

  • 「&」 ・・・ 「&amp;」
  • 「< 」・・・ 「&lt;」
  • 「> 」・・・ 「&gt;」
  • 「” 」・・・ 「&quot;」
  • 「’ 」・・・ 「&apos;」

XML内の、<description>タグ、<content>タグなどの中にHTMLを記述する場合、多くの場合以下のような記述を用いる。

<description>
<![CDATA[
<h1>タイトル</h1>
<p>文章がここにはいる</p>
]]>
</description>

このようにしてCDATAセクションを使うことで、実態参照を用いずに記述することが可能である。しかし、CDATAを使わずに実態参照を用いて記述されているXMLも数多く存在する。

<description>
&lt;h1&gt;タイトル&lt;/h1&gt;
&lt;p&gt;文章がここにはいる&lt;/p&gt;
</description>

このようになる。

■実態参照が使われたXMLをパースする際の問題

こういったXML文書をlibxml2.7.0以降を使ったPHP関数でパースすると、実態参照だけが消失し、以下のような見るに堪えない結果となる。

h1タイトル/h1
p文章がここにはいる/p

さくらインターネットのレンタルサーバでは、各種ミドルウェアのバージョンアップが早く、libxml2.7.2などがすでに導入されており、そのサーバを利用している場合、RSSやXMLから情報収集しているプログラムで不具合が生じることになるだろう。

■対処方法

専用サーバであれば、libxmlのバージョンを2.6.30に落とすなどして対処できるが、そうでない場合には別の対処が必要となるだろう。考えられるひとつの方法は、XML内の実態参照をデコードし、CDATAを使った記述に書き換えた上でパースすることだ。以下にPHPでそれを行うための関数を示す。

function insertCDATA( $xml_str )
{
$target_tags = array( ‘description’, ‘content’, ‘content:encoded’ );
foreach ( $target_tags as $tag ) {
$ent = false;
if ( preg_match_all( ‘/<‘.$tag.'[^>]*>(.*?)<\/’.$tag.’>/ims’, $xml_str, $matches ) ) {
if ( is_array( $matches[1] ) && count( $matches[1] ) ) {
foreach ( $matches[1] as $m ) {
if ( !preg_match( ‘/^<!\[CDATA\[/im’, $m ) && preg_match( ‘/&gt;|&lt;|&amp;|&quot;|&apos;/ims’, $m ) ) {
$ent = true;
break;
}
}
}
if ( !$ent ) {
continue;
}
$encode = mb_detect_encoding( $xml_str );
$xml_str = preg_replace( ‘/(<‘.$tag.'[^>]*>)(?!\s*<!\[CDATA\[)(.*)(<\/’.$tag.’>)/Ueims’,
‘”\\1<![CDATA[“.html_entity_decode(“\\2″,ENT_COMPAT,”$encode”).”]]>\\3″‘, $xml_str );
}
}
return $xml_str;
}

function insertCDATA( $xml_str )
{
$target_tags = array( ‘description’, ‘content’, ‘content:encoded’ );
foreach ( $target_tags as $tag ) {
$ent = false;
if ( preg_match_all( ‘/<‘.$tag.'[^>]*>(.*?)<\/’.$tag.’>/ims’, $xml_str, $matches ) ) {
if ( is_array( $matches[1] ) && count( $matches[1] ) ) {
foreach ( $matches[1] as $m ) {
if ( !preg_match( ‘/^<!\[CDATA\[/im’, $m ) &&
preg_match( ‘/&gt;|&lt;|&amp;|&quot;|&apos;/ims’, $m ) ) {
$ent = true;
break;
}
}
}
if ( !$ent ) { continue; }
$encode = mb_detect_encoding( $xml_str );
$xml_str = preg_replace(
‘/(<‘.$tag.'[^>]*>)(?!\s*<!\[CDATA\[)(.*)(<\/’.$tag.’>)/Ueims’,
‘”\\1<![CDATA[“.html_entity_decode(“\\2″,ENT_COMPAT,”$encode”).”]]>\\3″‘, $xml_str );
}
}
return $xml_str;
}

この関数にXML文字列を渡すと、<description>タグ、<content>タグ、<content:enceded>タグを調べて、そこに実態参照があれば、CDATAによる記述に書き換えて返してくれます。

RSSをパースする際に、MagpieRSS(http://magpierss.sourceforge.net/)をご利用の方も多いだろう。このライブラリもlibxml2.7.xの影響を受ける。その場合、rss_fetch.incを開き、上記の関数を書き加えたうえで、_response_to_rss関数のはじめの部分を以下のように書き換えてやるといい。

/*===============================================*\
Function:   _response_to_rss
Purpose:    parse an HTTP response object into an RSS object
Input:      an HTTP response object (see Snoopy)
Output:     parsed RSS object (see rss_parse)
\*===============================================*/

function _response_to_rss ($resp) {
/* ++++++++++++++++++++ Simple Eye changed +++++++++++++++++++ */
//    $rss = new MagpieRSS( insertCDATA($resp->results), MAGPIE_OUTPUT_ENCODING, MAGPIE_INPUT_ENCODING, MAGPIE_DETECT_ENCODING );
/* ++++++++++++++++++++ Simple Eye changed +++++++++++++++++++ */
$rss = new MagpieRSS( $resp->results, MAGPIE_OUTPUT_ENCODING, MAGPIE_INPUT_ENCODING, MAGPIE_DETECT_ENCODING );

・・・・・・・・つづく・・・・・・・・・

session.bug_compat_42 と session.bug_compat_warn

Written in 2009年08月20日 by | コメントする( 0件 )

Warning: Unknown(): Your script possibly relies on a session side-effect which existed until PHP 4.2.3. Please be advised that the session extension does not consider global variables as a source of data, unless register_globals is enabled. You can disable this functionality and this warning by setting session.bug_compat_42 or session.bug_compat_warn to off, respectively. in Unknown on line 0
PHP バージョンが 4.2.3 とそれ以前には、たとえ register_globals が無効の場合でもグローバルスコープでセッション変数の初期化を 許してしまうドキュメント化されていない特徴/バグがあります。 この機能を使用している場合で session.bug_compat_warn も有効にしている場合、 PHP 4.3.0 とそれ以降のバージョンでは警告が発されます。 この特徴/バグは、 以下のディレクティブを無効にすることで無効にすることが可能です。
session.bug_compat_42
session.bug_compat_warn
上記の「この機能を使用している場合」に相当しているかどうかを
PHPがどんな条件で判断しているかを6つのケースから考える。
●エラーが出ない[case1.php]
($_SESSIONのキーとグローバル変数が違う場合)
<?php
session_start();
$bbb = $_GET[‘abc’];
$_SESSION[‘aaa’] = $bbb;
?>
●エラーが出ない[case2.php]
($_SESSIONのキーとグローバル変数が同じ場合でも、
外部からの変数を受け取っていない場合)
<?php
session_start();
$aaa = ‘abc’;
$_SESSION[‘aaa’] = $aaa;
?>
●エラーが出る[case3.php]
($_SESSIONのキーとグローバル変数が同じ場合で、かつ、
外部からの変数を受け取っている場合)
<?php
session_start();
$aaa = $_GET[‘abc’];
$_SESSION[‘aaa’] = $aaa;
?>
●エラーが出る[case4.php]
($_SESSIONのキーとグローバル変数が同じ場合で、
その$_SESSIONが外部からグローバル変数とは関係ない外部変数を受け取っている場合)
<?php
session_start();
$aaa = ‘abc’;
$_SESSION[‘aaa’] = $_GET[‘abc’];
?>
●エラーが出る[case5.php]
($_SESSIONのキーとグローバル変数が同じ場合で、
その$_SESSIONが外部からグローバル変数とは関係ない外部変数を
別のグローバル変数を介して受け取っている場合)
<?php
session_start();
$aaa = ‘abc’;
$bbb = $_GET[‘abc’];
$_SESSION[‘aaa’] = $bbb;
?>
●エラーが出ない[case6.php]
($_SESSIONのキーとグローバル変数が同じものがある場合で、
その$_SESSIONとは別の$_SESSIONが外部変数を受け取っている場合)
<?php
session_start();
$aaa = ‘abc’;
$bbb = $_GET[‘abc’];
$_SESSION[‘aaa’] = $aaa;
$_SESSION[‘ccc’] = $bbb;
?>
●結論(エラーが出る条件)
①$_SESSIONのキーと同じ名前のグローバル変数がある
例) $_SESSION[‘aaa’] と $aaa
②その$_SESSIONが間接的、直接的を問わず、何らかの外部変数を読み込んでいる
例1) $_SESSION[‘aaa’] = $_GET[‘abc’];
例2) $bbb = $_GET[‘abc’];
$_SESSION[‘aaa’] = $bbb;
●回避策
php.iniの以下のディレクティブをOffにする
session.bug_compat_42
session.bug_compat_warn

■■ 以下のエラーを検証する ■■

Warning: Unknown(): Your script possibly relies on a session side-effect which existed until PHP 4.2.3. Please be advised that the session extension does not consider global variables as a source of data, unless register_globals is enabled. You can disable this functionality and this warning by setting session.bug_compat_42 or session.bug_compat_warn to off, respectively. in Unknown on line 0

PHP バージョンが 4.2.3 とそれ以前には、たとえ register_globals が無効の場合でもグローバルスコープでセッション変数の初期化を 許してしまうドキュメント化されていない特徴/バグがあります。 この機能を使用している場合で session.bug_compat_warn も有効にしている場合、 PHP 4.3.0 とそれ以降のバージョンでは警告が発されます。 この特徴/バグは、 以下のディレクティブを無効にすることで無効にすることが可能です。

session.bug_compat_42
session.bug_compat_warn

上記の「この機能を使用している場合」に相当しているかどうかを PHPがどんな条件で判断しているかを6つのケースから考える。

●エラーが出ない[case1.php]

($_SESSIONのキーとグローバル変数が違う場合)

<?php
session_start();
$bbb = $_GET[‘abc’];
$_SESSION[‘aaa’] = $bbb;
?>

●エラーが出ない[case2.php]

($_SESSIONのキーとグローバル変数が同じ場合でも、外部からの変数を受け取っていない場合)

<?php
session_start();
$aaa = ‘abc’;
$_SESSION[‘aaa’] = $aaa;
?>

●エラーが出る[case3.php]

($_SESSIONのキーとグローバル変数が同じ場合で、かつ、外部からの変数を受け取っている場合)

<?php
session_start();
$aaa = $_GET[‘abc’];
$_SESSION[‘aaa’] = $aaa;
?>

●エラーが出る[case4.php]

($_SESSIONのキーとグローバル変数が同じ場合で、その$_SESSIONが外部からグローバル変数とは関係ない外部変数を受け取っている場合)

<?php
session_start();
$aaa = ‘abc’;
$_SESSION[‘aaa’] = $_GET[‘abc’];
?>

●エラーが出る[case5.php]

($_SESSIONのキーとグローバル変数が同じ場合で、その$_SESSIONが外部からグローバル変数とは関係ない外部変数を別のグローバル変数を介して受け取っている場合)

<?php
session_start();
$aaa = ‘abc’;
$bbb = $_GET[‘abc’];
$_SESSION[‘aaa’] = $bbb;
?>

●エラーが出ない[case6.php]

($_SESSIONのキーとグローバル変数が同じものがある場合で、その$_SESSIONとは別の$_SESSIONが外部変数を受け取っている場合)

<?php
session_start();
$aaa = ‘abc’;
$bbb = $_GET[‘abc’];
$_SESSION[‘aaa’] = $aaa;
$_SESSION[‘ccc’] = $bbb;
?>

●結論(エラーが出る条件)

①$_SESSIONのキーと同じ名前のグローバル変数がある

例) $_SESSION[‘aaa’] と $aaa

②その$_SESSIONが間接的、直接的を問わず、何らかの外部変数を読み込んでいる

例1) $_SESSION[‘aaa’] = $_GET[‘abc’];

例2)

$bbb = $_GET[‘abc’];
$_SESSION[‘aaa’] = $bbb;

●回避策

php.iniの以下のディレクティブをOffにする

session.bug_compat_42
session.bug_compat_warn

PHPデバッガdbgのインストール

Written in 2009年08月19日 by | コメントする( 0件 )

●dbgのホームページ

http://dd.cron.ru/dbg/

●ソースコード取得

http://dd.cron.ru/dbg/downloads.php

●インストールマニュアル

http://dd.cron.ru/dbg/installation.php

●準備

①PHPをインストールしよう。

②PREFIX/bin/にphpizeが作成されていることを確認する。

③ソースdbg-2.11.32-src.tar.gzをダウンロード

④次のプログラムがインストールされていることを確認。

autoconf 2.13 以降

automake 1.4 以降

libtool 1.3.3 以降

●ソース展開

/usr/local/src/dbg/でソースを展開する

tar xzvf dbg-2.11.32-src.tar.gz

●スクリプトdeferphpizeを調整

deferphpizeの初めの方にあるphpizeへのパスを適切なものにする

cd dbg-2.11.32

vi deferphpize

~・~・~・~・~・~・~・~・~・~・~・~・~・~・~・~・~・~・~・~・~・~・~・~・~・~・

#!/bin/sh

phpize=${phpize:-“/usr/local/php/bin/phpize”}

if test -f $phpize; then

$phpize

else

echo “You have to make and install php first. Make sure phpize script is located at $phpize”

exit 1

fi

・・・

~・~・~・~・~・~・~・~・~・~・~・~・~・~・~・~・~・~・~・~・~・~・~・~・~・~・

●deferphpizeを走らせる

./deferphpize

これにより、dbg.soライブラリがPHPのモジュールサブディレクトリに作成される。

私の場合は、/usr/local/php/lib/php/extensions/no-debug-non/zts-20050922/dbg.so

に作成された。これを/usr/local/php/lib/php/extensions/dbg.soに移動した。

PHP4の場合、ソースディレクトリの/usr/local/src/dbg/dbg-2.11.32/modules/dbg.so

に作成された。

●エラー対処

In file included from /usr/local/src/dbg/dbg-2.11.32/dbg.c:21:

/usr/local/php4-4apache1.3/include/php/main/php_network.h:78:25: openssl/ssl.h: No such file or directory

In file included from /usr/local/src/dbg/dbg-2.11.32/dbg.c:21:

/usr/local/php4-4apache1.3/include/php/main/php_network.h:129: error: syntax error before “SSL”

/usr/local/php4-4apache1.3/include/php/main/php_network.h:129: warning: no semicolon at end of struct or union

/usr/local/php4-4apache1.3/include/php/main/php_network.h:132: error: syntax error before ‘}’ token

/usr/local/php4-4apache1.3/include/php/main/php_network.h:162: error: syntax error before “SSL_METHOD”

make: *** [dbg.lo] エラー 1

このエラーが出たら、openssl-devel パッケージをインストールする必要がある。

yum install openssl-devel

●php.iniの設定

エクステンションへのパスの指定

extension_dir = “/usr/local/php/lib/php/extensions”

利用するエクステンションの指定

extension=dbg.so

dbgのセクション

[debugger]

debugger.enabled=on

debugger.profiler_enabled=on

●apacheの再起動

apacheを再起動させてphpinfo()を表示させて、ZENDのロゴ付近に以下の記述があり、dbgのセクションがあればインストール成功。

This program makes use of the Zend Scripting Language Engine:

Zend Engine v2.1.0, Copyright (c) 1998-2006 Zend Technologies

with DBG v2.11.32, (C) 2000,2005, by Dmitri Dmitrienko