SQLite-Fehler 'Versuch, eine schreibgeschützte Datenbank zu schreiben' beim Einfügen?

123

Ich habe eine SQLite-Datenbank, die ich für eine Website verwende. Das Problem ist, dass INSERT INTOich eine bekomme , wenn ich es versuchePDOException

SQLSTATE[HY000]: General error: 8 attempt to write a readonly database

Ich habe SSH in den Server und überprüfte Berechtigungen, und die Datenbank hat die Berechtigungen

-rw-rw-r--

Ich bin mit * nix-Berechtigungen nicht so vertraut, aber ich bin mir ziemlich sicher, dass dies bedeutet

  • Kein Verzeichnis
  • Der Besitzer hat Lese- / Schreibberechtigungen (das bin ich laut ls -l)
  • Die Gruppe verfügt über Lese- / Schreibberechtigungen
  • Alle anderen haben nur Leseberechtigungen

Ich habe auch überall gesucht, wo ich wusste, dass ich das sqlite3Programm verwenden kann, und nichts Relevantes gefunden.

Da ich nicht wusste, mit welchen Berechtigungen PDO versucht, die Datenbank zu öffnen, habe ich es getan

chmod o+w supplies.db

Jetzt bekomme ich noch einen PDOException:

SQLSTATE[HY000]: General error: 14 unable to open database file

Es tritt jedoch NUR auf, wenn ich versuche, eine INSERTAbfrage auszuführen, nachdem die Datenbank geöffnet ist.

Irgendwelche Ideen, was los ist?

Austin Hyde
quelle
Grundsätzlich ist das httpd (apache> php> PDO) nicht Sie, also besitzt es die Datei nicht, hat also keine Schreibberechtigungen ... interessant ...
SparK
sudo chgrp www-data test.dbmit dem Hinzufügen von Berechtigungen für mich gearbeitet
Zippp

Antworten:

305

Das Problem, wie sich herausstellt, ist , dass die PDO SQLite - Treiber erfordert , dass , wenn Sie einen Schreibvorgang tun werden ( INSERT, UPDATE, DELETE, DROPusw.), dann werden die Ordner der Datenbank in wohnt Schreibrechte haben muss, sowie die tatsächlichen Datenbankdatei.

Ich habe diese Informationen in einem Kommentar ganz unten auf der PDO SQLite-Treiberhandbuchseite gefunden .

Austin Hyde
quelle
9
Außerdem darf SELinux (falls installiert) nicht erzwungen werden. Ich habe anderthalb Tage gebraucht, um das herauszufinden.
Steve V.
1
Hum, sorry, aber ich danke, dass es das war, aber es löste das Problem nur vorübergehend. Das Hauptproblem war, dass mein WWW-Datenbenutzer nicht in der WWW-Datengruppe war.
Dorian
5
Wie ich weiß, muss der enthaltende Ordner beschreibbar sein, da beim Schreiben eine Journaldatei erstellt wird und somit die Datenbank selbst. Um denselben Benutzer wie der Webserver zu haben, kopieren Sie den Inhalt der Datei in ein anderes erstelltes Ad-hoc-Verzeichnis.
lcapra
4
Auch die Datenbankdatei und das Verzeichnis, in dem sie sich befindet, müssen im Besitz von 'www-data' auf Linux-Boxen sein.
Anisbet
1
Derzeit verfügt sqlite3 möglicherweise über drei Dateien, die Dateien, .dba .db-shmund a .db-wal, und natürlich über das übergeordnete Verzeichnis der drei Dateien, die für den Benutzer, der das Programm ausführt , alle beschreibbar sein müssen.
Marcos Dione
17

Dies kann passieren, wenn der Eigentümer der SQLite-Datei selbst nicht mit dem Benutzer identisch ist, der das Skript ausführt. Ähnliche Fehler können auftreten, wenn nicht der gesamte Verzeichnispfad (dh jedes Verzeichnis auf dem Weg) beschrieben werden kann.

Wem gehört die SQLite-Datei? Du?

Als wen läuft das Skript? Apache oder niemand?

Charles
quelle
1
Ich besitze die SQLite-Datei, weiß aber nicht, als wen das Skript ausgeführt wird. Wie kann ich das herausfinden? (Denken Sie daran, dies ist auf einem gemeinsam genutzten Host und ich habe eingeschränkte Berechtigungen)
Austin Hyde
1
Ah, das macht mehr Spaß. Wenn Sie Shared Hosting verwenden, besteht eine sehr gute Chance, dass das Skript als "Niemand" oder "Apache" ausgeführt wird. Lassen Sie Ihr Skript eine Datei ( file_put_contents('./foo.txt', 'Hello, world');) erstellen , die Ihnen zeigt, als wen es ausgeführt wird. Möglicherweise muss das Skript die SQLite-Datenbank erstellen. Dies kann eine unterhaltsame Übung sein, wenn Sie bereits Daten in Ihrer aktuellen Datei haben ...
Charles
Gute Idee, aber no-go. Wer auch immer PHP ausführt, hat keine Schreibrechte, daher kann er die Datei nicht erstellen. Gibt es überhaupt PHP, das abrufen kann, als welcher Benutzer es gerade ausgeführt wird?
Austin Hyde
Der einzige Weg scheint über die POSIX-Erweiterung zu sein , die auf POSIX-y-Systemen standardmäßig aktiviert ist. Ihr Hosting-Anbieter hat möglicherweise R'd TFM und hat es deaktiviert.
Charles
Nun, sie haben TFM, okay. posix_getuid()funktioniert auch nicht.
Austin Hyde
6

Für mich ging es eher um die Durchsetzung von SELinux als um Berechtigungen. Der Fehler "Nur-Lese-Datenbank" verschwand, nachdem ich die Durchsetzung deaktiviert hatte, gemäß dem Vorschlag von Steve V. in einem Kommentar zur akzeptierten Antwort.

echo 0 >/selinux/enforce

Bei Ausführung dieses Befehls funktionierte alles wie vorgesehen (CentOS 6.3).

Das spezielle Problem, auf das ich gestoßen war, war beim Einrichten von Graphite. Ich hatte dreimal überprüft, ob der Apache-Benutzer Eigentümer war und sowohl in meine graphite.db als auch in das übergeordnete Verzeichnis schreiben konnte. Aber bis ich SELinux "repariert" habe, war alles, was ich bekam, eine Stapelverfolgung mit dem Effekt von: DatabaseError: Versuch, eine schreibgeschützte Datenbank zu schreiben

Noah Sussman
quelle
8
SELinux ist eine Sicherheitsmaßnahme und sollte daher nicht ohne guten Grund deaktiviert werden. Es ist besser herauszufinden, warum SELinux überhaupt blockiert, und es richtig zu konfigurieren, anstatt es zu deaktivieren.
Jens Wegar
5

Dies kann durch SELinux verursacht werden. Wenn Sie SELinux nicht vollständig deaktivieren möchten, müssen Sie das Datenbankverzeichnis fcontext auf httpd_sys_rw_content_t setzen.

semanage fcontext -a -t httpd_sys_rw_content_t "/var/www/railsapp/db(/.*)?"
restorecon -v /var/www/railsapp/db
Andy Fraley
quelle
4

Ich habe diesen Fehler erhalten, als ich versucht habe, in eine Datenbank auf einem Android-System zu schreiben.

Anscheinend benötigt sqlite3 nicht nur Schreibberechtigungen für die Datenbankdatei und das enthaltende Verzeichnis (wie @ austin-hyde bereits in seiner Antwort sagte), sondern auch die Umgebungsvariable TMPDIRmuss auf ein (möglicherweise beschreibbares) Verzeichnis verweisen.

Auf meinem Android-System habe ich es eingestellt TMPDIR="/data/local/tmp"und jetzt läuft mein Skript wie erwartet :)

Bearbeiten:

Wenn Sie keine Umgebungsvariablen festlegen können, können Sie eine der anderen hier aufgeführten Methoden verwenden: https://www.sqlite.org/tempfiles.html#temporary_file_storage_locations likePRAGMA temp_store_directory = 'directory-name';

Thilo
quelle
2

Ich habe den gleichen Fehler von IIS unter Windows 7 erhalten. Um diesen Fehler zu beheben, musste ich dem IUSR-Konto für SQLite-Datenbankdateien Vollzugriffsberechtigungen hinzufügen. Sie müssen die Berechtigungen nicht ändern, wenn Sie SQLite unter Webmatrix anstelle von IIS verwenden.

l0pan
quelle
2

Zusammenfassend habe ich das Problem behoben, indem ich die Datenbankdatei (* .db) in einen Unterordner gestellt habe.

  • Der Unterordner und die darin enthaltene Datenbankdatei müssen Mitglied der Gruppe www-data sein.
  • In der Gruppe www-data müssen Sie das Recht haben, in den Unterordner und die Datenbankdatei zu schreiben.
Erkan Hürnalı
quelle
0

Ich habe dies in meinem Browser erhalten, als ich von http: // localhost zu http://145.900.50.20 (wobei 145.900.50.20 meine lokale IP-Adresse ist) gewechselt und dann wieder zu localhost gewechselt habe - es war notwendig, bei der zu bleiben IP-Adresse, nachdem ich diese einmal geändert hatte

kris
quelle
0

Ich benutzte:

echo exec ('whoami');

Um herauszufinden, wer das Skript ausführt (z. B. Benutzername), und dem Benutzer dann Berechtigungen für das gesamte Anwendungsverzeichnis zu erteilen, wie z.

sudo chown -R: Benutzername / var / www / html / myapp

Hoffe das hilft jemandem da draußen.

Shasi Kanth
quelle