PHP実行時間の原因と対策

このQ&Aのポイント
  • PHPの実行時間が異常に長くなる原因を特定するために、いくつかの処理を行っています。
  • 具体的には、SimpleXML関数を使用してブログのRSSを取得し、各記事をループして本文を抽出し、200文字までの抜粋を作成しています。
  • 抜粋した文章をNグラム法で分解し、MySQLにフルテキストインデックスとして挿入しています。
回答を見る
  • ベストアンサー

このPHPの実行時間が異常に長くなってしまう原因はどこでしょうか?

このPHPの実行時間が異常に長くなってしまう原因はどこでしょうか? [1] SimpleXML関数でブログのRSSを取得 [2] ブログの各記事(RSS中の<item>~</item>内)をforeachでループ foreach($xml->…->item as $item) [3] 記事の本文の改行を消去した上で先頭から200文字を取得 $description = mb_substr(mb_str_replace(array("\r\n","\r","\n"),'',$item->description),0,200,'UTF-8') [4] 抜粋した200文字をNグラム法で分解 $ngram = $ngram->to_fulltext($description,'4') [5] 分解した文章をフルテキストインデックスに設定したMySQLにINSERT ※[3]~[5]を数十回ループします ※mb_str_replaceはこちらを使わせていただいております http://fetus.k-hsu.net/document/programming/php/mb_str_replace.html ※Nグラム法に関してはこちらを使わせていただいております http://www.tatamilab.jp/rnd/archives/000390.html ※Nグラムクラスの定義は[1]と[2]の間でしています 処理開始時と、各処理終了時にmicrotime()で時間を取得し、 その差を表示させてみたところ、以下のようになりました SimpleXMLでRSSを取得 0.462195 Nグラム法のクラス定義 0.462571 1ループ目開始 0.462877 Nグラム法で分解 0.462877 INSERT終了 0.464095 2回目のループを開始 0.464107 Nグラム法で分解 0.464593 INSERT終了 0.464684 3回目のループを開始 0.464714 Nグラム法で分解 0.465141 INSERT終了 0.46522 4回目のループを開始 0.465229 Nグラム法で分解 0.465851 INSERT終了 0.465942 5回目のループ開始 0.466016 Fatal error: Maximum execution time of 100 seconds exceeded in /home/***/include/include.php on line 53 上記のように表示されました なお、ローカル(XAMPPで構築した環境)では数十回のループが正常に処理されます(時間切れになったことはありません) include.phpは上記のmb_str_replace関数の定義部分で、「$index = -1;」の部分です。 何度か時間を置いて繰り返し実行してみましたが、mb_str_replaceの定義部分でつっかえているようです。 長くなってしまいましたが、何が原因なのかアドバイスをいただければと思います。 よろしくお願いします。

  • PHP
  • 回答数2
  • ありがとう数7

質問者が選んだベストアンサー

  • ベストアンサー
noname#243182
noname#243182
回答No.1

大変興味があります。 問題の箇所が独自に定義された関数であり、またそれの利用方法についても改行を取り除くだけということですので、一度これを標準関数に置き換えてはいかがでしょうか。 改行を取り除くだけであれば、例2 の方法でよいと思います。 http://jp.php.net/manual/ja/function.str-replace.php また、処理が中断されてしまう箇所にエラー情報を収集するコードをもう少し書き足してみたり、ポイントごとにログを書き出すようにしたりすると、様子がはっきりするかもしれません。 http://jp.php.net/manual/ja/book.errorfunc.php いつも 5回目のループでこけるのか、それとも特定のフィードでたまたま 5番目の記事でこけたのか、そのあたりも気になります。はじめのフィード取得でデータが壊れていないかも確認したいところです。 フィードの文字コードセットを取得して、設定できる関数には極力これを設定するというのが大事かもしれないですね。 しかし、まずは改行を取り除く部分だけとりあえず標準関数にしてみてはいかがでしょうか。

php_noob
質問者

お礼

回答ありがとうございました!

php_noob
質問者

補足

回答ありがとうございました。 まず回答について補足させていただきます。 ・いつも特定の記事でこけているようです。 ・はじめのフィード取得で実際にはfile_get_contentsした後に、文字コードの確認、制御文字や不完全なマルチバイト文字等の基本的なチェックをした後、 simplexml_load_stringでオブジェクト化しています。 ・(しかしバイナリセーフでない関数で定義されているmb_str_replaceでNULLバイト文字のチェックをしていたので意味がありませんでした) ・質問投稿後、mb_str_replaceをstr_replaceに置き換えたところ、問題なく動作することが確認できました。 ・しかし不安なのでu修飾子をつけたpreg_replaceに置き換えました(問題なく動作しました) 次に、質問の追加をさせていただきたいと思います。 正規表現置換ではマルチバイト対応の関数でないと文字化けするとよく注意書きがありますが、 今回のようにマルチバイト文字が含まれる文字列から、マルチバイトではない文字を置き換える場合、 マルチバイトに対応していないstr_replaceが文字化けの原因になることはありますか?

その他の回答 (1)

noname#243182
noname#243182
回答No.2

特定の制御文字を除去したいだけであれば「str_replace()」で問題は発生しないと思います。 ただ、有名なオープンソース SNS でのフィルタリング処理を見ますと「preg_replace()」の u 修飾子つきでしたので、読み込んだフィードが UTF-8 で記述されている限りは、これに倣うのがよいかもしれませんね。 「str_replace()」や「preg_replace()」が制御文字をどのような方法で発見するのかは、ソースを読めばわかると思うのですが、これはやっていません。安心がほしい場合はこのあたりを確認してみてください。 あと、出来れば一問一答形式でお願いします。

関連するQ&A

  • PHPです2つのスクリプトの相違がわかりません

    PHPですが、以下の2つのスクリプトで同じ結果がでると思ったのですが現実は違いました。 henkan.php <html> <body> <?php $uketori=$_POST['UKETORI']; $uketori=str_replace("pen","pencil", $uketori); $uketori=strtoupper($uketori); print "$uketori"; ?> </body> </html> henkan2.php <?php $str=$_POST['UKETORI']; echo str_replace("です。","だよん。", $str) . "<br>\n"; echo "<br>\n"; echo mb_ereg_replace("です。","だよん。", $str) . "<br>\n"; echo "<br>\n"; ?> フォームに です。 という文字を入れたら変換されて だよん。 と表示さしたいのですが、上の2つで相違がでました。なぜなんでしょうか。 henkan.php では変換されませんでした。 henkan2.php では変換されました。

    • ベストアンサー
    • PHP
  • executeの実行が一回しかされない

    foreach ($rss->channel->item as $val) { $title = $val->title; $link = $val->link; $description = $val->description; $pubDate = $val->pubDate; $dccreator = $val->dccreator $stmt = $dbh->prepare("insert into rss (title,link,description,pubDate,dccreator) values(?,?,?,?,?)"); $stmt->execute(array($title,$link,$description,$pubDate,$dccreator)); } 上のような感じでexecuteの実行をループさせようとしています。 しかし最初の一回しか実行されません。(DBへの書き込みが最初の一度しかされません) すいませんが、何かアドバイスいただけませんでしょうか? よろしくお願いいたします。

    • ベストアンサー
    • PHP
  • 動的なPHPを静的なhtmlページに変換したい

    動的なPHPページ(RSS)を静的なhtmlのページとして、変換したいのですが、どのようにしたら良いでしょうか? 書いたPHPは下記のようなモノです。 <?php error_reporting(E_ERROR); require_once 'rss_fetch.inc'; define('MAGPIE_OUTPUT_ENCODING', 'UTF-8'); $url = 'http://b.hatena.ne.jp/entrylist?mode=rss&url=http%3A%2F%2Fwww.lucky-bag.com'; $rss = fetch_rss($url); $title = $rss->channel['title']; $title = mb_convert_encoding($title, "EUC-JP", "auto"); echo "<h3>$title</h3>\n"; echo "<dl>\n"; foreach ($rss->items as $item ) { $title = htmlspecialchars($item['title']); $title = mb_convert_encoding($title, "EUC-JP", "auto"); $description = htmlspecialchars($item['description']); $url = htmlspecialchars($item['link']); echo "<dt><a href=\"$url\">$title</a></dt>\n"; $description = mb_convert_encoding($description, "EUC-JP", "auto"); echo "<dd>$description</dd>\n"; } echo "</dl>\n"; ?> どうぞよろしくお願いいたします。

    • 締切済み
    • PHP
  • php5.3.3でeregをループ内で使用すると

    php5.3.3でeregをループ内で使用すると動作がとまり、エラーログにも何も出力されません。 10回目のループでなぜか動作がとまるようです。 $mail=""; $fp=fopen("php://stdin", "r"); while(!feof($fp)) $mail.=fread($fp, 10240); fclose($fp); $MailArray = explode("\n", $mail); $Counter = 0; $InputCheck = new InputCheck(); for ($i = 0; $i < count($MailArray); $i++){ if (strpos($MailArray[$i], "From: ") === 0){ $From = str_replace("From: ", "", $MailArray[$i]); $From = ereg_replace(">.*$", "", $From); $From = ereg_replace("^.*<", "", $From); $From = ereg_replace("\r", NULL, $From); if(!$InputCheck->isRightEMail($From)){ $i++; $From = str_replace("From: ", "", $MailArray[$i]); $From = ereg_replace(">.*$", "", $From); $From = ereg_replace("^.*<", "", $From); $From = ereg_replace("\r", NULL, $From); } } else if (strpos($MailArray[$i], "To: ") === 0){ $To = str_replace("To: ", "", $MailArray[$i]); $To = ereg_replace(">.*$", "", $To); $To = ereg_replace("^.*<", "", $To); $To = ereg_replace("\r", NULL, $To); if(!$InputCheck->isRightEMail($To)){ $i++; $To = str_replace("To: ", "", $MailArray[$i]); $To = ereg_replace(">.*$", "", $To); $To = ereg_replace("^.*<", "", $To); $To = ereg_replace("\r", NULL, $To); } } } 上記は空メールされたfromとtoを取得するものです。 eregをpregに変えれば問題なく動作します。 5.3以降からeregは非推奨になりましたが、使用することはできるようですが、ループ内で使用するとなぜか動作がそこでストップします。 非推奨の関数を使用すると動作が止まりエラーログにも出力されないことはよくあるのでしょうか? エラーログに出力されなかったため原因を特定するのに苦労しました。 eregなどの非推奨関数を使用した場合の不具合に関してご教示頂けると幸いです。 宜しくお願いいたします。

    • ベストアンサー
    • PHP
  • PHPパーサー MagpieRSSについて

    PHPパーサーのMagpieRSSを使用しています。 読み込むxmlが更新されてもそれが反映されません。 また、htmlとして書き出す際に<p>タグにid名を付けたいのですが、idをつけるとエラーがでます。これはPHPでは文法的にまずいんでしょうか?下記が使用しているソースです。 重ねて質問なんですが、下記のソースでは1つのxmlしか読み込んでいませんが、複数のxmlを読み込むにはどうしたらいいのでしょうか。 よろしくお願いします。 <?php require_once 'rss_fetch.inc'; require_once 'rss_utils.inc'; $url = 'http://www.xxxxx/xxxxxx/index.xml'; $rss = fetch_rss($url); $title = $rss->channel['title']; $title = mb_convert_encoding($title, "UTF-8", "auto"); $rss->items = array_slice($rss->items, 0, 1); foreach ($rss->items as $item ) { $description = $item[description]; $description = mb_convert_encoding($description, "UTF-8", "auto"); $url = $item[link]; $date = date("Y.m.d", $item['date_timestamp']); echo "$description?n"; } ?>

    • ベストアンサー
    • PHP
  • preg_replaceで連続した改行

    preg_replaceで5回以上の連続した改行を1回の改行に直したいのですが、 正規表現はどのように書いたらいいのでしょうか? 書いてみたのですが、動いてくれません。。。 <? $str=preg_replace("/\n/{5,}","\n",$str); ?> 申し訳ありませんが、ご教授ください。

    • ベストアンサー
    • PHP
  • sjisで書いているPHPとeucのMysqlでの不都合

    カゴヤインターネットルーティングというレンタルサーバーを借りております。 PHPは携帯のサイトのためどうしてもsjisで書かないといけません。 mysqlはeucです。 ソとか能などよくある文字化けをおこすので addslashes()関数をつかって $str='ソフト'; $com = addslashes($str); としてinsertします。 登録・表示は問題ないのですが、どうしても検索ができません。 $com= 'ソフト'; SELECT * FROM item where item_name like '%$com%' とするとどうしても検索できません。 http://sb.xrea.com/archive/index.php/t-4070.html にも同様のことが書かれていましたが、 $str = mb_convert_encoding($str, "EUC-JP", "SJIS"); のように変換してもうまくいきませんでした。 まことにお手数おかけしますが、ご教授お願いします。

    • ベストアンサー
    • PHP
  • 初めてばかりのPHPでメールフォーム作ったのですが

    メールフォームを制作したのですが、動いたのはいいのですが、 別々にformの値を送っているのですが、うまく動きません。 どうしたらいいでしょうか? mb_language("Japanese"); mb_internal_encoding("UTF-8"); if($_SERVER['REQUEST_METHOD']=="POST"){ $array = array(); $vacation_radio = htmlspecialchars($_POST["vacation_radio"], ENT_QUOTES); $name = htmlspecialchars($_POST["name"], ENT_QUOTES); $vacation_helo = htmlspecialchars($_POST["vacation_helo"], ENT_QUOTES); $kanso = htmlspecialchars($_POST["kanso"], ENT_QUOTES); $h = htmlspecialchars($_POST["h"], ENT_QUOTES); $m = htmlspecialchars($_POST["m"], ENT_QUOTES); if(isset($_POST["vacation"])){ $vacation_radio_search = array("1", "2", "3"); $vacation_radio_replace = array('午前', '午後', '深夜); $vacation_radio_a = str_replace($vacation_radio_search, $vacation_radio_replace, $vacation_radio); $vacation_helo_search = array("5", "6"); $vacation_helo_replace = array('おはようございます。', 'おつかれさまです。'); $vacation_helo_a = str_replace($vacation_helo_search, $vacation_helo_replace, $vacation_helo); mb_convert_variables('UTF-8', 'EUC-JP', $name); mb_convert_variables('UTF-8', 'EUC-JP', $kanso); $mail_object = "ITSG ". $vacation_radio_a ." ". $name ; $mail_ob = $vacation_helo_a. "\n". $name ."\n\n". $vacation_radio_a ."\n". $kanso; if (mb_send_mail("test@test.com", $mail_object, $mail_ob, "From: test@test.com")) { echo "メールが送信されました。"; } else { echo "メールの送信に失敗しました。"; } } if(isset($_POST["flex"])) { $vacation_helo_search = array("7", "8"); $vacation_helo_replace = array('おはようございます。', 'おつかれさまです。'); $vacation_helo_a = str_replace($vacation_helo_search, $vacation_helo_replace, $vacation_helo); mb_convert_variables('UTF-8', 'EUC-JP', $name); mb_convert_variables('UTF-8', 'EUC-JP', $kanso); $mail_object_a = $name . " " . $h . ":" . $m ; //$mail_ob_a = $vacation_helo_a. "\n". $name ."\n\n". $h .":" . $m ."\n". $kanso; $mail_ob_a = $vacation_helo_a; if (mb_send_mail("test@test.com", $mail_object_a, $mail_ob_a, "From: test@test.com")) { echo "メールが送信されました。"; } else { echo "メールの送信に失敗しました。"; } } } flexの7と8の値が帰って来ません。 どうしたらよいのでしょうか? わからないなりにつくってみたのでソースが汚いと思いますが、よろしくお願い致します。

    • ベストアンサー
    • PHP
  • ループ内での後方参照の使用に関して

    下記のようなプログラムを作成しました。 (Perl のバージョンは 5.8.8 となります。) for ($i=0; $i<=105; $i++) { $str1 = "str1"; $str2 = "1234567890str1test"; $str2=~ s/^(\d+)($str1)/test/g; print $i."\n"; print $1."\n"; print $2."\n"; print $str2."\n"; } このプログラムを実行しますと、ループが100回実施するまでは $1, $2の値を 取得できるのですが、100回を超えると取得できなくなります。 (上記で行っている置換処理は100回を超えても正常に処理されます。) 質問としましては、この現象は Perl のバグなのでしょうか。 それとも、私の正規表現の書き方に不備があるのでしょうか。 ネットでいろいろ調べてみたのですが、答えが見つからなかったため、 質問させていただきました。 よろしくお願い致します。

  • phpで作成したファイルをシェルで読み込むと最後の行を読み込めない

    phpでリストを取得し、ファイルに書き込んでいます。 リストはスペース区切りで帰ってくるので、改行コードに変換しています。 $str = "a b c"; $str =str_replace(" ","\n",$str); //リストファイルへ書き込み $pointer=fopen("aaa.txt","w"); flock($pointer, LOCK_EX); fputs($pointer, $str); flock($pointer, LOCK_UN); fclose($pointer); これをviで開いてみると a b c と予定通り書き込まれています。 このリストをシェルスクリプトでループして読み込んでいるのですが 最後の行を読み込んでくれません。 while read line do echo "$line" done < aaa.txt とやると 最後の行が読み込まれないんです!(aとbしか表示されない) ちなみに、aaa.txtをviで開いて何もせずに保存終了すると 正常に最後の行が表示されることから、aaa.txtの終了コードがうまく 書き込まれていないのでは?と予想していますが、よくわかっていません。 どうしたら最後の行を読んでくれるのでしょうか。 ※最後の行に改行コードをつけると次の空白行を読みにいってエラーになるのでそれ以外でお願いします。

    • 締切済み
    • PHP