ฉันต้องการ จำกัด การค้นหาเฉพาะอักขระที่ใช้กับภาษาอังกฤษ + ตัวเลข เหตุผลก็คือการดูข้อความค้นหาที่ช้าที่สุดในบันทึก mysql ที่ฉันพบว่าส่วนใหญ่มาจากการค้นหาในตัวอักษรอาหรับรัสเซียและจีนดังนั้นฉันจึงต้องการข้ามมันและแสดงข้อความแสดงข้อผิดพลาดแทน
ฉันต้องการ จำกัด การค้นหาเฉพาะอักขระที่ใช้กับภาษาอังกฤษ + ตัวเลข เหตุผลก็คือการดูข้อความค้นหาที่ช้าที่สุดในบันทึก mysql ที่ฉันพบว่าส่วนใหญ่มาจากการค้นหาในตัวอักษรอาหรับรัสเซียและจีนดังนั้นฉันจึงต้องการข้ามมันและแสดงข้อความแสดงข้อผิดพลาดแทน
คำตอบ:
โซลูชันนี้กรองสตริงการค้นหาโดยใช้นิพจน์ทั่วไปซึ่งจับคู่อักขระจากสคริปต์ Common และ Latin Unicode เท่านั้น
ฉันเพิ่งได้ใจของฉันปลิวไปที่กองมากเกิน ตามที่ปรากฎนิพจน์ทั่วไปจะมีกลไกเพื่อจับคู่หมวดหมู่ Unicode ทั้งหมดรวมถึงค่าเพื่อระบุ"สคริปต์" Unicodeทั้งหมดซึ่งแต่ละตัวสอดคล้องกับกลุ่มของอักขระที่ใช้ในระบบการเขียนที่แตกต่างกัน
สิ่งนี้ทำได้โดยใช้\p
เมตาอักขระตามด้วยตัวระบุหมวดหมู่ Unicode ในเครื่องหมายปีกกา - [\p{Common}\p{Latin}]
จับคู่อักขระเดี่ยวในสคริปต์ละตินหรือสคริปต์ทั่วไป - ซึ่งรวมถึงเครื่องหมายวรรคตอนตัวเลขและสัญลักษณ์อื่น ๆ
ในฐานะที่เป็นชี้ @ Paul 'นกกระจอกเหยี่ยว' Biron ออกที่u
ธงปรับปรุงรูปแบบควรจะตั้งในตอนท้ายของการแสดงออกปกติในการสั่งซื้อสำหรับ PHP ของฟังก์ชั่น PCRE ในการรักษาสตริงเรื่องเป็นUTF-8
Unicode เข้ารหัส
มารวมกันแล้วลวดลาย
/^[\p{Latin}\p{Common}]+$/u
จะจับคู่สตริงทั้งหมดที่ประกอบด้วยอักขระหนึ่งตัวหรือมากกว่าในสคริปต์ Latin และ Common Unicode
สถานที่ที่ดีในการดักจับสตริงการค้นหาคือการpre_get_posts
กระทำที่มันจะดำเนินการทันทีก่อนที่ WordPress จะดำเนินการค้นหา ด้วยการดูแลมากขึ้นนี้ยังสามารถทำได้โดยใช้กรองrequest
function wpse261038_validate_search_characters( $query ) {
// Leave admin, non-main query, and non-search queries alone
if( is_admin() || !$query->is_main_query() || !$query->is_seach() )
return;
// Check if the search string contains only Latin/Common Unicode characters
$match_result = preg_match( '/^[\p{Latin}\p{Common}]+$/u', $query->get( 's' ) );
// If the search string only contains Latin/Common characters, let it continue
if( 1 === $match_result )
return;
// If execution reaches this point, the search string contains non-Latin characters
//TODO: Handle non-Latin search strings
//TODO: Set up logic to display error message
}
add_action( 'pre_get_posts', 'wpse261038_validate_search_characters' );
เมื่อได้รับการพิจารณาแล้วว่าสตริงการค้นหามีอักขระที่ไม่ใช่ละตินคุณสามารถใช้WP_Query::set()
เพื่อปรับเปลี่ยนแบบสอบถามโดยการเปลี่ยนชื่อแบบสอบถามเป็น vars - ดังนั้นจึงมีผลต่อแบบสอบถาม SQL WordPress ประกอบและประมวลผล
ตัวแปรข้อความค้นหาที่เกี่ยวข้องมากที่สุดน่าจะเป็นดังนี้:
s
เป็นตัวแปรแบบสอบถามที่สอดคล้องกับสตริงการค้นหา การตั้งค่าให้null
เป็นหรือสตริงว่างเปล่า ( ''
) จะส่งผลให้ WordPress ไม่ต้องรักษาข้อความค้นหาอีกต่อไป - บ่อยครั้งที่ผลลัพธ์นี้ในเทมเพลตเก็บถาวรที่แสดงโพสต์ทั้งหมดหรือหน้าแรกของเว็บไซต์ขึ้นอยู่กับค่าของอีก vars แบบสอบถาม อย่างไรก็ตามการตั้งค่าเป็นช่องว่างเดียว ( ' '
) จะส่งผลให้ WordPress รับรู้เป็นการค้นหาและพยายามแสดงsearch.php
แม่แบบpage_id
สามารถใช้เพื่อนำผู้ใช้ไปยังหน้าที่เฉพาะเจาะจงที่คุณเลือกpost__in
สามารถ จำกัด คิวรีให้เลือกเฉพาะโพสต์ ด้วยการตั้งค่าให้เป็นอาร์เรย์ที่มี ID การโพสต์ที่เป็นไปไม่ได้มันสามารถทำหน้าที่เป็นตัวชี้วัดเพื่อให้แน่ใจว่าแบบสอบถามไม่ส่งคืนอะไรเลยในใจคุณอาจทำต่อไปนี้เพื่อตอบสนองต่อการค้นหาที่ไม่ดีโดยการโหลดsearch.php
แม่แบบที่ไม่มีผลลัพธ์:
function wpse261038_validate_search_characters( $query ) {
// Leave admin, non-main query, and non-search queries alone
if( is_admin() || !$query->is_main_query() || !$query->is_seach() )
return;
// Check if the search string contains only Latin/Common Unicode characters
$match_result = preg_match( '/^[\p{Latin}\p{Common}]+$/u', $query->get( 's' ) );
// If the search string only contains Latin/Common characters, let it continue
if( 1 === $match_result )
return;
$query->set( 's', ' ' ); // Replace the non-latin search with an empty one
$query->set( 'post__in', array(0) ); // Make sure no post is ever returned
//TODO: Set up logic to display error message
}
add_action( 'pre_get_posts', 'wpse261038_validate_search_characters' );
วิธีที่คุณแสดงข้อความข้อผิดพลาดจริง ๆ นั้นขึ้นอยู่กับแอปพลิเคชันของคุณและความสามารถของธีมของคุณ - มีหลายวิธีที่สามารถทำได้ หากธีมของคุณเรียกใช้get_search_form()
ในเทมเพลตการค้นหาโซลูชันที่ง่ายที่สุดน่าจะใช้pre_get_search_form
action hook เพื่อแสดงข้อผิดพลาดของคุณเหนือแบบฟอร์มการค้นหา:
function wpse261038_validate_search_characters( $query ) {
// Leave admin, non-main query, and non-search queries alone
if( is_admin() || !$query->is_main_query() || !$query->is_seach() )
return;
// Check if the search string contains only Latin/Common Unicode characters
$match_result = preg_match( '/^[\p{Latin}\p{Common}]+$/u', $query->get( 's' ) );
// If the search string only contains Latin/Common characters, let it continue
if( 1 === $match_result )
return;
$query->set( 's', ' ' ); // Replace the non-latin search with an empty one
$query->set( 'post__in', array(0) ); // Make sure no post is ever returned
add_action( 'pre_get_search_form', 'wpse261038_display_search_error' );
}
add_action( 'pre_get_posts', 'wpse261038_validate_search_characters' );
function wpse261038_display_search_error() {
echo '<div class="notice notice-error"><p>Your search could not be completed as it contains characters from non-Latin alphabets.<p></div>';
}
ความเป็นไปได้อื่น ๆ สำหรับการแสดงข้อผิดพลาดรวมถึง:
wp_enqueue_script
hook ที่มี$priority
ขนาดใหญ่กว่าที่ใช้จาวาสคริปต์นั้นและใช้wp_localize_script()
เพื่อตั้งค่าตัวแปรให้รวมข้อความแสดงข้อผิดพลาดของคุณwp_redirect()
เพื่อส่งผู้ใช้ไปยัง URL ที่คุณเลือก (วิธีนี้ต้องการการโหลดหน้าเว็บเพิ่มเติม)s
ตัวแปรคิวรีเป็น''
แทนที่' '
และใช้page_id
แทนpost__in
เพื่อส่งคืนเพจที่คุณเลือกloop_start
เบ็ดเพื่อฉีดWP_Post
วัตถุปลอมที่มีข้อผิดพลาดของคุณลงในผลลัพธ์การค้นหา - นี่เป็นแฮ็คที่น่าเกลียดที่สุดและอาจดูไม่เหมาะสมกับธีมของคุณ แต่มีผลข้างเคียงที่อาจเกิดขึ้นจากการปราบปรามข้อความtemplate_include
hook ตัวกรองเพื่อแลกเปลี่ยนเทมเพลตการค้นหากับแบบกำหนดเองในชุดรูปแบบหรือปลั๊กอินที่แสดงข้อผิดพลาดของคุณหากไม่มีการตรวจสอบชุดรูปแบบที่เป็นปัญหามันเป็นการยากที่จะกำหนดเส้นทางที่คุณควรใช้
คุณจะทำเช่นนี้โดยใส่ฟังก์ชันการตรวจสอบใน PHP เพื่อทดสอบอินพุตกับนิพจน์ทั่วไปเช่น ^[a-zA-Z0-9,.!?' ]*
ดังนั้นจะมีลักษณะเช่นนี้:
if ( preg_match( "^[a-zA-Z0-9,.!?'" ]*", {search variable} ) ) {
// Success
} else {
// Fail
}
RexEx ฉันใช้สำหรับทุกตัวอักษรA-Z
, a-z
, 0-9
เช่นเดียวกับ,
, .
, !
, ?
, '
, "
และ(เว้นวรรค)
วิธีการแก้ปัญหาด้านล่างของฉันคือแฮ็คที่ใช้ฟังก์ชันmbstringของ PHP ในทางที่ผิดเพื่อพยายามทำนายตัวอักษรอย่างน่าอัศจรรย์โดยดูจากการจัดเรียงของไบต์ที่เขียนสตริง นี่เป็นความคิดที่ไม่ดีจริงๆและมีแนวโน้มที่จะเกิดข้อผิดพลาดสูง
โปรดดูคำตอบอื่น ๆของฉันสำหรับวิธีแก้ปัญหาที่ง่ายกว่าและเชื่อถือได้มากกว่า
วิธีหนึ่งในการป้องกันการค้นหาโดยใช้ตัวอักษรที่ไม่ใช่ละตินคือการใช้ฟังก์ชั่นของ PHPmb_detect_encoding()
เพื่อดูว่าสตริงการค้นหาสอดคล้องกับการเข้ารหัสอักขระที่เลือกอย่างใดอย่างหนึ่งหรือไม่ สถานที่ที่ดีในการทำเช่นนี้คือการpre_get_posts
กระทำเนื่องจากเป็นไฟก่อนที่จะดำเนินการแบบสอบถาม
สิ่งที่คุณทำจริงหลังจากที่คุณพิจารณาแล้วว่าการค้นหากำลังใช้การเข้ารหัสที่ไม่ถูกต้องเป็นแอปพลิเคชันที่เฉพาะเจาะจงจริงๆ ที่นี่ฉันได้ตั้งค่าการค้นหาเป็นพื้นที่เดียวเพื่อให้แน่ใจว่า WordPress ยังตีความการค้นหาเป็นการค้นหาและยังคงโหลดsearch.php
เทมเพลต (และไม่ได้นำผู้ใช้ไปยังหน้าแรกเหมือนที่เกิดขึ้นเมื่อสตริงการค้นหาเป็น สตริงว่างเปล่า) ฉันยังใช้ความระมัดระวังเพิ่มขึ้นของการตั้งค่า'post__in'
ไปยังอาร์เรย์ที่มีความเป็นไปไม่ได้โพสต์รหัสในการสั่งซื้อเพื่อให้แน่ใจว่าไม่มีอะไรแน่นอนจะถูกส่งกลับ
อีกทางหนึ่งคุณอาจลองตั้งค่าสตริงการค้นหาnull
และการตั้งค่าpage_id
เพื่อนำผู้ใช้ไปยังหน้าด้วยข้อความแสดงข้อผิดพลาดที่กำหนดเองของคุณ
function wpse261038_validate_search_query_encoding( $query ) {
$valid_encodings = array( 'Windows-1252' );
// Ignore admin, non-main query, and non-search queries
if( is_admin() || !$query->is_main_query() || !$query->is_seach() )
return;
// Retrieve the encoding of the search string (if it's one listed in $valid_encodings)
$search_encoding = mb_detect_encoding( $query->get( 's' ), $valid_encodings, true );
// If the search encoding is one in $valid_encodings, leave the query as-is
if( in_array( $search_encoding, $valid_encodings ) )
return;
// If it wasn't, sabotage the search query
$query->set( 's', ' ' );
$query->set( 'post__in', array(0) );
// Set up your error message logic here somehow, perhaps one of the following:
// - Add a template_include filter to load a custom error template
// - Add a wp_enqueue_scripts hook with a greater priority than your theme/plugin's, and
// use wp_localize_script() in the hook to pass an error message for your JavaScript
// to display
// - Perform a wp_redirect() to send the user to the URL of your choice
// - Set a variable with an error message which your theme or plugin can display
}
add_action( 'pre_get_posts', 'wpse261038_validate_search_query_encoding' );
ผมเขียนทดสอบความคุ้มครองการเปรียบเทียบสตริงหุ่นบางอย่างในตัวอักษรที่แตกต่างกันกับทั้งหมดของการเข้ารหัสเริ่มต้นการสนับสนุนโดย PHP มันไม่ได้สมบูรณ์แบบด้วยการยืด (ฉันไม่รู้ว่าจริง ๆ แล้วว่าสตริงของฉันมีจริงและดูเหมือนจะสำลักในการตรวจจับภาษาญี่ปุ่น) แต่มันค่อนข้างมีประโยชน์สำหรับการพิจารณาผู้สมัคร คุณสามารถดูได้ในการดำเนินการที่นี่
หลังจากทำการค้นคว้าการเข้ารหัสตัวอักษรที่มีศักยภาพที่ตั้งค่าสถานะโดยการทดสอบนั้นดูเหมือนว่าWindows-1252
จะเป็นตัวเลือกที่สมบูรณ์แบบสำหรับความต้องการของคุณครอบคลุมตัวอักษรละตินเช่นเดียวกับสำเนียงภาษาละตินทั่วไป
การเลือกISO-8859
ชุดอักขระควรเป็นอีกทางเลือกหนึ่งที่ทำงานได้ แต่ด้วยเหตุผลที่ฉันไม่สามารถคาดศีรษะได้mb_
ฟังก์ชั่นดูเหมือนจะไม่แยกความแตกต่างระหว่างISO-8859
ชุดอักขระที่แตกต่างกันแม้ว่าจะระบุว่าเป็นการเข้ารหัสแยกต่างหาก
ที่จะช่วยให้ตัวละครบางอย่างร่วมกันอื่น ๆ HTML-ENTITIES
ที่คุณอาจพิจารณาเพิ่ม
ISO-8859
เข้ารหัสได้
ขณะที่ฉันพยายามอธิบาย @MichaelRogers เมื่อเขาโพสต์คำถามที่คล้ายกันเมื่อหลายวันก่อนการรู้ชุดอักขระ (หรือสคริปต์) ที่ใช้ในสตริงนั้นไม่เพียงพอที่จะตรวจจับภาษาของสตริงนั้น
ดังนั้นในขณะที่วิธีการที่มีรายละเอียดโดย @bosco จะลบสตริงภาษารัสเซียและอื่น ๆ (ด้วยการแก้ไข 2 รายการด้านล่าง) แต่จะไม่จำกัด การค้นหาของคุณเป็นภาษาอังกฤษ
หากต้องการดูสิ่งนี้ลอง:
$strings = array (
'I\'m sorry', // English
'Je suis désolé', // French
'Es tut mir Leid', // German
'Lorem ipsum dolor sit amet', // Lorem ipsum
'أنا سعيد', // Arabic
'я счастлив', // Russian
'我很高兴', // Chinese (Simplified)
'我很高興', // Chinese (Traditional)
) ;
foreach ($strings as $s) {
if (preg_match ('/^[\p{Latin}\p{Common}]+$/u', $s) === 1) {
echo "$s: matches latin+common\n" ;
}
else {
echo "$s: does not match latin+common\n" ;
}
}
[ หมายเหตุ:การแก้ไข 2 รายการที่กล่าวถึงข้างต้นเกี่ยวกับสิ่งที่ @bosco มีให้:
/u
ฟายเออร์ (จำเป็นสำหรับการรักษารูปแบบและหัวเรื่องตามที่เข้ารหัส UTF-8, ดูPHP: Regex Pattern Modifiers ]ซึ่งจะผลิต:
I'm sorry: matches latin+common
Je suis désolé: matches latin+common
Es tut mir Leid: matches latin+common
Lorem ipsum dolor sit amet: matches latin+common
أنا سعيد: does not match latin+common
я счастлив: does not match latin+common
我很高兴: does not match latin+common
我很高興: does not match latin+common
[ หมายเหตุ:ฉันพูดภาษาอังกฤษฝรั่งเศสและเยอรมัน (และLorem ipsum :-) นิดหน่อยแต่พึ่งใช้ Google แปลภาษาเป็นภาษาอาหรับรัสเซียและจีน]
อย่างที่คุณเห็นการพึ่งพาการตรวจสอบสคริปต์ละตินจะไม่ทำให้แน่ใจว่าคุณมีภาษาอังกฤษ
มีจำนวนเธรดใน StackOverflow (เช่นตรวจจับภาษาจากสตริงใน PHP ) ที่ให้ข้อมูลเพิ่มเติมเกี่ยวกับหัวเรื่อง