
PHP初心者です。
CSVデータを活用してサイトを作ろうとしているのですが、
フリーワードで検索すると下記のようなエラーが出てしまいます。
Fatal error: Allowed memory size of 52428800 bytes exhausted
(tried to allocate 77287300 bytes) in
レンタルサーバー(ロリポップ)に
memory_limitについて問い合わせたところ、
消費メモリを削減して対処してほしいと言われました。
10件だけ表示するようにすれば解決するかと思い、
自分なりにあれこれいじってみたのですが、
うまくいきませんでした。
10件だけ表示する方法やメモリ消費を抑える方法を
お分かりになる方がいらっしゃいましたら、
ぜひご教授お願いいたします。
-index.php-トップページ
<form action="search.php" method="get"><input type="text" name="key" size="90">
<input type="submit" name="submit" value="検索"></form>
-seach.php-検索結果表示ページ
<?php
if($_GET["key"]==""){
print"キーワードを入力してください";
}else{
$KeyWord=$_GET["key"];
$KeyWord=htmlspecialchars($KeyWord);
$KeyWord=mb_convert_encoding($KeyWord,"Shift_JIS");
$KeyWord=mb_convert_kana($KeyWord,s);
$ArrKeyword=explode(" ",$KeyWord);
$Result=array();
$Data=file("item.csv");
for($i=0;$i<sizeof($Result);$i++){
$lines=strip_tags($Data[$i]);
$Match=true;
for($n=0;$n<sizeof($ArrKeyword);$n++){
if(!eregi($ArrKeyword[$n],$lines)){
$Match=false;
break;
}
}
if($Match==true){
array_push($Result,$Data[$i]);
}
}
?>
<?php
$n=sizeof($Result);
if($n==0){
print"見つかりませんでした";
}else{
print"{$n}件見つかりました";
?>
<ul>
<?php
for($i=0;$i<sizeof($Result);$i++){
$line=explode(",",$Result[$i]);
?>
<li><a href="item.php?id=<?=$line[0]?>"><?=$line[3]?></a></li>
<?php
}
}
}
?>
下記の行がエラーのようです。
for($i=0;$i<sizeof($Result);$i++){
No.4ベストアンサー
- 回答日時:
fopen関数に変更したものを書いてみました。
<?php
$ArrKeywordLength = sizeof($ArrKeyword);
$fp = fopen('item.csv', "r");
$Result=array();
while(!feof($fp)){
$ret = fgets($fp, 4096);
$lines = strip_tags($ret);
$Match=true;
for($n=0; $n<$ArrKeywordLength;$n++){
if(!eregi($ArrKeyword[$n], $lines)){
$Match = false;
break;
}
}
if($Match === true){
$Result[] = $ret;
}
}
?>
処理速度はだいたい一緒ですが、メモリの最大使用量が控えめです。
file関数は、テキストの内容を改行区切りで一気に配列に代入するという動作を行っているため、
その時点で一気にメモリ使用量が増えてしまいます。
fopen関数でファイルを開いて一行ずつ読み出し、という方法を行えば、
一気にデータを取得しないし配列に展開しないため、メモリ消費量が抑えられます。
また、for文中に「sizeof(又はcount)関数」で配列の長さを取得すると
1回ループごとに再計算を行いますので、処理が遅くなります(うろ覚えですが)
出来れば、for文の外側で配列の長さを取得してから変数で与えてやったほうがよりよいです。
array_push関数に関しては、
$var[] = $str;
この記述方法でまったく同じ動作をし、なおかつ若干動作が速いです。
eregi関数に関しては、要件が分からなかったのでそのままにしましたが、
もし、単純に文字列が含まれているかを確認するのであれば、前の回答者さんが仰っているようにstrposを利用したほうが早いです。
また、eregi関数は、正規表現を利用することが出来ます。もし検索ワードに正規表現が含まれている場合は、正規表現でマッチングを行ってしまいますが、それでは問題があるのであれば、前述したようにstrposをご利用したほうが良いです。
<?php
if(strpos($lines, $ArrKeyword[$n]) === false){ //もし適合しなかったらという条件
}
?>
わざわざプログラムを作って書いていただきありがとうございます。
実行してみたところ、一行目の
$ArrKeywordLength = sizeof($ArrKeyword);
の部分でエラーが出たのですが、一行目を削除したら、
おっしゃる通りメモリの使用が少なくなり、
無事表示することができました。
本当にありがとうございます。
一行目は削除しても問題なかったのでしょうか?
No.6
- 回答日時:
記述したのは該当ロジック部分のみになりますので、
$KeyWordの内容を$ArrKeyWordに保存しなければnullのため、エラーになってしまいます。
一度、質問者さんが記述したプログラムに当て込んで見てください。
また、別の回答者さんが仰っているようにデータベースに移行することも検討してみてください。
最初はSQLiteのようなファイルベースの簡易データベースから触れると、労力も少なくて良いと思います。
そうなんですか…。
今確認したところ、apache上ではできたのですが、
ロリポップにアップロードしたらメモリオーバーしました(汗)
SQLiteも調べてみます。
本当にどうもありがとうございました。
No.5
- 回答日時:
データが数万あるならば、データベースの使用を検討したほうがいいかもしれません。
この回答への補足
アドバイスありがとうございます。
本当はそうした方がいいのかもしれませんね。
ただ、データベースの使用となると、
また覚えることが増えるので躊躇してしまいます…。
No.3
- 回答日時:
fopen関数に変更したものを書いてみました。
<?php
$ArrKeywordLength = sizeof($ArrKeyword);
$fp = fopen('item.csv', "r");
$Result=array();
while(!feof($fp)){
$ret = fgets($fp, 4096);
$lines = strip_tags($ret);
$Match=true;
for($n=0; $n<$ArrKeywordLength;$n++){
if(!eregi($ArrKeyword[$n], $lines)){
$Match = false;
break;
}
}
if($Match === true){
$Result[] = $ret;
}
}
?>
処理速度はだいたい一緒ですが、メモリの最大使用量が控えめです。
file関数は、テキストの内容を改行区切りで一気に配列に代入するという動作を行っているため、
その時点で一気にメモリ使用量が増えてしまいます。
fopen関数でファイルを開いて一行ずつ読み出し、という方法を行えば、
一気にデータを取得しないし配列に展開しないため、メモリ消費量が抑えられます。
また、for文中に「sizeof(又はcount)関数」で配列の長さを取得すると
1回ループごとに再計算を行いますので、処理が遅くなります(うろ覚えですが)
出来れば、for文の外側で配列の長さを取得してから変数で与えてやったほうがよりよいです。
array_push関数に関しては、
$var[] = $str;
この記述方法でまったく同じ動作をし、なおかつ若干動作が速いです。
eregi関数に関しては、要件が分からなかったのでそのままにしましたが、
もし、単純に文字列が含まれているかを確認するのであれば、前の回答者さんが仰っているようにstrposを利用したほうが早いです。
また、eregi関数は、正規表現を利用することが出来ます。もし検索ワードに正規表現が含まれている場合は、正規表現でマッチングを行ってしまいますが、それでは問題があるのであれば、前述したようにstrposをご利用したほうが良いです。
<?php
if(strpos($lines, $ArrKeyword[$n]) === false){ //もし適合しなかったらという条件
}
?>
No.2
- 回答日時:
eregiよりはstrposを使用してみてはどうでしょう。
$Result=array();
$Data=file("item.csv");
foreach ($Data as $lines) {
$Match=true;
foreach($ArrKeyword as $key) {
if(!strpos($lines,$key)){
$Match = false;
break;
}
}
if($Match==true){
array_push($Result,$lines);
}
}
アドバイスありがとうございます。
やってみたところ、やはり同じエラーが出ました。
行が数万あるのでcsvファイルが大きすぎなのでしょうか…。
さらにいろいろいじってるうちに
なぜか結果表示までできなくなってしまいました(涙)
No.1
- 回答日時:
file()なんかで処理せずにきちんとfopenしてfgetcsv()などで
処理してみてはどうでしょうか?
http://www.php.net/manual/ja/function.fgetcsv.php
解答ありがとうございます。
お恥ずかしい話ですが、
ネットでいろいろ検索していて
fgetcsvというものがあるのはわかったのですが、
初心者なので具体的にどうプログラムに
書けばいいのかわからないので諦めていました。
なので、下記のサイトを参考にして
プログラムを作成しようと思っているんです。
http://affiliate.aki-f.com/prog/page/35.html
重ねて質問をしてとても申し訳ないのですが、
どのように記述すればよろしいのでしょうか?
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- PHP PHPで画像の渡しが上手く行きません。 1 2023/02/02 09:39
- PHP php テーブルが作成できない 1 2022/11/17 23:41
- PHP PHPでCookieを使った訪問回数について 1 2023/05/28 14:10
- MySQL php テーブルを作れない 2 2022/11/17 18:22
- Excel(エクセル) PHPプログラムをエクセルに張り付けると検索ボックスがでてくる! 3 2022/05/08 07:10
- PHP PHPのエラーの解消法について教えて下さい。 1 2023/02/06 10:48
- PHP PHPでユーザー情報を入力して簡易ログイン機能をつくってみたのですが 1 2023/05/29 08:51
- PHP if(preg_match("/[^0-9]/",$gu_d)){意味を教えてください。 1 2022/05/06 05:37
- JavaScript フォームが空欄の時にフォームの外をクリックすると、エラーが出るコードを調べています。 1 2023/06/25 11:51
- JavaScript javascript作成してます。ラジオボタンで判定するコードを書いてます。 1 2023/07/18 11:03
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
CakePHPのfindの取得件数は?
-
多次元連想配列のキーを変数で...
-
PHPでfile()を使った際の配列の...
-
配列をループでたくさん宣言し...
-
複数選択可能なリストボックス...
-
String だと「 ByRef引数の型が...
-
配列のランク付け
-
総当たりのアルゴリズムについて
-
Array Array と表示される
-
SimpleXML関数で取得したXML要...
-
DBを使用しないで「○件リスト表...
-
phpで表示件数をcsvの項目ごと...
-
[PHP] fputcsv()関数でファイル...
-
禁止ワード設定
-
unset使用時の利点
-
配列の値の更新方法について
-
ネストが深い時のforeachはどう...
-
PHP掲示板で新着順に表示させた...
-
配列を回すとき、最後の要素だ...
-
PHPからCSVをアップロード後、m...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
String だと「 ByRef引数の型が...
-
配列をループでたくさん宣言し...
-
$_SESSIONに二次元配列を使える...
-
チェックボックス複数選択 mys...
-
配列一致(要素順番は違うが内容...
-
file_existsでファイル名の部分...
-
Smartyのテンプレートからjavas...
-
ネストが深い時のforeachはどう...
-
foreachのなかで次のキーを参照...
-
漢字のソートについて
-
PHPにてクラスを配列にすること...
-
ExcelVBAのチェックボックスに...
-
URLのサブドメインとドメイン部...
-
PHPのカッコ[ ]の使い方について
-
配列を回すとき、最後の要素だ...
-
PHPのPOSTでの半角スペース
-
PHPのループ数限界値について
-
$_POSTを一括してサニタイズし...
-
postgresql関数をつかったレコ...
-
ファイルから指定行数分だけ読...
おすすめ情報