¿Error de SQLite 'intento de escribir una base de datos de solo lectura' durante la inserción?

124

Tengo una base de datos SQLite que estoy usando para un sitio web. El problema es que cuando lo intento INSERT INTO, obtengo unPDOException

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

SSH'd en el servidor y revisé los permisos, y la base de datos tiene los permisos

-rw-rw-r--

No estoy tan familiarizado con los permisos * nix, pero estoy bastante seguro de que esto significa

  • No es un directorio
  • El propietario tiene permisos de lectura / escritura (ese soy yo, según ls -l)
  • El grupo tiene permisos de lectura / escritura
  • Todos los demás solo tienen permisos de lectura

También busqué en todas partes que conocía el uso del sqlite3programa, y ​​no encontré nada relevante.

Como no sabía con qué permisos PDO está tratando de abrir la base de datos, lo hice

chmod o+w supplies.db

Ahora tengo otro PDOException:

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

Pero SOLO ocurre cuando intento ejecutar una INSERTconsulta después de que la base de datos está abierta.

¿Alguna idea de lo que está pasando?

Austin Hyde
fuente
Básicamente, el httpd (apache> php> PDO) no es usted, por lo que no posee el archivo, por lo que no tiene permisos de escritura ... interesante ...
SparK
sudo chgrp www-data test.dbcon agregar permisos funcionó para mí
Zippp

Respuestas:

305

El problema, como resulta, es que el conductor DOP SQLite requiere que si se va a realizar una operación de escritura ( INSERT, UPDATE, DELETE, DROP, etc), luego en la carpeta de la base de datos reside en deben tener permisos de escritura, así como la real archivo de base de datos.

Encontré esta información en un comentario en la parte inferior de la página del manual del controlador PDO SQLite .

Austin Hyde
fuente
9
Además, SELinux (si está instalado) no debe ser obligatorio. Me llevó un día y medio descubrirlo.
Steve V.
1
Hum, lo siento, pero agradezco que fuera así, pero solo resolvió el problema temporalmente, el problema principal era que mi usuario de www-data no estaba en el grupo de www-data.
Dorian
55
Como sé, la carpeta que contiene debe poder escribirse porque al escribir un diario se creará un archivo y, por lo tanto, el propio db. Para tener el mismo usuario que el servidor web, intente copiar el contenido del archivo a otro ad hoc creado.
lcapra
44
Además, el archivo db y el directorio en el que reside deben ser propiedad de 'www-data' en los cuadros de Linux.
anisbet
1
Actualmente sqlite3 podría tener 3 archivos, los .db, una .db-shm, y una .db-walarchivos, y por supuesto el directorio padre de los tres, el cual debe ser toda escritura para el usuario que ejecuta el programa.
Marcos Dione
17

Esto puede suceder cuando el propietario del archivo SQLite no es el mismo que el usuario que ejecuta el script. Se pueden producir errores similares si no se puede escribir en toda la ruta del directorio (es decir, en cada directorio del camino).

¿A quién pertenece el archivo SQLite? ¿Tú?

¿A quién se ejecuta el script? Apache o nadie?

Charles
fuente
1
Soy dueño del archivo SQLite, pero no sé con quién se ejecuta el script. ¿Cómo puedo averiguarlo? (Tenga en cuenta que esto está en un host compartido y tengo permisos limitados)
Austin Hyde
1
Ah, eso hace las cosas más divertidas. Si está en un alojamiento compartido, existe una muy buena posibilidad de que el script se ejecute como "nobody" o "apache". Haga que su script cree un archivo ( file_put_contents('./foo.txt', 'Hello, world');), que le mostrará a quién se está ejecutando. Lo más probable es que necesite que el script cree la base de datos SQLite. Este puede ser un ejercicio entretenido si ya tiene datos en su archivo actual ...
Charles
Buena idea, pero no. Quienquiera que ejecute PHP no tiene privilegios de escritura, por lo que no puede crear el archivo. ¿Hay alguna forma de que PHP pueda recuperar a qué usuario se está ejecutando actualmente?
Austin Hyde
La única forma parece ser a través de la extensión POSIX , que está habilitada de manera predeterminada en los sistemas POSIX-y. Sin embargo, su proveedor de alojamiento puede tener R'd TFM y deshabilitarlo.
Charles
Bueno, R'd TFM, está bien. posix_getuid()tampoco funciona
Austin Hyde
6

Para mí, el problema era la aplicación de SELinux en lugar de los permisos. El error de "base de datos de solo lectura" desapareció una vez que desactivé la aplicación, siguiendo la sugerencia hecha por Steve V. en un comentario sobre la respuesta aceptada.

echo 0 >/selinux/enforce

Al ejecutar este comando, todo funcionó según lo previsto (CentOS 6.3).

El problema específico que encontré fue durante la configuración de Graphite. Verifiqué tres veces que el usuario de apache era propietario y podía escribir tanto en mi graphite.db como en su directorio principal. Pero hasta que "solucioné" SELinux, todo lo que obtuve fue un seguimiento de la pila en el sentido de: DatabaseError: intento de escribir una base de datos de solo lectura

Noah Sussman
fuente
8
SELinux es una medida de seguridad, por lo que no debe deshabilitarse sin una muy buena razón. Sería mejor averiguar por qué SELinux está bloqueando en primer lugar y configurarlo correctamente en lugar de deshabilitarlo.
Jens Wegar
5

Esto puede ser causado por SELinux. Si no desea deshabilitar SELinux por completo, debe configurar el directorio db fcontext en 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
fuente
4

Recibí este error cuando intenté escribir en una base de datos en un sistema Android.

Aparentemente, sqlite3 no solo necesita permisos de escritura en el archivo de la base de datos y el directorio que lo contiene (como ya dijo @ austin-hyde en su respuesta) sino que también la variable de entorno TMPDIRdebe apuntar a un directorio (posiblemente editable).

En mi sistema Android lo configuré TMPDIR="/data/local/tmp"y ahora mi script se ejecuta como se esperaba :)

Editar:

Si no puede establecer variables de entorno, puede usar uno de los otros métodos enumerados aquí: https://www.sqlite.org/tempfiles.html#temporary_file_storage_locations comoPRAGMA temp_store_directory = 'directory-name';

Thilo
fuente
2

Recibí el mismo error de IIS en Windows 7. Para solucionar este error, tuve que agregar permisos de control total a la cuenta IUSR para el archivo de base de datos sqlite. No necesita cambiar los permisos si usa sqlite en webmatrix en lugar de IIS.

l0pan
fuente
2

En resumen, he solucionado el problema poniendo el archivo de base de datos (* .db) en una subcarpeta.

  • La subcarpeta y el archivo de la base de datos deben ser miembros del grupo www-data.
  • En el grupo www-data, debe tener derecho a escribir en la subcarpeta y en el archivo de la base de datos.
Erkan Hürnalı
fuente
0

Obtuve esto en mi navegador cuando cambié de usar http: // localhost a http://145.900.50.20 (donde 145.900.50.20 es mi dirección IP local) y luego volví a cambiar a localhost: era necesario permanecer con el Dirección IP una vez que había cambiado a esa vez

kris
fuente
0

Solía:

echo exec ('whoami');

para averiguar quién está ejecutando el script (por ejemplo, nombre de usuario), y luego le dio al usuario permisos para todo el directorio de la aplicación, como:

sudo chown -R: nombre de usuario / var / www / html / myapp

Espero que esto ayude a alguien por ahí.

shasi kanth
fuente