ます’s Blog - どうでもいい記事100選

どうでもいい記事100選

strrpos関数とmb_strrpos関数の挙動の違い

詳しくはコレから始まるスレッドを参照して頂きたいのですが。
(PHP5では)mbstring.func_overloadでstrrpos関数をオーバーロードすると、(状況によっては)マヅイ事になりそうです。
ただでさえ海外の人からは不評な機能なのに(更に)拍車がかかりそう。
という訳で、逃げの一手。。。。のタコさんパッチ。
mb_strrpos関数の引数仕様をstrrpos関数の引数仕様に合わせてみました。
encoding引数は普段から使っていないので(個人的には)特に問題ナッシング。

--- php-5.1.2,orig/ext/mbstring/mbstring.c	2006-01-01 21:50:08.000000000 +0900
+++ php-5.1.2/ext/mbstring/mbstring.c	2006-02-27 11:17:53.000000000 +0900
@@ -1612,11 +1612,12 @@
 }
 /* }}} */
 
-/* {{{ proto int mb_strrpos(string haystack, string needle [, string encoding])
+/* {{{ proto int mb_strrpos(string haystack, string needle [, int offset [, string encoding]])
    Find the last occurrence of a character in a string within another */
 PHP_FUNCTION(mb_strrpos)
 {
 	int n;
+	long offset;
 	mbfl_string haystack, needle;
 	char *enc_name = NULL;
 	int enc_name_len;
@@ -1627,8 +1628,9 @@
 	haystack.no_encoding = MBSTRG(current_internal_encoding);
 	needle.no_language = MBSTRG(current_language);
 	needle.no_encoding = MBSTRG(current_internal_encoding);
+	offset = 0;
 
-	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|s", (char **)&haystack.val, &haystack.len, (char **)&needle.val, &needle.len, &enc_name, &enc_name_len) == FAILURE) {
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|ls", (char **)&haystack.val, &haystack.len, (char **)&needle.val, &needle.len, &offset, &enc_name, &enc_name_len) == FAILURE) {
 		RETURN_FALSE;
 	}
 
@@ -1648,7 +1650,17 @@
 		php_error_docref(NULL TSRMLS_CC, E_WARNING,"Empty needle");
 		RETURN_FALSE;
 	}
-	n = mbfl_strpos(&haystack, &needle, 0, 1);
+	if (offset < 0) {
+		offset = haystack.len + offset;
+		if (offset < 0) {
+			RETURN_FALSE;
+		}
+		haystack.len = offset + needle.len;
+		offset = 0;
+	} else if (offset > haystack.len) {
+		RETURN_FALSE;
+	}
+	n = mbfl_strpos(&haystack, &needle, offset, 1);
 	if (n >= 0) {
 		RETVAL_LONG(n);
 	} else {

うーん。offsetの負の指定は仕様が訳ワカメ。。。これ、本当に必要なのか?
気になるのが「if (offset > haystack.len)」の部分。
文字数として比較してなくて、バイト数として比較しています。
この比較は、mb_strpos関数(内部の処理)でも行なっていますが、これって本当は、

	n = mbfl_strlen(&haystack);
	if (offset > n) {
		RETURN_FALSE;
	}

こんな感じで比較しないのと駄目なのかなぁ。。。という気がしています。
マルチバイト対応関数なんだから、offsetの意味合いもバイト数ではなくて文字数なのでは。。。って事です。
この辺が(いまいち)よく分かってないので、負の計算は適当です。
っていうか「mbstring.func_overload」はPHP3(i18n)互換モードとして「1」にしか設定してないから全然関係ないんだけどね。
bytelen関数が無さげなので(やはり)strlen関数は必要なんです。
メール送信にしても専用の関数を作ってるしなぁ。オリジナルのmail関数(mb_send_mail)関数は使いづらい。