frFrench ▾
deGerman
enEnglish
esSpanish
hiHindi
itItalian
jaJapanese
koKorean
noNorwegian
zhChinese
Accueil Nouveautés Actualités Tutoriels Consommation Culture Vidéo Buzz Divers

Aksenter og ñ i slugs: Derfor ender artikler med 404

Publié le 06 novembre 2026
Hendene til en utvikler som skriver kode på en bærbar PC foran en skjerm med programkode

En artikkel publiseres, tittelen ser riktig ut … men den offentlige lenken gir 404. Ingen feil i PHP-loggene eller databasen: artikkelen finnes. Synderen er én bokstav, ñ i « La Niña ». Dette skjedde på bloggen vår tidlig i november 2026, og årsaken er verdt å undersøke grundig.

Prinsippet er enkelt: Artikkeladressen lages av tittelen, som en slug (eller et alias). Hvis funksjonen slipper gjennom et tegn som webserveren ikke kan rute, blir artikkelen utilgjengelig selv om alt ellers ser riktig ut.

Scenarioet: En slug som beholder ñ

Funksjonen vår erstattet aksenttegn enkeltvis med en håndskrevet tabell: é ble e, à ble a, ç ble c og så videre. Tabellen dekket fransk, men ikke spansk eller portugisisk: ñ, í, ó, ú, ò, ö og ã ble beholdt. Tittelen « La Niña : le risque économique caché derrière El Niño » ga dermed et alias som fortsatt inneholdt ñ.

På serveren ruter filen .htaccess artiklene med en regel som denne:

RewriteRule ^article/([a-zA-Z0-9-_]+)$ /index.php?page_theme=article&alias=$1 [L]

Tegnklassen [a-zA-Z0-9-_] godtar bare ASCII-bokstaver, tall, bindestrek og understrek. Nettleseren sender ñ kodet som %C3%B1, og Apache dekoder det før sammenligning. UTF-8-bytene som oppstår, inngår ikke i tegnklassen. Regelen matcher ikke, ingen annen regel overtar, og serveren svarer med 404.

Detaljen som forsterker feilen: Sluttankeret

Noen dager tidligere hadde vi lagt til $ på slutten av mønsteret. Uten dette krevde regelen bare treff i starten av adressen: For /article/la-niña-… fanget den opp la-ni og kuttet resten uten varsel. Avhengig av hvordan CMS-et håndterer delvise aliaser, kan resultatet bli feil side, en duplikatside i Googles øyne eller en uforståelig 404. Sluttankeret gjør feilen tydelig, men løser ikke årsaken: Sluggen må ryddes opp.

Publicité

Hvorfor strtolower ikke redder deg

Noen av erstatningene våre gjaldt bare små bokstaver fordi vi regnet med at teksten først ble gjort om til små bokstaver. Men strtolower() håndterer bare ASCII. Siden PHP 8.2 er funksjonen heller ikke avhengig av lokalinnstillingene og lar Ñ og É stå urørt. En tittel skrevet med store bokstaver, « EL NIÑO », beholdt derfor aksenten selv etter at småbokstavene var rettet. Du må enten håndtere store bokstaver eksplisitt eller bruke mb_strtolower($titre, 'UTF-8').

UTF-8, latin1 og erstatninger som ikke treffer

To andre feller finnes i hjemmelagde erstatningstabeller.

  • Dobbel tegnkoding. Hvis en tittel har gått gjennom en MySQL-tilkobling med latin1 mens databasen bruker UTF-8 (eller omvendt), kan ñ bli ñ. Da finner ikke str_replace('ñ', 'n', …) noen treff, og sluggen inneholder ødelagte tegn. Kontroller tegnsettet i tilkoblingen (utf8mb4 overalt) før du skylder på funksjonen.
  • Regulære uttrykk uten modifikatoren u. preg_replace('/[àâä]/', 'a', $s) arbeider byte for byte: Klassen inneholder seks byte, og « à » (to byte) blir « aa ». Med /[àâä]/u tolker PCRE tegn, og resultatet blir riktig.

Slik lager du rene slugs i PHP

I stedet for å utvide tabellen i det uendelige bør du bruke Unicode-translitterering og deretter filtrere med en streng tillattliste.

Den robuste løsningen: intl-utvidelsen

function slugifier(string $titre): string
{
    // Translittère toute écriture en latin, puis en ASCII, et passe en minuscules
    $s = transliterator_transliterate('Any-Latin; Latin-ASCII; Lower()', $titre);
    // Liste blanche : tout ce qui n’est pas a-z ou 0-9 devient un tiret
    $s = preg_replace('/[^a-z0-9]+/', '-', $s);
    return trim($s, '-');
}

Denne varianten håndterer ñ, ß (som blir ss), œ, ø og ł, og også ikke-latinske skriftsystemer som Any-Latin romaniserer. Den er uavhengig av serverens lokalinnstillinger.

Alternativer og begrensninger

  • iconv('UTF-8', 'ASCII//TRANSLIT', $s) avhenger av aktiv lokalinnstilling. Uten setlocale(LC_CTYPE, 'fr_FR.UTF-8') kan glibc gi « Ni?a », og under Alpine (musl) er resultatet enda mindre pålitelig.
  • Normalizer::normalize($s, Normalizer::FORM_D) etterfulgt av preg_replace('/p{Mn}+/u', '', $s) fjerner aksenter, men beholder œ, æ, ß og ø, som ikke regnes som aksentbokstaver i Unicode.
  • En egen tabell er fortsatt et alternativ hvis intl ikke er tilgjengelig, men den må avsluttes med samme tillattliste. Det er denne som garanterer resultatet.

Hovedregelen: Slug og omskrivingsregel må bruke samme tegnsett

Rotårsaken var at vi hadde to ulike definisjoner av « tillatt tegn »: en implisitt i PHP-funksjonen og en eksplisitt i .htaccess. Husk denne regelen: Tillattlisten i slug-generatoren må samsvare med tegnklassen i omskrivingsregelen. Hvis .htaccess godtar [a-z0-9-], må funksjonen avsluttes med preg_replace('/[^a-z0-9]+/', '-', …), uten unntak.

Et lite tips: Sett bindestreken sist i tegnklassen, som i [a-zA-Z0-9_-]. Midt i klassen kan den fungere fordi motoren tolererer det, men den kan tolkes som et intervall og skape problemer senere.

Forebygging er bedre enn reparasjon

  • Test med vanskelige titler: « La Niña », « EL NIÑO », « Ça coûte 5 € », « Œuvre complète », « Straße » og en japansk tittel. Hver slug må matche mønsteret i Apache-regelen.
  • Reserveverdi for tom slug: En tittel som bare består av symboler, gir en tom streng. Bruk da artikkelens ID.
  • Kontroller eksisterende aliaser: En spørring som SELECT alias FROM articles WHERE alias NOT REGEXP '^[a-z0-9-]+$' finner raskt adresser som allerede er ødelagt.
  • Kontroller etter publisering: En enkel HTTP-forespørsel til den offentlige URL-en, som skal svare 200, ville avslørt problemet med én gang.

Hva med søkemotoroptimalisering?

Google kan indeksere URL-er med Unicode-tegn, så ñ i en adresse er ikke forbudt i seg selv. Men når lenken kopieres til en melding eller et sosialt nettverk, vises den ofte kodet, med lite innbydende %C3%B1. En kort og lesbar ASCII-slug er fortsatt det tryggeste valget, forutsatt at funksjonen ikke slipper gjennom uønskede tegn.

Hos oss besto rettingen av tre grep: fullføre translittereringen for både små og store bokstaver, rette aliaset i databasen og beholde sluttankeret i .htaccess, slik at fremtidige feil blir synlige i stedet for å bli kuttet uten varsel.

Tags
slug
URL
aksent
htaccess
UTF-8
SEO
Envoyer à un ami
Signaler cet article
A propos de l'auteur