SQLite/PHP只读模式?

9

我一直在尝试使用PHP中的PDO包装器与SQLite进行交互,取得了一些进展。 我可以从数据库中读取数据,但当我在浏览器中查看页面时,我的所有更新都未被提交到数据库中。奇怪的是,从我的shell中运行该脚本却可以成功地更新数据库。我怀疑可能是文件权限的问题,但即使将数据库的权限设置为完全访问(chmod 777),问题仍然存在。我应该尝试更改文件所有者吗?如果是这样,应该指定为哪个用户呢?

顺便说一下,我的机器是标准的Mac OS X Leopard安装,并已激活PHP。

@Tom Martin

谢谢您的回复。我刚刚运行了您的代码,发现PHP以用户_www运行。然后我尝试将数据库的所属权更改为_www,但这也没有起作用。

我还应该注意的是,PDO的errorInfo函数并未指示出现错误。这可能是PDO的某个设置,以只读方式打开了数据库吗?我听说SQLite会对整个文件进行写锁定。有没有可能是其他程序正在阻止写入,从而导致数据库被锁定?

我决定包含相关的代码。这将基本上是将Grant的脚本移植到PHP中。目前只包含Questions部分:

<?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>";

?>

抱歉,我无法再为您提供更多帮助。如果您可以从 shell 中使其正常工作,那么仍然可能是权限问题。 - Tom Martin
谢谢你的帮助。我也觉得这可能是一个权限问题,但我不明白为什么会出现这种情况。 - Kyle Cronin
尝试将 $db = new PDO('sqlite:test.db'); 更改为完整路径?比如说.. $db = new PDO('sqlite:/tmp/test.db'); ? - dbr
刚试了一下,没有任何区别。不过还是谢谢你的建议。 - Kyle Cronin
6个回答

12

Kyle,为了让PDO/Sqlite工作,你需要在数据库所在的目录拥有写入权限。

另外,我注意到你在循环中执行多个查询。如果你正在构建一些小型且负载不重的东西,这可能没问题。否则,我建议构建一个返回多个行并在单独的循环中处理它们的单个查询。


你修好了!谢谢!脚本大部分是逐行复制Grant的脚本,它以这种方式执行SQL语句。但是,我正在研究如何进行O(1) SELECT并将UPDATES排队,在最后执行它们。 - Kyle Cronin
我只想表达我的感谢,我从来没有想到这会是答案。我正在使用SQLite3(没有PDO),这对我帮助很大。 - John Chadwick

2

我在PHP手册上找到了答案:“存放数据库文件的文件夹必须可写。”


1

针对在 OS X 上遇到 SQLite 只读问题的人:

1)确定 Apache httpd 用户和用户所属的组:

grep "^User" /private/etc/apache2/httpd.conf
groups _www

2)在/Library/WebServer/Documents中创建一个子目录,用于存放您的数据库,并将其组更改为 httpd 的组:

sudo chgrp _www /Library/WebServer/Documents/db

一个不太安全的选项是打开/Library/WebServer/Documents的权限:

sudo chmod a+w /Library/WebServer/Documents


1

我认为PHP通常以用户“nodody”运行。不过在Mac上不确定。如果Mac有whoami,您可以尝试echo exec('whoami');来找出。


0

嗯,我现在也遇到了同样的问题,并通过一个错误找到了解决方法:只需将每个插入SQL指令放置在try...catch块中即可。这样可以确保你以正确的方式进行操作,否则它就不起作用。好了,现在它可以工作了。祝其他遇到此问题的人好运(因为我自己也使用了这个线程来尝试解决我的问题)。


0

@Tom 这取决于主机的设置。如果服务器将PHP作为Apache模块运行,则很可能是'nobody'(通常是设置为Apache用户的任何用户)。但是,如果PHP设置为cgi(例如fast-cgi),并且服务器运行SuExec,则php将作为拥有文件的同一用户运行。

无论哪种方式,包含数据库的文件夹必须可被脚本写入,可以是相同的用户,也可以是具有php用户写入权限的用户。

@Michal 除此之外,您可以使用beginTransaction();执行所有所需的操作,然后comit();来实际提交它们。


据我回忆,即使是在OSX 10.5(桌面版,而非服务器版)中自带的“标准”Apache/PHP安装程序也只包含PHP4。如果您想要享受PHP5的好处(并且重新编译Apache以获得更多通常与Apache+PHP+MySQL设置一起使用的功能),则必须重新编译PHP。 - Karl Blessing

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接