2010-08-01 41 views
5

Tôi đang cố gắng chia chuỗi HTML bằng mã thông báo để tạo bản xem trước blog mà không hiển thị toàn bộ bài đăng. Đó là một chút khó hơn so với lần đầu tiên tôi nghĩ. Dưới đây là các vấn đề:Câu đố: Chia chuỗi HTML chính xác

  • Một người dùng sẽ tạo HTML thông qua trình soạn thảo WYSIWYG (CKEditor). Đánh dấu không được đảm bảo là khá hay nhất quán.
  • Mã thông báo, read_more(), có thể được đặt ở bất kỳ đâu trong chuỗi, bao gồm được lồng trong một thẻ đoạn .
  • Chuỗi phân tách đầu tiên kết quả cần phải là HTML hợp lệ cho tất cả sử dụng hợp lý mã thông báo.

Các ví dụ về khả năng sử dụng:

<p>Some text here. read_more()</p> 

<p>Some text read more() here.</p> 

<p>read_more()</p> 

<p> read_more()</p> 

read_more() 

Cho đến nay, tôi đã cố gắng chỉ tách chuỗi trên được dấu hiệu, nhưng nó để lại HTML không hợp lệ. Regex có lẽ là một lựa chọn khác. Bạn sẽ sử dụng chiến lược nào để giải quyết vấn đề này và làm cho nó có khả năng chống đạn càng tốt? Bất kỳ đoạn mã hoặc gợi ý nào cũng sẽ được đánh giá cao (tôi đang sử dụng PHP).

+7

Regex là ** không ** tùy chọn. Xem câu trả lời này cho một câu hỏi SO khác: http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags/1732454#1732454 – You

+0

Tại sao bạn không thể sử dụng trim() trên chuỗi kết quả, tìm phần tử mở hoặc đóng bị thiếu và nối nó một cách thích hợp, để làm cho nó hợp lệ HTML? –

+0

@You Nếu regex không phải là một tùy chọn, vui lòng đề xuất một tùy chọn khác có thể hoạt động cho HTML có khả năng không hợp lệ (X). Theo như tôi biết, PHP không có trình phân tích cú pháp XML không đưa ra lỗi về XML không hợp lệ và không được cấp phép GPL. – VirtuosiMedia

Trả lời

2
function stripmore($in) 
{ 
    list($p1,$p2) = explode("read_more()",$in,2); 

    $pass1 = preg_replace("~>[^<>]+<~","><",$p2); 
    $pass2 = preg_replace("~^[^<>]+~","",$pass1); 

    $pass3 = null; 
    while ($pass3 != $pass2) 
    { 
     if ($pass3 !== null) $pass2 = $pass3; 
     $pass3 = preg_replace("~<([^<>]+)></\\1>~","",$pass2); 
    } 

    return $p1."read_more()".$pass3; 
} 

này dải bất kỳ phi html sau dấu read_more(), và làm giảm nó ở mức tối thiểu bằng cách tách thẻ tương ứng, trong khi vẫn giữ bất kỳ thẻ bắt đầu trước và kết thúc sau dấu:

<p>Some text here. read_more()</p> 
     ==> <p>Some text here. read_more()</p> 

<p>Some <b>text</b> read_more() <b>here</b>.</p> 
     ==> <p>Some <b>text</b> read_more()</p> 

<p>Some <b>text read_more() here</b>.</p> 
     ==> <p>Some <b>text read_more()</b></p> 
+0

Tôi đang thử nghiệm điều này ngay bây giờ, mvd. – VirtuosiMedia

+0

Cảm ơn, mvd, điều này hoạt động tốt. Có ổn không nếu tôi sử dụng chức năng của bạn và nếu có, bạn muốn được ghi có trong mã như thế nào? – VirtuosiMedia

+0

sử dụng nó như bạn thấy phù hợp, và như cho các khoản tín dụng, ưu tiên không phải ở tất cả. btw bạn cần phải tách '~ [^ <>] + $ ~' (mọi thứ sau thẻ cuối) và có thể các thẻ như '~ ] *> ~' cũng vậy. – mvds

0

Tại sao không sử dụng hai textareas? Một ở trên và dưới cắt? Nên làm rõ với người dùng những gì đang xảy ra và loại bỏ cơn đau đầu cho bạn.

Nếu bạn làm muốn sử dụng mã thông báo, bạn nên chọn thứ gì đó khác biệt hơn một chút. Có thể: <!--full body cut--> mà bạn có thể chắc chắn hơn không thực sự là nội dung bị nhầm lẫn với mã thông báo.

Nhưng dù sao, nếu bạn muốn chia chuỗi trên được dấu hiệu, bạn chỉ cần tìm ra nơi thẻ bạn sử dụng strpos() và sau đó sử dụng substr() để cắt bỏ phần đầu tiên. Một cái gì đó như:

$intro = substr($text, 0, strpos($string, $token)); 

Sau đó, chạy bạn $intro qua tidy (PHP mở rộng) để clean up the syntax và sau đó lột crap thêm nó cho biết thêm trong đó. (Tôi nghĩ rằng bạn có thể str_replace() các tính năng bổ sung có một chuỗi trống.)

+0

Tidy, không may, dường như không phải là một lựa chọn hợp lệ vì nó có thể không được cài đặt hoặc được kích hoạt trên tất cả các máy chủ PHP.(Dự án này sẽ được phân phối). Tuy nhiên, tôi không chắc chắn về mức độ sẵn có của Tidy, vì vậy hãy sửa tôi nếu tôi sai. Hai textareas chắc chắn sẽ giải quyết vấn đề, nhưng tôi đang cố gắng giữ cho ánh sáng giao diện người dùng, nếu có thể, vì vậy tôi muốn khám phá các tùy chọn khác trước. – VirtuosiMedia

1

Tùy chọn đúng duy nhất tôi hiện đang xem là viết trình phân tích ngữ pháp HTML ngữ cảnh miễn phí của bạn bằng PHP cho phép bạn đóng các thẻ thích hợp (chỉ đơn giản bằng cách popping ngăn xếp khi đạt đến đọc thêm() và cho mỗi pop thêm một thẻ đóng).

Đây là, tuy nhiên, rất nhiều công việc và điều này có thể làm việc tốt cho bạn:

$stripped = strip_tags($input); 
list($preview) = explode("read more()", $stripped); 

Bạn mất đánh dấu HTML nhưng nó chết dễ dàng để thực hiện.Và không thể XSS trên trang chủ của bạn :)

+0

Mất đánh dấu HTML không phải là tùy chọn, nhưng cảm ơn đề xuất. – VirtuosiMedia

+0

+1 cho đoạn đầu tiên về viết một trình phân tích cú pháp - đó là những gì tôi đã làm cho blog của riêng mình. Nó cơ bản đi qua các văn bản từ đầu và giữ một chồng các thẻ HTML hiện đang mở, sau đó một khi nó xác định nơi để phá vỡ các văn bản, nó gắn thêm bất kỳ thẻ đóng là cần thiết. Của tôi phức tạp hơn một chút bởi vì tôi không có một mã thông báo rõ ràng để đánh dấu sự phân chia - và nó bằng Python - nhưng nếu bạn thích, tôi sẽ sẵn sàng chia sẻ mã. –

+0

ah, đừng bận tâm, tôi thấy bạn có thứ gì đó tốt hơn –

1

Thay vì sử dụng HTML đầy đủ, tại sao không sử dụng một trong nhiều ngôn ngữ đánh dấu có thể tạo HTML, nhưng không yêu cầu bạn đóng thẻ, v.v. dễ đào tạo người dùng của bạn hơn và tránh tất cả các khả năng tấn công XSS chấp nhận HTML thô cho phép.

PHP Markdown có vẻ phù hợp, đặc biệt là với mong muốn của bạn để tránh GNU GPL.

+0

Nó dành cho phần quản trị của CMS, vì vậy tôi muốn có ít nhất một đường cong học tập nhất có thể. Tôi đã chọn CKEditor vì nó có nhiều tính năng phong phú hơn các trình soạn thảo markdown và nó cho phép người dùng không kỹ thuật gần gũi hơn với Word. Tôi lọc đầu vào. Nhờ đề nghị mặc dù. – VirtuosiMedia

+0

Vì vậy ... với sự sẵn có của WordPress, Drupal, Joomla, và một số điểm của các hệ thống CMS nguồn mở khác, tại sao bạn lại viết một hệ thống khác? Chỉ tò mò thôi. –

1

Để trả lời nhận xét cho nhận xét của tôi, tôi quyết định trả lời nhận xét, vì vậy tôi có thể tận dụng các tùy chọn đánh dấu.

Tại sao bạn không thể sử dụng trim() trên chuỗi kết quả, tìm phần tử mở hoặc đóng còn thiếu và nối thêm một cách thích hợp, để làm cho HTML hợp lệ?

Chỉ cần di chuyển về phía trước và quay lại để tìm phần tử mở/đóng tiếp theo và sửa HTML của bạn.

Vì vậy, bạn có thể chỉ cần đi tiếp và quay lại chuỗi để có được <> tiếp theo và nếu đó là phần tử HTML thì dừng ở đó, nếu không tiếp tục.

Lý tưởng nhất là bạn cần phải xử lý yêu cầu này một lần cho mỗi lần gửi, vì vậy bạn tiếp tục thanh toán giá để thực hiện thao tác này.

UPDATE:

tôi quên bao gồm một liên kết để giúp đỡ với strpos:

http://tuxradar.com/practicalphp/4/7/5

1

PHP gọn gàng là một trọng lượng rất nhẹ và tiện ích hiệu quả để sửa chữa thẻ không hợp lệ. Có một cái nhìn, tôi đã sử dụng nó và điểm chuẩn nó trong ứng dụng của tôi, và nó hoạt động tuyệt vời. Moreoever nó có nhiều tùy chọn cấu hình cho phù hợp với nhu cầu của bạn là tốt nhất, và chăm sóc của các vấn đề khác có thể giống như mã hóa, thẻ không hợp lệ lồng, vv

xem tham khảo: http://www.php.net/manual/en/tidy.cleanrepair.php

ví dụ sử dụng:

<?php 

    function tidyString($str) 
    { 
     $config = array('show-body-only' => true); /* else it adds HTML tags too */ 
     tidy_set_encoding('utf8'); 
     $outStr = tidy_repair_string($str,$config); 
     return $outStr; 
    } 


    $inStr = "<span> this is my incorrect html</spa"; 
    echo tidyString($inStr); // Output : <span>this is my incorrect html</span> 

    ?>