2011-08-08 27 views
7

Trước khi đi qua một chuỗi để eval() Tôi muốn chắc chắn rằng cú pháp là đúng và cho phép:Validate sử dụng đầu vào mã PHP trước khi đi qua nó để eval()

  1. Hai chức năng: a() và b()
  2. Bốn nhà khai thác:/* - +
  3. Chân đế:()
  4. số: 1,2, -1, 1

làm thế nào tôi có thể làm được điều này, có lẽ nó có cái gì để làm với PHP Tokenizer?

Tôi thực sự đang cố tạo một trình thông dịch công thức đơn giản để a() và b() sẽ được thay thế bằng ln() và exp(). Tôi không muốn viết một tokenizer và phân tích cú pháp từ đầu.

+0

Bạn có quan tâm đến thứ tự của những yếu tố đầu vào đó không? – hoppa

+0

Một ví dụ về hàm bạn sẽ cho phép và một hàm không nên vượt qua sẽ được thêm vào câu hỏi của bạn. Lưu ý việc sử dụng eval không nên được xem nhẹ. –

+2

Đó là lý do tại sao anh ấy muốn khử trùng trước tôi nghi ngờ;) – hoppa

Trả lời

2

phát Parser đã thực sự đã được viết cho PHP, và "LIME" đặc biệt đi kèm với các điển hình "máy tính" Ví dụ, đó sẽ là một điểm khởi đầu rõ ràng cho "ngôn ngữ nhỏ" của bạn: http://sourceforge.net/projects/lime-php/

Đã nhiều năm kể từ lần cuối tôi chơi với LIME, nhưng nó đã trưởng thành sau & ổn định rồi.

Ghi chú:

1) Sử dụng một đầy đủ về máy phát điện phân tích cú pháp mang đến cho bạn những lợi thế của việc tránh PHP eval() hoàn toàn nếu bạn muốn - bạn có thể làm cho LIME phát ra một phân tích cú pháp mà hiệu quả cung cấp một "eval" chức năng cho các biểu thức được viết bằng ngôn ngữ nhỏ của bạn (với xác thực được nạp vào). Điều này mang lại cho bạn lợi thế bổ sung cho phép bạn thêm hỗ trợ cho các chức năng mới, nếu cần. Đầu tiên, có vẻ như quá mức cần thiết để sử dụng trình tạo trình phân tích cú pháp cho tác vụ nhỏ như vậy, nhưng một khi bạn nhận được các ví dụ, bạn sẽ bị ấn tượng bởi việc sửa đổi và mở rộng chúng dễ dàng như thế nào. Và rất dễ dàng để đánh giá thấp sự khó khăn khi viết một trình phân tích cú pháp không có lỗi (thậm chí là một trình phân tích cú pháp không có lỗi) từ đầu.

+0

@stereofrog - Xin lỗi, tôi đã đọc sai lịch sử thay đổi. Liên kết ít nhất cũng nên hoạt động, mặc dù tôi biết rằng liên kết này không khớp với định dạng ưa thích (vì một số lý do liên kết được gắn kết không được hiển thị đúng cho tôi trong Chrome). – Peter

0

có, bạn cần Bộ mã thông báo hoặc nội dung tương tự nhưng chỉ là một phần của câu chuyện. Một tokenizer (thường được gọi là "lexer") chỉ có thể đọc và phân tích các phần tử của một biểu thức, nhưng không có phương tiện để phát hiện rằng một cái gì đó như "foo() + * bar)" là không hợp lệ. Bạn cần phần thứ hai, được gọi là parser để có thể sắp xếp mã thông báo bằng một loại cây (được gọi là "AST") hoặc cung cấp thông báo lỗi khi không làm như vậy. Trớ trêu thay, một khi bạn đã có một cây, "eval" là không cần thiết nữa, bạn có thể đánh giá biểu thức của bạn trực tiếp từ cây.

Tôi khuyên bạn nên viết một trình phân tích cú pháp bằng tay vì đây là một bài tập rất hữu ích và rất nhiều niềm vui. Recursive descent parsers khá dễ dàng để lập trình.

+0

Tôi đồng ý rằng việc viết một trình phân tích cú pháp bằng tay rất thú vị và là một phần của đào tạo cơ bản cho bất kỳ lập trình viên nghiêm túc nào. Nhưng nếu bạn đang làm việc "trên đồng hồ", IMO sẽ sử dụng lại trình tạo trình phân tích cú pháp trước khi thoát ra và dành một chút thời gian để lưu trữ các định nghĩa ngữ pháp. – Peter

+0

Tôi thấy quan điểm của bạn, nhưng tôi không đồng ý trong trường hợp của các trình phân tích cú pháp nói riêng. Đầu tiên, ngay cả khi bạn quan tâm đến việc tìm hiểu cách thức hoạt động của công cụ, bạn có thể tạo ra một số lỗi chuẩn dọc theo con đường để xây dựng một trình phân tích cú pháp đủ mạnh để xác định liệu một chuỗi đã cho từ Big Bad Web có thể được chuyển tới PHP hay không eval() - và mặc dù chúng tôi không thích sự thiếu hiểu biết, chúng tôi cũng không thích các ứng dụng web dễ bị tấn công. Thứ hai, tôi không nghĩ rằng nó có thể sử dụng một trình tạo trình phân tích cú pháp (thậm chí bề ngoài) mà không cần học một cái gì đó mới và hữu ích, ngay cả khi cuối cùng bạn quyết định một cách tiếp cận khác. – Peter

3

Theo như xác nhận là có liên quan, các thẻ nhân vật sau đây là hợp lệ:

operator: [/*+-] 
funcs: (a\(|b\() 
brackets: [()] 
numbers: \d+(\.\d+)? 
space: [ ] 

Một xác nhận đơn giản sau đó có thể kiểm tra nếu chuỗi đầu vào phù hợp với bất kỳ sự kết hợp của các mô hình. Bởi vì funcs mã thông báo là khá chính xác và nó không mâu thuẫn nhiều với thẻ khác, xác nhận này nên được khá ổn định w/o cần thực hiện bất kỳ cú pháp/ngữ pháp đã:

Chỉ
$tokens = array(
    'operator' => '[/*+-]', 
    'funcs' => '(a\(|b\()', 
    'brackets' => '[()]', 
    'numbers' => '\d+(\.\d+)?', 
    'space' => '[ ]', 
); 

$pattern = ''; 
foreach($tokens as $token) 
{ 
    $pattern .= sprintf('|(?:%s)', $token); 
} 
$pattern = sprintf('~^(%s)*$~', ltrim($pattern, '|')); 

echo $pattern; 

nếu chuỗi đầu vào toàn bộ trận đấu chống lại mẫu dựa trên mã thông báo, nó xác nhận.Nó vẫn có thể là cú pháp sai PHP, đặt bạn có thể đảm bảo nó chỉ là xây dựng dựa trên các thẻ quy định:

~^((?:[/*+-])|(?:(a\(|b\())|(?:[()])|(?:\d+(\.\d+)?)|(?:[ ]))*$~ 

Nếu bạn xây dựng mô hình tự động - như trong ví dụ - bạn có thể sửa đổi tokens ngôn ngữ của bạn sau này dễ dàng hơn.

Ngoài ra, đây có thể là bước đầu tiên để trình mã hóa/lexer của riêng bạn. Sau đó, luồng mã thông báo có thể được chuyển cho trình phân tích cú pháp có thể xác thực và giải thích nó. Đó là phần user187291 wrote about.

Cách khác để viết lexer + parser và bạn cần xác thực cú pháp, bạn có thể xây dựng ngữ pháp dựa trên mã thông báo và sau đó thực hiện ngữ pháp mã thông báo dựa trên mã thông báo của đầu vào.

Mã thông báo là những từ bạn sử dụng trong ngữ pháp của mình. Bạn sẽ cần phải mô tả dấu ngoặc đơn và định nghĩa hàm chính xác hơn sau đó trong mã thông báo và trình mã thông báo phải tuân thủ các quy tắc rõ ràng hơn mà mã thông báo thay thế một mã thông báo khác. Khái niệm này được nêu trong another question of mine. Nó sử dụng regex cũng như để xây dựng ngữ pháp và xác nhận cú pháp, nhưng nó vẫn không phân tích cú pháp. Trong trường hợp của bạn, eval sẽ là trình phân tích cú pháp bạn đang sử dụng.

+0

[Mô phỏng cấu trúc ngôn ngữ mảng php hoặc phân tích bằng regexp?] (Http://stackoverflow.com/questions/3267951/simulate-php-array-language-construct-or-parse-with-regexp/3268443#3268443) – hakre

0

Bạn có thể sử dụng token_get_all(), kiểm tra từng mã thông báo và hủy tại mã thông báo không hợp lệ đầu tiên.

0

Câu trả lời của hakre, sử dụng regexes là một giải pháp tốt, nhưng hơi phức tạp một chút. Ngoài ra, việc xử lý danh sách trắng các chức năng trở nên khá lộn xộn. Và nếu điều này không đúng, nó có thể có tác động rất khó chịu trên hệ thống của bạn.

Có lý do nào mà bạn không sử dụng javascript 'eval' thay thế không?

+0

I cần lấy một số dữ liệu từ cơ sở dữ liệu vào công thức, vì vậy tôi không thể sử dụng JS. – hidarikani

Các vấn đề liên quan