SQLite/PHP は読み取り専用ですか?
-
09-06-2019 - |
質問
PHP の PDO ラッパーで SQLite を使用しようとしましたが、うまくいきませんでした。データベースからは正常に読み取ることができますが、ブラウザでページを表示すると、更新がデータベースにコミットされません。不思議なことに、シェルからスクリプトを実行するとデータベースが更新されます。ファイル権限が原因ではないかと疑ったのですが、データベースがフルアクセス (chmod 777) を提供しているにもかかわらず、問題は解決しません。ファイルの所有者を変更してみる必要がありますか?もしそうなら、どうすればよいでしょうか?
ちなみに、私のマシンは Mac OS X Leopard を標準インストールし、PHP を有効化したものです。
@トム・マーティン
お返事ありがとうございます。コードを実行したところ、PHP はユーザー _www として実行されているようです。次に、データベースを _www が所有するように chown しようとしましたが、それも機能しませんでした。
PDO の errorInfo 関数は、エラーが発生したことを示していないことにも注意してください。これは、PDO がデータベースを読み取り専用で開く設定になっている可能性がありますか?SQLite はファイル全体に対して書き込みロックを実行すると聞いたことがあります。書き込みを妨げるものによってデータベースがロックされている可能性はありますか?
問題のコードを含めることにしました。これは多かれ少なかれ、 グラントの脚本 PHPに。これまでのところ、質問セクションだけです。
<?php
$db = new PDO('sqlite:test.db');
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://stackoverflow.com/users/658/kyle");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_COOKIE, "shhsecret=1293706652");
$page = curl_exec($ch);
preg_match('/summarycount">.*?([,\d]+)<\/div>.*?Reputation/s', $page, $rep);
$rep = preg_replace("/,/", "", $rep[1]);
preg_match('/iv class="summarycount".{10,60} (\d+)<\/d.{10,140}Badges/s', $page, $badge);
$badge = $badge[1];
$qreg = '/question-summary narrow.*?vote-count-post"><strong.*?>(-?\d*).*?\/questions\/(\d*).*?>(.*?)<\/a>/s';
preg_match_all($qreg, $page, $questions, PREG_SET_ORDER);
$areg = '/(answer-summary"><a href="\/questions\/(\d*).*?votes.*?>(-?\d+).*?href.*?>(.*?)<.a)/s';
preg_match_all($areg, $page, $answers, PREG_SET_ORDER);
echo "<h3>Questions:</h3>\n";
echo "<table cellpadding=\"3\">\n";
foreach ($questions as $q)
{
$query = 'SELECT count(id), votes FROM Questions WHERE id = '.$q[2].' AND type=0;';
$dbitem = $db->query($query)->fetch(PDO::FETCH_ASSOC);
if ($dbitem['count(id)'] > 0)
{
$lastQ = $q[1] - $dbitem['votes'];
if ($lastQ == 0)
{
$lastQ = "";
}
$query = "UPDATE Questions SET votes = '$q[1]' WHERE id = '$q[2]'";
$db->exec($query);
}
else
{
$query = "INSERT INTO Questions VALUES('$q[3]', '$q[1]', 0, '$q[2]')";
echo "$query\n";
$db->exec($query);
$lastQ = "(NEW)";
}
echo "<tr><td>$lastQ</td><td align=\"right\">$q[1]</td><td>$q[3]</td></tr>\n";
}
echo "</table>";
?>
解決
カイル、PDO/Sqlite が機能するには、データベースが存在するディレクトリへの書き込み権限が必要です。
また、ループ内で複数の選択を実行していることがわかります。小さくて負荷が高くないものを構築している場合は、これで問題ないかもしれません。それ以外の場合は、複数の行を返す単一のクエリを作成し、それらを別のループで処理することをお勧めします。
他のヒント
で答えを見つけました PHPマニュアル 「データベース ファイルを格納するフォルダーは書き込み可能である必要があります。」
PHP は通常、ユーザー「nodody」として実行されると思います。ただし、Mac についてはわかりません。Macにwhoamiがある場合は試してみてください echo exec('whoami');
調べるために。
OS X 上の SQLite で読み取り専用の問題が発生した場合:
1) Apache を決定する httpd ユーザーとユーザーが所属するグループ:
grep "^User" /private/etc/apache2/httpd.conf
グループ_www
2) にサブディレクトリを作成します /ライブラリ/Webサーバー/ドキュメント データベースのグループを httpd のグループに変更します。
sudo chgrp _www /ライブラリ/WebServer/Documents/db
安全性の低いオプションは、次の権限を開くことです。 /ライブラリ/Webサーバー/ドキュメント:
sudo chmod a+w /ライブラリ/Webサーバー/ドキュメント
@Tomは、サーバーがApacheモジュールとしてPHPを実行している場合、ホスティングのセットアップに依存します。それは「誰も」である可能性があります(通常、Apacheがセットアップしているものは何でも)。ただし、PHP が CGI (fast-cgi など) としてセットアップされており、サーバーが SuExec を実行している場合、php はファイルを所有する同じユーザーとして実行されます。
いずれにしても、データベースを含むフォルダーは、同じユーザーであるか、書き込み権限が php ユーザーに設定されていることで、スクリプトによって書き込み可能でなければなりません。
@michalはさておき、begintransaction()を使用できます。必要なアクションをすべて実行してから comit();実際にコミットしてみます。
さて、私は今同じ問題を抱えていましたが、間違いでそれを理解しました:SQL 命令のすべての挿入部分を try...catch
それをブロックします。正しい方法でやらないとうまくいきません。さて、今は機能しています。この問題を抱えている他の人にとって幸運を祈ります(私自身もこのスレッドを使用して問題を解決しようとしたため)。