Zend_Db使用時に1カラムに大量の(テキスト)データを入れるとエラーも返さず真っ白になってしまう件について

9月 2nd, 2011

Zend_Dbを使用して、1カラムに大量のデータを入れた際に、画面が真っ白になりエラーも返さず止まりました。
SQL自体は正しく、1カラムのデータ量を減らしたら普通にクエリが通る状態でした。


環境は
VMware Player使用
メモリ1G割当
Centos5
php 5.3.5
mysql 5.0.77
Zend_Db_Adapterはmysqli
です。

以下検証がだらだら続きます。
読むの面倒という方は一気にスクロールして結論をどうぞ。

検証用テーブル作成。

 CREATE TABLE `test_table` (
 `seq` int(11) NOT NULL auto_increment,
 `text` longtext NOT NULL,
 PRIMARY KEY  (`seq`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

 

<?php
require_once 'Zend/Db.php';

ini_set("display_errors",1);
error_reporting(E_ALL);

$db = Zend_Db::factory("Mysqli", array(
'host'     => '127.0.0.1',
'username' => 'hoge',
'password' => 'xxxxxxxx',
'dbname'   => 'test',
));

$str = <<<EOF
短い文章
EOF;

$sql = "INSERT INTO test_table (text) VALUES (".$db->quote($str).")";
try {
$db->query($sql);
} catch (Exception $e) {
echo $e->getMessage();
exit;
}
echo "fin<br />\n";
exit;

これは通りますが、

<?php
require_once 'Zend/Db.php';

ini_set("display_errors",1);
error_reporting(E_ALL);

$db = Zend_Db::factory("Mysqli", array(
'host'     => '127.0.0.1',
'username' => 'hoge',
'password' => 'xxxxxxxx',
'dbname'   => 'test',
));

$str = <<<EOF
適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?適当な長い文章だったら?
EOF;

$sql = "INSERT INTO test_table (text) VALUES (".$db->quote($str).")";
try {
$db->query($sql);
} catch (Exception $e) {
echo $e->getMessage();
exit;
}
echo "fin<br />\n";
exit;

これ位になると私の環境では必ず画面真っ白でエラーも出ず止まりました。
また、中途半端な長さの時に画面リロードを繰り返すと、通るときや通らない時もありました。

原因究明の為、Zend_Dbの中身を追いかけていくと
Zend/Db/Statement.php

177行目
protected function _stripQuoted($sql)
内の
preg_replaceに長い文字列を渡してしまい、そこでエラーも吐かず止まってしまっていたようです。
その部分について下記のように書き換えました。

// get a version of the SQL statement with all quoted
// values and delimited identifiers stripped out
// remove "foo\"bar"
/*
$sql = preg_replace("/$q($qe|\\\\{2}|[^$q])*$q/", '', $sql);
// remove 'foo\'bar'
if (!empty($q)) {
$sql = preg_replace("/$q($qe|[^$q])*$q/", '', $sql);
}

return $sql;
*/
$sql = str_replace(array('\\\''),array('¥’'),$sql);
$return_sql = "";
$tmp = explode("'",$sql);
for($i=0;$i<count($tmp);++$i){
  if($i % 2 == 0){
    $return_sql .= $tmp[$i];
  }
}
return $return_sql;

204行目~210行目(バージョンによっては多少行数が違うかもしれません)までをコメントアウトし、その下に
$sql = str_replace(array(‘\\\”),array(‘¥’’),$sql);
$return_sql = “”;
$tmp = explode(“‘”,$sql);
for($i=0;$i<count($tmp);++$i){
if($i % 2 == 0){
$return_sql .= $tmp[$i];
}
}
return $return_sql;
を追加しました。

簡単にチェックした所、取り敢えず問題なく動いているようです。

注)そのままコピー&ペーストして使用して頂いて構いませんが、プログラムにミスがあっても責任を負いかねます。
私自身のZend_Dbの使い方として、自分でsqlを書いてクエリの発行部分をZend_Dbにお任せというやりかたです。
ですので、Zend_Dbを使ってsqlを組み立てる方法は動作検証もしておりません
また、もっとこうした方が良い、自分の環境だとバグった等ありましたら、是非コメントをお願いいたします。

カテゴリー: mysql, PHP, 開発

Leave a comment

コメントフィード1件のコメント

  1. しぐれ

    同じ問題にぶち当たってこちらにたどりつきました。
    Zend側で修正が入っていないかchangelogを見てみたら、1.12.0で修正されているようです。

    ZF-5063: Segmentaion fault on preg_replace in Zend_Db_Statement
    http://framework.zend.com/issues/browse/ZF-5063

Leave a comment

コメントは承認待ちです。表示されるまでしばらく時間がかかるかもしれません。

Feed

http://blog.yume-dia.jp / Zend_Db使用時に1カラムに大量の(テキスト)データを入れるとエラーも返さず真っ白になってしまう件について