Ошибка SQLite "попытка записи базы данных только для чтения" во время вставки?

124

У меня есть база данных SQLite, которую я использую для веб-сайта. Проблема в том, что когда я пытаюсь INSERT INTOэто сделать, я получаюPDOException

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

Я подключился по SSH к серверу и проверил разрешения, а у базы данных есть разрешения

-rw-rw-r--

Я не очень знаком с разрешениями * nix, но уверен, что это означает

  • Не каталог
  • Владелец имеет права на чтение / запись (по словам меня ls -l)
  • У группы есть права на чтение и запись
  • У всех остальных есть только права на чтение

Я также искал везде, где знал об использовании sqlite3программы, и не нашел ничего подходящего.

Поскольку я не знал, с какими разрешениями PDO пытается открыть базу данных, я сделал

chmod o+w supplies.db

Теперь я получаю еще одно PDOException:

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

Но это происходит ТОЛЬКО, когда я пытаюсь выполнить INSERTзапрос после открытия базы данных.

Есть идеи о том, что происходит?

Остин Хайд
источник
в основном httpd (apache> php> PDO) - это не вы, поэтому он не владеет файлом, поэтому у него нет прав на запись ... интересно ...
SparK 05
sudo chgrp www-data test.dbс добавлением разрешений у меня
сработало

Ответы:

305

Проблема, как выясняется, является то , что драйвер PDO SQLite требует , что если вы собираетесь делать операцию записи ( INSERT, UPDATE, DELETE, DROPи т.д.), то папка базы данных постоянно находится в должен иметь права на запись, а также фактическое файл базы данных.

Я нашел эту информацию в комментарии в самом низу страницы руководства по драйверу PDO SQLite .

Остин Хайд
источник
9
Кроме того, SELinux (если он установлен) не должен быть принудительным. Мне потребовалось полтора дня, чтобы понять это.
Стив В.
1
Хм, извините, но я благодарен, что это было так, но это просто временно решило проблему, основная проблема заключалась в том, что мой пользователь www-data не входил в группу www-data.
Дориан
5
Насколько я знаю, содержащаяся папка должна быть доступной для записи, потому что при записи будет создан файл журнала, а значит, и сама база данных. Чтобы иметь того же пользователя, что и веб-сервер, попробуйте скопировать содержимое файла в другой созданный специально.
lcapra
4
Также файл db и каталог, в котором он находится, должны принадлежать www-data в ящиках Linux.
anisbet 08
1
В настоящее время sqlite3 может иметь 3 файла, файлы, .dba .db-shmи a .db-wal, и, конечно же, родительский каталог из трех, который должен быть доступен для записи пользователю, запускающему программу.
Маркос Дион
17

Это может произойти, если владелец самого файла SQLite не совпадает с пользователем, запускающим сценарий. Подобные ошибки могут возникнуть, если нельзя записать весь путь к каталогу (то есть каждый каталог по пути).

Кому принадлежит файл SQLite? Вы?

От кого запущен сценарий? Апач или никто?

Чарльз
источник
1
У меня есть файл SQLite, но я не знаю, от кого запускается скрипт. Как я могу узнать? (Имейте в виду, это на общем хосте, и у меня ограниченные права)
Остин Хайд
1
Ах, это делает вещи веселее. Если вы находитесь на виртуальном хостинге, очень высока вероятность, что сценарий будет работать как «none» или «apache». Пусть ваш скрипт создаст файл ( file_put_contents('./foo.txt', 'Hello, world');), который покажет вам, от кого он работает. Скорее всего, вам понадобится скрипт для создания базы данных SQLite. Это может быть интересным упражнением, если у вас уже есть данные в вашем текущем файле ...
Чарльз
Хорошая идея, но нет. У кого бы ни был запущен PHP, нет прав на запись, поэтому он не может создать файл. Есть ли способ узнать, от имени какого пользователя он сейчас работает?
Остин Хайд
Кажется, единственный способ - использовать расширение POSIX , которое по умолчанию включено в системах POSIX-y. Однако ваш хостинг-провайдер может иметь R'd TFM и отключил его.
Charles
Ну, они R'd TFM, хорошо. posix_getuid()тоже не работает.
Остин Хайд,
6

Для меня проблема заключалась в применении SELinux, а не в разрешениях. Ошибка «база данных только для чтения» исчезла, как только я отключил принудительное исполнение, следуя предложению Стива В. в комментарии к принятому ответу.

echo 0 >/selinux/enforce

После запуска этой команды все заработало, как задумано (CentOS 6.3).

Конкретная проблема, с которой я столкнулся, возникла во время установки Graphite. Я трижды проверил, владеет ли пользователь apache и может ли он писать как в мой graphite.db, так и в его родительский каталог. Но пока я не "исправил" SELinux, все, что у меня было, это трассировка стека с эффектом: DatabaseError: попытка записи базы данных только для чтения

Ной Сассман
источник
8
SELinux - это мера безопасности, поэтому не следует отключать ее без уважительной причины. Лучше сначала выяснить, почему SELinux блокирует, и правильно настроить его, а не отключать.
Йенс Вегар,
5

Это может быть вызвано SELinux. Если вы не хотите полностью отключать SELinux, вам необходимо установить для каталога db fcontext значение httpd_sys_rw_content_t.

semanage fcontext -a -t httpd_sys_rw_content_t "/var/www/railsapp/db(/.*)?"
restorecon -v /var/www/railsapp/db
Энди Фрейли
источник
4

Я получил эту ошибку, когда попытался записать в базу данных в системе Android.

По-видимому, sqlite3 не только нужны разрешения на запись в файл базы данных и содержащий каталог (как уже сказал @ austin-hyde в своем ответе), но и переменная среды TMPDIRдолжна указывать на (возможно, доступный для записи) каталог.

В моей системе Android я установил его, TMPDIR="/data/local/tmp"и теперь мой скрипт работает, как ожидалось :)

Редактировать:

Если вы не можете установить переменные среды, вы можете использовать один из других методов, перечисленных здесь: https://www.sqlite.org/tempfiles.html# Contemporary_file_storage_locations, напримерPRAGMA temp_store_directory = 'directory-name';

Тило
источник
2

Я получил ту же ошибку от IIS под Windows 7. Чтобы исправить эту ошибку, мне пришлось добавить разрешения на полный контроль учетной записи IUSR для файла базы данных sqlite. Вам не нужно менять разрешения, если вы используете sqlite под веб-матрицей вместо IIS.

l0pan
источник
2

Таким образом, я решил проблему, поместив файл базы данных (* .db) во вложенную папку.

  • Подпапка и файл базы данных в ней должны входить в группу www-data.
  • В группе www-data у вас должно быть право записи в подпапку и файл базы данных.
Эркан Хюрнали
источник
0

Я получил это в своем браузере, когда перешел с http: // localhost на http://145.900.50.20 (где 145.900.50.20 - мой локальный IP-адрес), а затем снова вернулся на localhost - необходимо было остаться с IP-адрес после того, как я сменил на него однажды

крис
источник
0

Я использовал:

эхо exec ('whoami');

чтобы узнать, кто запускает сценарий (скажем, имя пользователя), а затем предоставил пользователю разрешения на весь каталог приложения, например:

sudo chown -R: имя пользователя / var / www / html / myapp

Надеюсь, это поможет кому-то там.

Shasi Kanth
источник