Aramayı latin karakterleriyle sınırla


9

Aramayı İngilizce + sayılarla kullanılan karakterlerle sınırlamak istiyorum. Bunun nedeni en çok bulduğum mysql günlüğündeki en yavaş sorgulara Arap, Rusça ve Çince karakterlerde yapılan aramalardan geliyor, bu yüzden onları atlamak ve bunun yerine bir hata mesajı görüntülemek istiyorum.


Hatanızı nasıl görüntülemek istediğinizi
bosco

Hatanın arama sayfasında, arama formunun altında veya üstünde görünmesini istiyorum.
Michael Rogers

Yanıtlar:


10

Bu çözüm, yalnızca Common ve Latin Unicode komut dosyalarındaki karakterlerle eşleşen normal bir ifade uygulayarak arama dizelerini filtreler.


Latin Karakterlerini Normal İfadelerle Eşleştirme

Sadece aklım yığın taşması de üzerinde şişirilmiş vardı . Görüldüğü gibi, normal ifadeler , her biri farklı yazma sistemlerinde kullanılan karakter gruplarına karşılık gelen tüm Unicode "komut dosyalarını" belirten değerler de dahil olmak üzere tüm Unicode kategorilerini eşleştirmek için bir mekanizmaya sahiptir .

Bu, \pmeta karakter ve ardından kıvırcık ayraçlarda bir Unicode kategori tanımlayıcısı kullanılarak yapılır - bu nedenle Latin veya Ortak komut dosyalarındaki[\p{Common}\p{Latin}] tek bir karakterle eşleşir - buna noktalama işaretleri, sayılar ve çeşitli simgeler dahildir.

As @ Paul 'Sparrow Hawk' Biron işaret , u desen değiştirici bayrak olarak konu dizesini tedavisinde PHP'nin PCRE işlevleri için sırayla normal ifadenin sonunda ayarlanmalıdır UTF-8Unicode kodlanmış.

Hep birlikte o zaman, desen

/^[\p{Latin}\p{Common}]+$/u

Latin ve Ortak Unicode komut dosyalarında bir veya daha fazla karakterden oluşan bir dizenin tamamı ile eşleşir.


Arama Dizesini Filtreleme

Bir arama dizesini yakalamak için iyi bir yer, WordPress sorguyu yürütmeden hemen önce gerçekleşen pre_get_postseylemdir . Daha fazla dikkatle , bu bir requestfiltre kullanılarak da gerçekleştirilebilir .

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' );

İzin Verilmeyen Aramalara Yanıt Verme

Bir arama dizesinin Latin olmayan karakterler içerdiği belirlendikten sonra WP_Query::set(), sorguyu değiştirmek için adlandırılmış sorgu değişkenlerini değiştirerek kullanabilirsiniz - böylece WordPress'in daha sonra oluşturduğu ve yürüttüğü SQL sorgusunu etkiler.

En alakalı sorgu değişkenleri muhtemelen aşağıdaki gibidir:

  • sbir arama dizesine karşılık gelen sorgu değişkenidir. Bunu nullveya boş bir dizeyi ( '') ayarlamak , WordPress'in sorguyu artık bir arama olarak ele almamasına neden olur - çoğu zaman bu, diğerlerinin değerlerine bağlı olarak tüm yayınları veya sitenin ön sayfasını görüntüleyen bir arşiv şablonuyla sonuçlanır. sorgu değişkenleri. ' 'Ancak, onu tek bir boşluğa ( ) ayarlamak, WordPress'in bir arama olarak tanınmasına ve böylece search.phpşablonu görüntülemeye çalışmasına neden olur .
  • page_id kullanıcıyı seçtiğiniz belirli bir sayfaya yönlendirmek için kullanılabilir.
  • post__insorguyu belirli bir yayın seçimiyle kısıtlayabilir. İmkansız bir yazı kimliği olan bir diziye ayarlandığında , sorgunun kesinlikle hiçbir şey döndürmediğinden emin olmak için bir ölçü işlevi görebilir .

Yukarıdakileri göz önünde bulundurarak, search.phpşablonu sonuçsuz olarak yükleyerek kötü bir aramaya yanıt vermek için aşağıdakileri yapabilirsiniz :

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' );

Hata Görüntüleme

Hata mesajını gerçekte görüntüleme şekliniz, uygulamanıza ve temanızın yeteneklerine bağlıdır - bunun yapılabileceği birçok yol vardır. Temanız get_search_form()arama şablonunu çağırıyorsa , en kolay çözüm muhtemelen hatanızı arama formunun hemen üstünde çıkarmak için bir pre_get_search_formişlem kancası kullanmaktır :

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>';
}

Hata mesajı görüntülemek için diğer bazı olasılıklar:

  • Siteniz "flash" veya "modal" iletileri görüntüleyebilecek JavaScript kullanıyorsa (veya kendi başınıza bu yetenekleri ekliyorsanız), belirli bir değişken ayarlandığında sayfa yükleme sırasında iletileri görüntülemek için mantığı ekleyin, ardından bir wp_enqueue_scriptkanca ekleyin bir ile $prioritybüyük daha hangi enqueues JavaScript ve kullanımı o wp_localize_script()senin hata mesajını da bu değişkeni ayarlamak için.
  • wp_redirect()Kullanıcıyı istediğiniz URL'ye göndermek için kullanın (bu yöntem ek sayfa yüklemesi gerektirir).
  • Bir PHP değişkeni ayarlayın veya temanızı / eklentinizi hata hakkında uygun bir yerde görüntüleyebilecek şekilde bilgilendirecek bir yöntem çağırın.
  • Set ssorgu değişkeni ''yerine ' 've kullanım page_idyerine post__insizin seçtiğiniz bir sayfa dönebilmek için.
  • Sorgunuzun sonuçlarına hatanızı içeren sahte bir nesneyi enjekte etmek için bir loop_startkanca kullanın WP_Post- bu kesinlikle çirkin bir hack'tir ve özel temanızla doğru görünmeyebilir, ancak "Sonuç Yok" iletisini bastırmanın potansiyel olarak istenen yan etkisi vardır.
  • template_includeArama şablonunu temanızdaki veya eklentinizdeki özel bir şablonla değiştirerek hatanızı gösteren bir filtre kancası kullanın .

Söz konusu temayı incelemeden hangi rotayı izlemeniz gerektiğini belirlemek zordur.


2

Bunu, girişi normal bir ifadeye karşı test etmek için PHP'de bir doğrulama işlevi koyarak gerçekleştirirsiniz. ^[a-zA-Z0-9,.!?' ]*

Yani şöyle görünecektir:

if ( preg_match( "^[a-zA-Z0-9,.!?'" ]*", {search variable} ) ) {
   // Success
} else {
   // Fail
}

RexEx Bütün karakterler için kullanılan A-Z, a-z, 0-9yanı sıra ,, ., !, ?, ', ", ve (boşluk).


2

EDIT: Bu çözüm önerilmez

Aşağıdaki benim çözüm dizeyi oluşturan baytların düzenlemesine bakarak sihirli bir şekilde alfabe ilahi denemek için PHP'nin mbstring fonksiyonları kötüye bir hack . Bu gerçekten kötü bir fikir ve hataya son derece yatkındır .

Çok daha basit ve çok daha güvenilir bir çözüm için lütfen diğer cevabıma bakın .


Latince olmayan alfabe kullanarak arama yapmayı önlemenin bir yolu , arama dizesinin özel bir karakter kodlaması seçiminden birine uygun olup olmadığını görmek için PHP mb_detect_encoding()işlevini kullanmaktır . Bunu yapmak için iyi bir yerdir eylem o sorgu yürütüldüğünde hemen önce patlar gibi.pre_get_posts

Bir aramanın geçersiz bir kodlama kullandığını belirledikten sonra yaptığınız şey gerçekten uygulamaya özeldir. Burada, WordPress'in sorguyu hala bir arama olarak yorumladığından emin olmak için arama sorgusunu tek bir alana ayarladım ve böylece search.phpşablonu yükler (ve kullanıcıyı arama dizesi olduğunda olduğu gibi ön sayfaya yönlendirmez) boş bir dize). Ayrıca kesinlikle hiçbir şeyin döndürülmediğinden emin olmak için imkansız bir posta kimliğine sahip bir diziye ayarlamanın'post__in' ek bir önlemini alıyorum .

Alternatif olarak, kullanıcıyı özel hata mesajınızı içeren bir sayfaya yönlendirmek için arama dizesini nullayarlamayı ve ayarlamayı düşünebilirsiniz 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' );

Kodlama Seçimi

Ben PHP tarafından desteklenen tüm varsayılan kodlamalar farklı alfabe bazı kukla dizeleri karşılaştırarak bir kapsama testi yazdı . Herhangi bir streç ile mükemmel değil (kukla tellerimin ne kadar gerçekçi olduğu hakkında hiçbir fikrim yok ve Japonca tespitini boğuyor gibi görünüyor), ancak adayları belirlemek için biraz yararlı. Burada çalışırken görebilirsiniz .

Bu testle işaretlenen potansiyel karakter kodlamalarını araştırdıktan sonra Windows-1252, Latin alfabesini ve ortak Latin dillerinin aksanlarını kapsayan ihtiyaçlarınız için mükemmel bir seçim gibi görünüyor .

Seçmeler ISO-8859karakter kümeleri gerektiğini ben kafamı kaydıramazsınız Ancak nedenlerle, uygulanabilir, yeni bir seçim olabilir mb_fonksiyonları arasında ayrım görünmüyor ISO-8859ayrı kodlamalar olarak listeleme rağmen bireyin farklı karakter kümeleri.

Diğer bazı yaygın karakterlere izin vermek için de eklemeyi düşünebilirsiniz HTML-ENTITIES.


Mbstring işlevlerinin çalıştığı mekanizmanın kodlamalar arasında ayrım yapamayacağı görülmektedirISO-8859 .
bosco

Bağlantılı testimin yanlış ve yanıltıcı olduğunu öğrendim - mbstring işlevleri bayt dizilerinin öncülünün çalıştığı için, bir kodlama listelenen alfabe destekleyebilecek bayt dizileri kullanabilirken, aslında kodlamanın aslında bunları desteklediği anlamına gelmez karakter. Bu nedenle, kodlamaları test ederek dizelerin alfabelerini filtrelemek güvenilir bir mekanizma değildir . Lütfen bunun yerine diğer cevabımı düşünün.
bosco

1

@MichaelRogers'a birkaç gün önce benzer bir soru gönderdiğinde açıklamaya çalıştığım gibi, bir dizede kullanılan karakter kümesini (veya komut dosyasını) bilmek o dizenin dilini algılamak için yeterli DEĞİLDİR .

@Bosco tarafından açıklanan yöntem ise Böylelikle olacak (2 düzeltmeler aşağıda birlikte) Russian vb dizeleri kaldırmak, bu olacak DEĞİL İngilizce'ye aramalarınızı sınırlamak.

Bunu görmek için şunu deneyin:

$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" ;
        }
    }

[ not: @bosco'nun sağladığı yukarıda belirtilen 2 düzeltme şunlardır:

  1. kalıp bir dize içine alınır (sözdizimsel olarak doğru PHP olması gerekir)
  2. /udeğiştiriciyi ekledi (desen ve konuyu UTF-8 kodlu olarak işlemek için gereklidir, bkz. PHP: Normal İfade Düzenleyicileri ]

hangi üretecek:

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

[ not: İngilizce, Fransızca ve biraz Almanca konuşuyorum (ve biraz Lorem ipsum :-), ancak Arapça, Rusça ve Çince için Google Çeviri'ye güveniyordum]

Gördüğünüz gibi, latin betiği kontrol etmeye güvenmek, İngilizceniz olduğundan emin DEĞİLDİR .

Konu hakkında daha fazla bilgi sağlayan StackOverflow'da (ör . PHP'deki dizeden dili algıla) bir dizi iş parçacığı vardır .


Bana bir dost, bilgiçlik taslayan not bırakalım: Lorem ipsum bir dil değil, birisi konuşuyor söylemek "lorem ipsum" birisi konuşur demek gibi bir "Merhaba dünya" :) dilini ipsum Lorem olan latince eski , hayır ve "lorem ipsum" değil anlama geliyor merhaba dünya '' :) Aslında bir yazım hatası olduğunu 'dolorem ipsum' hangi vasıta 'acı kendisi' ya da öyle bir şey.
gmazzap

@gmazzap Biliyorum, bu bir şakaydı (dolayısıyla ":-)"). Ben dahil lorem ipsum kontrol bu noktayı pekiştirmek için komut dosyası yok değil dilini test edin.
Paul 'Sparrow Hawk' Biron

ve daha da bilgiç olmak için , lipsum.com'da dediği gibi , "Lorem Ipsum, 45 yılında yazılmış Cicero'nun" de Finibus Bonorum et Malorum "un (1.10.32 ve 1.10.33) bölümlerinden geliyor. M.Ö." Ama aynı zamanda anadili bir latin konuşmacı için saçma hale getirmek için çeşitli "randomizasyonlar" vardır, bu yüzden aslında "eski latin" değil, tamamen oluşturulmuş bir "dil" dir.
Paul 'Sparrow Hawk' Biron

Ah, güzel yakalar @ Paul'SparrowHawk'Biron! Düzenli ifadeyi düzeltmek ve çözümümün tam olarak ne yaptığını netleştirmek için cevabımı güncelleyeceğim.
bosco

1
Kişinin İspanyolca yazıp yazmadığı umurumda değil. Kesinlikle İngilizce olması gerekmez. İngilizce dilinde kullanılan karakterleri söyledim, böylece A'dan Z'ye (büyük harf ve büyük harf) + sayılar. Diğer diller aynı karakterleri kullanırsa benim için iyi olur. İzin vermek istemediğim şey Kiril, kanji, Arapça harfler (adını bilmiyorum) ve Aa-Zz + 0-9 olmayan her şey. Dil önemli değil.
Michael Rogers
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.