Błąd SQLite „próba zapisania bazy danych tylko do odczytu” podczas wstawiania?

124

Mam bazę danych SQLite, której używam na stronie internetowej. Problem polega na tym, że kiedy próbuję INSERT INTO, otrzymuję plikPDOException

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

Dostałem SSH do serwera i sprawdziłem uprawnienia, a baza danych ma uprawnienia

-rw-rw-r--

Nie znam uprawnień * nix, ale jestem pewien, że to oznacza

  • To nie jest katalog
  • Właściciel ma uprawnienia do odczytu / zapisu (według mnie to ja ls -l)
  • Grupa ma uprawnienia do odczytu / zapisu
  • Wszyscy inni mają tylko uprawnienia do odczytu

Rozejrzałem się też wszędzie, gdzie znałem sqlite3program, i nie znalazłem nic odpowiedniego.

Ponieważ nie wiedziałem, z jakimi uprawnieniami PDO próbuje otworzyć bazę danych, tak zrobiłem

chmod o+w supplies.db

Teraz dostaję inny PDOException:

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

Ale dzieje się to TYLKO wtedy, gdy próbuję wykonać INSERTzapytanie po otwarciu bazy danych.

Jakieś pomysły na temat tego, co się dzieje?

Austin Hyde
źródło
zasadniczo httpd (apache> php> PDO) to nie Ty, więc nie jest właścicielem pliku, więc nie ma uprawnień do zapisu ... ciekawe ...
SparK
sudo chgrp www-data test.dbz dodawaniem uprawnień działało dla mnie
Zippp

Odpowiedzi:

305

Problem, jak się okazuje, jest to, że sterownik PDO SQLite wymaga, że jeśli masz zamiar zrobić operacji zapisu ( INSERT, UPDATE, DELETE, DROP, etc), a następnie folder bazy danych rezyduje w musi mieć uprawnienia do zapisu, jak również rzeczywiste plik bazy danych.

Znalazłem tę informację w komentarzu na samym dole strony podręcznika sterownika PDO SQLite .

Austin Hyde
źródło
9
Ponadto SELinux (jeśli jest zainstalowany) nie może wymuszać. Zajęło mi półtora dnia, żeby to rozgryźć.
Steve V.
1
Hum, przepraszam, ale dziękuję, że to było to, ale rozwiązało to problem tymczasowo, głównym problemem było to, że mój użytkownik www-data nie był w grupie www-data.
Dorian,
5
Jak wiem, folder zawierający musi być zapisywalny, ponieważ podczas pisania zostanie utworzony plik dziennika, a więc sama baza danych. Aby mieć tego samego użytkownika co serwer WWW, spróbuj skopiować zawartość pliku do innego utworzonego ad hoc.
lcapra
4
Również plik db i katalog, w którym się znajduje, muszą należeć do „www-data” na komputerach z systemem Linux.
anisbet
1
Obecnie sqlite3 może mieć 3 pliki, a .db, a .db-shmi .db-waloczywiście katalog nadrzędny z tych trzech, które muszą być zapisywalne dla użytkownika uruchamiającego program.
Marcos Dione
17

Może się to zdarzyć, gdy właściciel pliku SQLite sam w sobie jest nie tak samo jak użytkownik uruchomiony skrypt. Podobne błędy mogą wystąpić, jeśli nie można zapisać całej ścieżki katalogu (czyli każdego katalogu po drodze).

Kto jest właścicielem pliku SQLite? Ty?

Dla kogo działa skrypt? Apache czy nikt?

Charles
źródło
1
Jestem właścicielem pliku SQLite, ale nie wiem, jako kogo działa skrypt. Jak mogę się dowiedzieć? (Pamiętaj, że to jest na wspólnym hoście i mam ograniczone uprawnienia)
Austin Hyde
1
Ach, to sprawia, że ​​jest fajniej. Jeśli korzystasz z hostingu współdzielonego, istnieje bardzo duża szansa, że ​​skrypt działa jako „nobody” lub „apache”. Niech twój skrypt utworzy plik ( file_put_contents('./foo.txt', 'Hello, world');), który pokaże ci, jako działa. Istnieje duże prawdopodobieństwo, że skrypt utworzy bazę danych SQLite. To może być zabawne ćwiczenie, jeśli masz już dane w swoim bieżącym pliku ...
Charles,
Dobry pomysł, ale nie idź. Ktokolwiek PHP działa jako, nie ma uprawnień do zapisu, więc nie może utworzyć pliku. Czy mimo to PHP może pobrać aktualnie uruchomiony użytkownik?
Austin Hyde
Wydaje się, że jedynym sposobem jest rozszerzenie POSIX , które jest domyślnie włączone w systemach POSIX-y. Twój dostawca hostingu może mieć R'd TFM i wyłączyć go.
Charles
Cóż, R'd TFM, w porządku. posix_getuid()też nie działa.
Austin Hyde
6

Dla mnie problemem było raczej egzekwowanie SELinuksa niż uprawnienia. Błąd „bazy danych tylko do odczytu” zniknął po wyłączeniu wymuszania, zgodnie z sugestią Steve'a V. w komentarzu do zaakceptowanej odpowiedzi.

echo 0 >/selinux/enforce

Po uruchomieniu tego polecenia wszystko działało zgodnie z przeznaczeniem (CentOS 6.3).

Konkretny problem, który napotkałem, dotyczył konfiguracji Graphite. Potrójnie sprawdziłem, czy użytkownik Apache jest właścicielem i może pisać zarówno w moim graphite.db, jak iw jego katalogu nadrzędnym. Ale dopóki nie "naprawiłem" SELinuksa, jedyne co otrzymałem to ślad stosu w wyniku: DatabaseError: próba napisania bazy danych tylko do odczytu

Noah Sussman
źródło
8
SELinux jest środkiem bezpieczeństwa, więc nie powinien być wyłączany bez bardzo dobrego powodu. Lepiej byłoby dowiedzieć się, dlaczego SELinux blokuje w pierwszej kolejności i poprawnie go skonfigurować zamiast wyłączać.
Jens Wegar
5

Może to być spowodowane przez SELinux. Jeśli nie chcesz całkowicie wyłączać SELinuksa, musisz ustawić katalog db fcontext na httpd_sys_rw_content_t.

semanage fcontext -a -t httpd_sys_rw_content_t "/var/www/railsapp/db(/.*)?"
restorecon -v /var/www/railsapp/db
Andy Fraley
źródło
4

Otrzymałem ten błąd, gdy próbowałem pisać do bazy danych w systemie Android.

Najwyraźniej sqlite3 nie tylko potrzebuje uprawnień do zapisu w pliku bazy danych i katalogu zawierającego (jak @ austin-hyde już powiedział w swojej odpowiedzi), ale także zmienna środowiskowa TMPDIRmusi wskazywać na katalog (prawdopodobnie zapisywalny).

W moim systemie Android ustawiłem to na TMPDIR="/data/local/tmp"i teraz mój skrypt działa zgodnie z oczekiwaniami :)

Edytować:

Jeśli nie możesz ustawić zmiennych środowiskowych, możesz użyć jednej z innych metod wymienionych tutaj: https://www.sqlite.org/tempfiles.html#temporary_file_storage_locations, np.PRAGMA temp_store_directory = 'directory-name';

Thilo
źródło
2

Otrzymałem ten sam błąd z IIS pod Windows 7. Aby naprawić ten błąd, musiałem dodać pełne uprawnienia kontrolne do konta IUSR dla pliku bazy danych sqlite. Nie musisz zmieniać uprawnień, jeśli używasz sqlite pod webmatrix zamiast IIS.

l0pan
źródło
2

Podsumowując, rozwiązałem problem, umieszczając plik bazy danych (* .db) w podfolderze.

  • Podfolder i znajdujący się w nim plik bazy danych muszą należeć do grupy www-data.
  • W grupie www-data musisz mieć prawo zapisu do podfolderu i pliku bazy danych.
Erkan Hürnalı
źródło
0

Dostałem to w mojej przeglądarce, kiedy zmieniłem z http: // localhost na http://145.900.50.20 (gdzie 145.900.50.20 to mój lokalny adres IP), a następnie zmieniłem z powrotem na localhost - konieczne było pozostanie przy Adres IP raz zmieniłem na ten raz

kris
źródło
0

Użyłem:

echo exec ('whoami');

aby dowiedzieć się, kto uruchamia skrypt (powiedzmy nazwę użytkownika), a następnie nadał użytkownikowi uprawnienia do całego katalogu aplikacji, na przykład:

sudo chown -R: nazwa użytkownika / var / www / html / myapp

Mam nadzieję, że to komuś pomoże.

shasi kanth
źródło