Lỗi SQLite 'cố gắng ghi cơ sở dữ liệu chỉ đọc' trong khi chèn?


123

Tôi có một cơ sở dữ liệu SQLite mà tôi đang sử dụng cho một trang web. Vấn đề là khi tôi cố gắng INSERT INTO, tôi nhận được mộtPDOException

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

Tôi SSH vào máy chủ và kiểm tra quyền và cơ sở dữ liệu có quyền

-rw-rw-r--

Tôi không quen thuộc với quyền * nix, nhưng tôi khá chắc chắn điều này có nghĩa là

  • Không phải là một thư mục
  • Chủ sở hữu có quyền đọc / ghi (đó là tôi, theo ls -l)
  • Nhóm có quyền đọc / ghi
  • Mọi người khác chỉ có quyền đọc

Tôi cũng đã tìm mọi nơi tôi biết để sử dụng sqlite3chương trình, và thấy không có gì liên quan.

Vì tôi không biết PDO đang cố gắng mở cơ sở dữ liệu nào, nên tôi đã làm

chmod o+w supplies.db

Bây giờ, tôi nhận được một cái khác PDOException:

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

Nhưng nó CHỈ xảy ra khi tôi cố gắng thực hiện một INSERTtruy vấn sau khi cơ sở dữ liệu được mở.

Có ý kiến ​​nào về những việc đang ra không?


về cơ bản, httpd (apache> php> PDO) không phải là bạn, vì vậy nó không sở hữu tệp, vì vậy nó không có quyền ghi ... thú vị ...
SparK

sudo chgrp www-data test.dbvới việc thêm quyền làm việc cho tôi
Zippp

Câu trả lời:


305

Vấn đề, khi nó quay ra, là người lái xe PDO SQLite đòi hỏi rằng nếu bạn đang đi để làm một thao tác ghi ( INSERT, UPDATE, DELETE, DROP, vv), sau đó vào thư mục cơ sở dữ liệu cư trú trong phải có quyền ghi, cũng như thực tế tập tin cơ sở dữ liệu.

Tôi tìm thấy thông tin này trong một bình luận ở cuối trang hướng dẫn trình điều khiển SQLO PDO .


9
Ngoài ra, Selinux (nếu được cài đặt) không được thi hành. Mất một ngày rưỡi để tìm ra điều đó.
Steve V.

1
Xin lỗi, nhưng tôi cảm ơn vì điều đó, nhưng nó chỉ giải quyết được vấn đề tạm thời, vấn đề chính là người dùng dữ liệu www của tôi không thuộc nhóm dữ liệu www.
Dorian

5
Như tôi biết, thư mục chứa phải có thể ghi được vì khi viết tệp nhật ký sẽ được tạo và do đó chính db. Để có cùng người dùng với máy chủ web, hãy thử sao chép nội dung của tệp sang một quảng cáo được tạo khác.
lcapra

4
Ngoài ra, tệp db và thư mục chứa trong đó phải được sở hữu bởi 'dữ liệu www' trên các hộp linux.
đĩa mềm

1
Hiện tại sqlite3 có thể có 3 tệp, .dba, a .db-shmvà một .db-waltệp, và tất nhiên là thư mục mẹ của ba, tất cả đều có thể ghi cho người dùng đang chạy chương trình.
Marcos Dione

17

Điều này có thể xảy ra khi chủ sở hữu tệp SQLite không giống như người dùng đang chạy tập lệnh. Lỗi tương tự có thể xảy ra nếu toàn bộ đường dẫn thư mục (có nghĩa là mỗi thư mục trên đường đi) không thể được ghi vào.

Ai sở hữu tệp SQLite? Bạn?

Kịch bản đang chạy là ai? Apache hay không ai?


1
Tôi sở hữu tệp SQLite, nhưng tôi không biết tập lệnh chạy với ai. Làm thế nào tôi có thể tìm ra? (Hãy nhớ rằng, đây là trên một máy chủ được chia sẻ và tôi có quyền hạn chế)
Austin Hyde

1
Ah, điều đó làm cho mọi thứ vui hơn. Nếu bạn đang sử dụng dịch vụ lưu trữ được chia sẻ, rất có khả năng tập lệnh chạy dưới dạng "không ai" hoặc "apache". Có kịch bản của bạn tạo một tệp ( file_put_contents('./foo.txt', 'Hello, world');), nó sẽ cho bạn biết ai đang chạy. Có thể bạn sẽ cần có tập lệnh tạo cơ sở dữ liệu SQLite. Đây có thể là một bài tập giải trí nếu bạn đã có dữ liệu trong tệp hiện tại của mình ...
Charles

Ý tưởng tốt, nhưng không đi. Bất cứ ai PHP đang chạy như không có đặc quyền ghi, vì vậy nó không thể tạo tệp. Có cách nào PHP có thể lấy lại những gì người dùng hiện đang chạy không?
Austin Hyde

Cách duy nhất dường như là thông qua tiện ích mở rộng POSIX , được bật theo mặc định trên các hệ thống POSIX-y. Tuy nhiên, nhà cung cấp dịch vụ lưu trữ của bạn có thể có TFM và đã vô hiệu hóa nó.
Charles

Chà, họ đã TFM, được rồi. posix_getuid()cũng không hoạt động.
Austin Hyde

6

Đối với tôi, vấn đề là thực thi TỰ TIN chứ không phải là quyền. Lỗi "cơ sở dữ liệu chỉ đọc" đã biến mất sau khi tôi vô hiệu hóa thực thi, theo đề xuất của Steve V. trong một nhận xét về câu trả lời được chấp nhận.

echo 0 >/selinux/enforce

Khi chạy lệnh này, mọi thứ hoạt động như dự định (CentOS 6.3).

Vấn đề cụ thể tôi gặp phải là trong quá trình thiết lập Graphite. Tôi đã kiểm tra ba lần rằng người dùng apache sở hữu và có thể ghi vào cả graph.db và thư mục mẹ của nó. Nhưng cho đến khi tôi "sửa" SELinux, tất cả những gì tôi nhận được là một dấu vết ngăn xếp ảnh hưởng của: DatabaseError: cố gắng viết một cơ sở dữ liệu chỉ đọc


8
SELinux là một biện pháp bảo mật, vì vậy không nên vô hiệu hóa mà không có lý do chính đáng. Sẽ tốt hơn nếu tìm ra lý do tại sao SELinux chặn ngay từ đầu và định cấu hình chính xác thay vì vô hiệu hóa nó.
Jens Wegar

5

Điều này có thể được gây ra bởi SELinux. Nếu bạn không muốn tắt hoàn toàn SELinux, bạn cần đặt thư mục db fcontext thành 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

Tôi đã gặp lỗi này khi tôi cố ghi vào cơ sở dữ liệu trên hệ thống Android.

Rõ ràng sqlite3 không chỉ cần quyền ghi vào tệp cơ sở dữ liệu và thư mục chứa (như @ austin-hyde đã nói trong câu trả lời của anh ấy) mà cả biến môi trường TMPDIRphải trỏ đến một thư mục (có thể ghi được).

Trên hệ thống Android của tôi, tôi đã đặt nó TMPDIR="/data/local/tmp"và bây giờ tập lệnh của tôi chạy như mong đợi :)

Biên tập:

Nếu bạn không thể đặt các biến môi trường, bạn có thể sử dụng một trong các phương pháp khác được liệt kê tại đây: https://www.sqlite.org/tempfiles.html#t tạm_file_st Storage_locations nhưPRAGMA temp_store_directory = 'directory-name';


2

Tôi đã gặp lỗi tương tự từ IIS trong windows 7. Để khắc phục lỗi này, tôi đã phải thêm quyền kiểm soát hoàn toàn vào tài khoản IUSR cho tệp cơ sở dữ liệu sqlite. Bạn không cần thay đổi quyền nếu bạn sử dụng sqlite dưới webmatrix thay vì IIS.


2

Tóm lại, tôi đã khắc phục sự cố bằng cách đặt tệp cơ sở dữ liệu (* .db) vào thư mục con.

  • Thư mục con và tệp cơ sở dữ liệu trong đó phải là thành viên của nhóm dữ liệu www.
  • Trong nhóm dữ liệu www, bạn phải có quyền ghi vào thư mục con và tệp cơ sở dữ liệu.

0

Tôi đã nhận được điều này trong trình duyệt của mình khi tôi thay đổi từ sử dụng http: // localhost thành http://145.900.50.20 (trong đó 145.900.50.20 là địa chỉ IP cục bộ của tôi) và sau đó đổi lại thành localhost - cần phải ở lại với Địa chỉ IP một lần tôi đã thay đổi thành địa chỉ đó một lần


0

Tôi đã sử dụng:

echo exec ('whoami');

để tìm ra ai đang chạy tập lệnh (nói tên người dùng) và sau đó cấp quyền cho người dùng cho toàn bộ thư mục ứng dụng, như:

sudo chown -R: tên người dùng / var / www / html / myapp

Hy vọng điều này sẽ giúp ai đó ngoài kia.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.