Función PHP para hacer slug (cadena URL)

Resuelto Andres SK asked hace 54 años • 31 respuestas

Quiero tener una función para crear slugs a partir de cadenas Unicode, por ejemplo, gen_slug('Andrés Cortez')debería devolver andres-cortez. ¿Cómo debería hacer eso?

Andres SK avatar Jan 01 '70 08:01 Andres SK
Aceptado

En lugar de un reemplazo largo, prueba este:

public static function slugify($text, string $divider = '-')
{
  // replace non letter or digits by divider
  $text = preg_replace('~[^\pL\d]+~u', $divider, $text);

  // transliterate
  $text = iconv('utf-8', 'us-ascii//TRANSLIT', $text);

  // remove unwanted characters
  $text = preg_replace('~[^-\w]+~', '', $text);

  // trim
  $text = trim($text, $divider);

  // remove duplicate divider
  $text = preg_replace('~-+~', $divider, $text);

  // lowercase
  $text = strtolower($text);

  if (empty($text)) {
    return 'n-a';
  }

  return $text;
}

Esto se basó en el del tutorial Jobeet de Symfony.

Maerlyn avatar Jun 02 '2010 07:06 Maerlyn

Actualizar

Dado que esta respuesta está recibiendo cierta atención, agrego una explicación.

La solución proporcionada esencialmente reemplazará todo excepto AZ, az, 0-9 y - (guión) por - (guión). Por lo tanto, no funcionará correctamente con otros caracteres Unicode (que son caracteres válidos para una cadena/slug de URL). Un escenario común es cuando la cadena de entrada contiene caracteres que no están en inglés.

Utilice esta solución solo si está seguro de que la cadena de entrada no tendrá caracteres Unicode que tal vez desee que formen parte de la salida/slug.

P.ej. "नारी शक्ति" se convertirá en "----------" (todos los guiones) en lugar de "नारी-शक्ति" (slug de URL válida).

Respuesta

$slug = strtolower(trim(preg_replace('/[^A-Za-z0-9-]+/', '-', $string)));
TheKalpit avatar Dec 12 '2015 20:12 TheKalpit

Si tiene instalada la extensión intl , puede usar la función Transliterator::transliterate para crear un slug fácilmente.

$string = 'Namnet på bildtävlingen';

$rules = <<<'RULES'
    :: Any-Latin;
    :: NFD;
    :: [:Nonspacing Mark:] Remove;
    :: NFC;
    :: [^-[:^Punctuation:]] Remove;
    :: Lower();
    [:^L:] { [-] > ;
    [-] } [:^L:] > ;
    [-[:Separator:]]+ > '-';
RULES;

$slug = \Transliterator::createFromRules($rules)
    ->transliterate( $string );

echo $slug; // namnet-pa-bildtavlingen

manifestación

Tenga en cuenta que esta solución funciona sea cual sea el alfabeto y es muy flexible.

hdogan avatar Nov 11 '2012 14:11 hdogan

Nota: ¡Tomé esto de WordPress y funciona!

Úselo así:

echo sanitize('testing this link');

Código

//taken from wordpress
function utf8_uri_encode( $utf8_string, $length = 0 ) {
    $unicode = '';
    $values = array();
    $num_octets = 1;
    $unicode_length = 0;

    $string_length = strlen( $utf8_string );
    for ($i = 0; $i < $string_length; $i++ ) {

        $value = ord( $utf8_string[ $i ] );

        if ( $value < 128 ) {
            if ( $length && ( $unicode_length >= $length ) )
                break;
            $unicode .= chr($value);
            $unicode_length++;
        } else {
            if ( count( $values ) == 0 ) $num_octets = ( $value < 224 ) ? 2 : 3;

            $values[] = $value;

            if ( $length && ( $unicode_length + ($num_octets * 3) ) > $length )
                break;
            if ( count( $values ) == $num_octets ) {
                if ($num_octets == 3) {
                    $unicode .= '%' . dechex($values[0]) . '%' . dechex($values[1]) . '%' . dechex($values[2]);
                    $unicode_length += 9;
                } else {
                    $unicode .= '%' . dechex($values[0]) . '%' . dechex($values[1]);
                    $unicode_length += 6;
                }

                $values = array();
                $num_octets = 1;
            }
        }
    }

    return $unicode;
}

//taken from wordpress
function seems_utf8($str) {
    $length = strlen($str);
    for ($i=0; $i < $length; $i++) {
        $c = ord($str[$i]);
        if ($c < 0x80) $n = 0; # 0bbbbbbb
        elseif (($c & 0xE0) == 0xC0) $n=1; # 110bbbbb
        elseif (($c & 0xF0) == 0xE0) $n=2; # 1110bbbb
        elseif (($c & 0xF8) == 0xF0) $n=3; # 11110bbb
        elseif (($c & 0xFC) == 0xF8) $n=4; # 111110bb
        elseif (($c & 0xFE) == 0xFC) $n=5; # 1111110b
        else return false; # Does not match any model
        for ($j=0; $j<$n; $j++) { # n bytes matching 10bbbbbb follow ?
            if ((++$i == $length) || ((ord($str[$i]) & 0xC0) != 0x80))
                return false;
        }
    }
    return true;
}

//function sanitize_title_with_dashes taken from wordpress
function sanitize($title) {
    $title = strip_tags($title);
    // Preserve escaped octets.
    $title = preg_replace('|%([a-fA-F0-9][a-fA-F0-9])|', '---$1---', $title);
    // Remove percent signs that are not part of an octet.
    $title = str_replace('%', '', $title);
    // Restore octets.
    $title = preg_replace('|---([a-fA-F0-9][a-fA-F0-9])---|', '%$1', $title);

    if (seems_utf8($title)) {
        if (function_exists('mb_strtolower')) {
            $title = mb_strtolower($title, 'UTF-8');
        }
        $title = utf8_uri_encode($title, 200);
    }

    $title = strtolower($title);
    $title = preg_replace('/&.+?;/', '', $title); // kill entities
    $title = str_replace('.', '-', $title);
    $title = preg_replace('/[^%a-z0-9 _-]/', '', $title);
    $title = preg_replace('/\s+/', '-', $title);
    $title = preg_replace('|-+|', '-', $title);
    $title = trim($title, '-');

    return $title;
}
Imran Omar Bukhsh avatar Apr 28 '2012 03:04 Imran Omar Bukhsh

Siempre es una buena idea utilizar soluciones existentes que cuenten con el respaldo de muchos desarrolladores de alto nivel. El más popular es https://github.com/cocur/slugify . En primer lugar, admite más de un idioma y se está actualizando.

Si no desea utilizar el paquete completo, puede copiar la parte que necesita.

Vazgen Manukyan avatar Apr 25 '2016 20:04 Vazgen Manukyan