Consulta sobre PHP y URLs amigables

Dekard89

Saludos Señores!
Estoy teniendo problemas con mi código PHP. La idea es que los posts de mi página web generen una URL amigable para los buscadores de forma automática. No obstante, el código que utilizo ahora mismo no elimina artículos, preposiciones o acentos de las palabras.

Quiero que haga lo siguiente:
Título: Con orgullo y pasión se puede conseguir cualquier cosa
URL: orgullo-pasion-puede-conseguir-cualquier-cosa

A continuación os pongo el código PHP:

<?php
if (!defined('BASE_URL')) {
    exit ('No direct script access allowed');
}

/**
 *--------------------------------------------------------------------------
 * === CLASS SOLUTIISOFT ===
 *--------------------------------------------------------------------------
 * Collection of static methods helpful
 *
 * PHP version 5.3
 *
 * @category   E-Blog
 * @package    Core
 * @subpackage Libraries
 * @filename   solutiisoft.php
 * @author     Solutii Soft <[email protected]>
 * @copyright  2013 Solutii Soft
 * @license    2013 Solutii Soft
 * @link       http://www.eblog.solutiisoft.com
 * @since      File available since Release 1.0
 */
class Solutii_Soft
{

    /**
     * Create a friendly URL
     *
     * @param string $str URL which need to be transform
     *
     * @function friendlyURL
     * @access   public
     * @return   string
     */
    public static function friendlyURL($str)
    {
        $delimiter  = '-';
        $clean      = iconv('UTF-8', 'ASCII//TRANSLIT', $str);
        $clean      = preg_replace("/[^a-zA-Z0-9\/_|+ -]/", '', $clean);
        $clean      = strtolower(trim($clean, '-'));
        $clean      = preg_replace("/[\/_|+ -]+/", $delimiter, $clean);

        return $clean;
    }

    /**
     * All characters in the string after the last _, if these numbers will be deleted
     *
     * @param string $string string which need to be transform
     *
     * @function slugURL
     * @access   public
     * @return   string
     */
    public static function slugURL($string)
    {
        $url = explode('-', $string);

        if (is_numeric(end($url))) {
            end($url);
            unset($url[key($url)]);
        }

        return self::friendlyURL(implode('-', $url));
    }

    /**
     * Clean all spaces before and after the comma
     *
     * @param string $string string which need to be transform
     *
     * @function prepareTags     
     * @access   public
     * @return   string
     */
    public static function prepareTags($string)
    {
        return implode(",", preg_split('~,\s*~', trim($string)));
    }

    /**
     * One-way string hashing
     *
     * @param string $string string which need to be hash
     *
     * @function hashPassword
     * @access   public
     * @return   hashed string
     */
    public static function hashPassword($string)
    {
        global $_EBLOG_hash;

        $salt       = $_EBLOG_hash['salt'];
        $strength   = "12";

        if (CRYPT_BLOWFISH == 1) {
            $presalt        = (version_compare(PHP_VERSION, '5.3.7', '<')) ? '2a' : '2y';
            $blowfish_salt  = '$'. $presalt .'$' . $strength . '$'. substr($salt, 0, CRYPT_SALT_LENGTH) .'$';
            return crypt($string, $blowfish_salt);
        }
        return sha1(hash_hmac('sha512', $salt, $string));
    }

    
/** * Remove all malicious code (better known as XSS) * * @param string $dirty_html string that need to be clean * * @function cleanXSS * access public * @return string */ public static function cleanXSS($dirty_html) { include_once 'public/vendor/htmlpurifier/htmlpurifier.standalone.php'; $config = HTMLPurifier_Config::createDefault(); $purifier = new HTMLPurifier($config); return $purifier->purify($dirty_html); }

/** * Check if an array is empty * * @param array $array array which need to be check * * @function isEmptyArray * @access public * @return true for empty or false otherwise */ public static function isEmptyArray($array) { if (array_filter($_FILES['image']['name']) === array()) { return true; } return false; } /** * Remove all characters up to the first _ including this * * @param string $imageName name of image * * @function altOfImage * @access public * @return string */ public static function altOfImage($imageName) { $name = explode('_', pathinfo($imageName, PATHINFO_FILENAME)); unset($name[0]); return implode(' ', $name); } } /* end of file solutiisoft.php */

A ver si a alguno de vosotros se os ocurre como arreglarlo para que elimine los artículos, preposiciones y acentos (pero no el carácter acentuado, solo el acento).

Edito: adjunto el archivo .php http://ge.tt/5Nlo6e72/v/0?c

vincen

Mete el codigo en

code

Para que sea mas facil de leer

1 respuesta
Dekard89

#2 Listo, gracias por la anotación :)

DarkSoldier

estas palabras que supuestamente penalizan en el SEO se llaman stopwords, te dejo un listado de ellas en español y con un replace ya bastaría supongo xd

http://www.berriart.com/wp-content/espanol-stopwords.txt
http://www.navigla.es/posicionamiento-seo/palabras-stopwords-seo-espanol/

1 respuesta
txandy

#1 El problema lo tienes en esta expresión regular:

$clean      = preg_replace("/[^a-zA-Z0-9\/_|+ -]/", '', $clean);

Tendrías que hacer un str_replace de las letras con tilde a las letras sin tilde, algo como

str_replace('ó','o', $clean)

Y así con cada letra, la ñ tambien tendrías que ponerla, creo recordar que le puedes pasar un array en plan

str_replace(array(ó,ñ,í), array(o,n,i), $clean)

y lo hace igual pero todas a la vez o debería hacerlo así si no recuerdo del todo mal la funcion str_replace...

Esos str_replace antes de la expresión regular que he copiado aqui.

1 1 respuesta
Dekard89

#5 Lo he reemplazado, pero el php crashea sin darme código de error. Sencillamente recargo la página y no aparece absolutamente nada en pantalla :S.

1 respuesta
txandy

#6

Tendrías que dejarlo algo tal que así...

  $delimiter  = '-';
  $clean      = iconv('UTF-8', 'ASCII//TRANSLIT', $str);
  $clean      = str_replace(array("ó","á"),array("o",'a'), $clean);
  $clean      = preg_replace("/[^a-zA-Z0-9\/_|+ -]/", '', $clean);
  $clean      = strtolower(trim($clean, '-'));
  $clean      = preg_replace("/[\/_|+ -]+/", $delimiter, $clean);

Si te sigue sin mostrar los errores añade

ini_set('display_errors', '1');

o debug con die() por mitad de la clase xD

1 respuesta
Dekard89

#7 Es maravilloso XD. Ahora no crashea, pero sigue eliminando las letras que acompañan a los acentos: /apple-y-la-explotacin-infantil

Al código se la pela, es un outsider jajaja.
Para mi que en el resto hay alguna línea que me está jodiendo.

Edito: os adjunto el archivo .php http://ge.tt/5Nlo6e72/v/0?c

1 respuesta
Dekard89

#4 Gracias por tu aporte :). Lamentablemente hay algo del código que sigue impidendo a:

public static function friendlyURL($str)

ejecutar las ordenes que le escribo correctamente. La intención es que el código elimine acentos y un puñado de stopwords a la hora de generar el slug de la url.

Pero esto se está convirtiendo en algo más complicado que la máquina Enigma XD.

Edito: os adjunto el archivo .php http://ge.tt/5Nlo6e72/v/0?c

palotex

#8 tienes bien configurado el setlocale? Prueba añadiendo antes de nada

 setlocale(LC_ALL, 'es_ES'); 
2 respuestas
Dekard89

#10 Primero de todo, gracias por atender mi problema y ahora perdona mi ineptitúd. ¿Lo pongo tal que así?:

public static function friendlyURL($str)
    {
        $delimiter  = '-';
        $clean      = iconv('UTF-8', 'ASCII//TRANSLIT', $str);
        $clean      = preg_replace("/[^a-zA-Z0-9\/_|+ -]/", '', $clean);
        $clean      = strtolower(trim($clean, '-'));
        $clean      = preg_replace("/[\/_|+ -]+/", $delimiter, $clean);
        setlocale(LC_ALL, 'es_ES');

    return $clean;

Como te digo, llevo dos telediarios en esto del php por lo que aún me pierdo bastante :f5: :f5: :f5: :f5:

1 respuesta
txandy

#11 Yo creo que esta lina es la que te esta fastidiandio un poco

$clean      = iconv('UTF-8', 'ASCII//TRANSLIT', $str);

Prueba a eliminarla, estas convirtiendo lo UTF8 (que es como hay que trabajar) a ASCII noseq, intenta trabajar siempre en UTF8 para evitar problemas con tildes y demas. Borra esa linia y nos cuentas que salida te da.

PHP es un lenguaje linear, si lo pones al final no te va a funcionar, porque primero ejecuta lo de arriba y luego lo de abajo ;) tendrias que ponerlo en la primera linea después de {

1 3 respuestas
Dekard89

#12 Gracias una vez más. Veamos, al eliminar esa línea, no ocurre nada en la URL. Los acentos se siguen eliminando junto al carácter al que acompañan como en el anterior ejemplo: /apple-y-la-explotacin-infantil
No obstante, al eliminarla no crashea la página. Funciona como siempre. Podemos considerarlo un avance, pero aún queda por solucionar el problema de los acentos y las stopwords.

public static function friendlyURL($str)
    {
        $delimiter  = '-';
        $clean      = preg_replace("/[^a-zA-Z0-9\/_|+ -]/", '', $clean);
        $clean      = strtolower(trim($clean, '-'));
        $clean      = preg_replace("/[\/_|+ -]+/", $delimiter, $clean);

    return $clean;
}
1 respuesta
Dekard89

#10 Al introducir esa línea, de la forma que me ha anotado oportunamente #12, no recibo mensaje de vuelta. Todo sigue funcionando con normalidad.

TeNSHi

#13 Has hecho la prueba con palabras con ñ después de quitar esa linea? o esas palabras las quieres filtrar todas?

1 respuesta
Dekard89

#15 Pues mira, no había probado las Ñs todavida. Al hacerlo despues de quital la línea

    $clean      = iconv('UTF-8', 'ASCII//TRANSLIT', $str);

, hay un erro 404 con las Ñs. ¿Os dice algo esta nueva condición?

1 respuesta
TeNSHi

#16 Es que en teoría para eso es esa linea, lo que pasa que en vez de darte un error pensaba que simplemente te quitaría la letra.

No se si ya lo has leído pero puedes echarle un vistazo a este link para sacar ideas:

http://cubiq.org/the-perfect-php-clean-url-generator

Creo que ya te lo han comentado pero deberías poner en este orden estas lineas:

        $delimiter  = '-';
        setlocale(LC_ALL, 'es_ES');
        $clean      = iconv('UTF-8', 'ASCII//TRANSLIT', $str);
        $clean      = preg_replace("/[^a-zA-Z0-9\/_|+ -]/", '', $clean);
        $clean      = strtolower(trim($clean, '-'));
        $clean      = preg_replace("/[\/_|+ -]+/", $delimiter, $clean);

Si no pones el setlocale antes del iconv creo que o no funcionaba bien o fallaba porque te estará cogiendo una configuración regional que no es la española, vamos al menos yo en su momento tuve algún problema con eso.

1 1 respuesta
Dekard89

#17 Si, conozco la página que me has pasado y he intentado utilizar algunas recomendaciones que en ella aparecen, pero o no funcionan o hacen que deje de funcionar la página. En parte puede ser todo esto por lo que txandy comenta #12. Hay que trabajar en UTF8 y las propuestas de la página funcionan con ASCII.

Por otro lado, lo del setlocale ya lo he probado pero sin efecto a cambio en la página.
Gracias aún así, creo que cada vez estamos más cerca de descubrir cual es el problema :).

1 respuesta
TeNSHi

#18 Con el código que he puesto arriba que es lo que no te funciona?

1 respuesta
txandy

Tal vez tengas que hacer la warrada de usar utf8_decode y utf8_encode...

1
Dekard89

#19 Básicamente no ocurre nada. No hay cambios en la construcción de las urls. Luego con los ejemplos de la página que me has pasado, con algunos la página crashea y con otros al igual que con el fragmento que me has pasado, la página sigue funcionando igual, construyendo las urls como anteriormente cito.

http://ge.tt/5Nlo6e72/v/0?c
Este es el archivo maldito que tantos problemas me está creando XD.

1 respuesta
TeNSHi

#21 Pues probando este código (he puesto es_ES.UTF8, pero poniendo es_ES también funciona) me funciona bien:

	$str = 'en el día de hoy se acaba el año';
	setlocale(LC_ALL,'es_ES.UTF8');
        $delimiter  = '-';
        $clean      = iconv('UTF-8', 'ASCII//TRANSLIT', $str);
        $clean      = preg_replace("/[^a-zA-Z0-9\/_|+ -]/", '', $clean);
        $clean      = strtolower(trim($clean, '-'));
        $clean      = preg_replace("/[\/_|+ -]+/", $delimiter, $clean);

    echo($clean);

Y de resultado me da: en-el-dia-de-hoy-se-acaba-el-ano

Lo puedes probar en http://phpfiddle.org/

Como estas llamando a la función friendlyURL?

1 1 respuesta
Dekard89

#22 Por como la llamo te refieres a "public static function friendlyURL" tal vez?
Pues si te funciona no entiendo porque aqui no lo hace. En lo que me respondes voy a vaciar el contenido del ftp, voy a crear una nueva base de datos y voy a subir de nuevo el script.

Y para ir adelantando ya, feliz salida y entrada de año a toda la gente del hilo ! :P

1 respuesta
TeNSHi

#23 Si, me refiero a esa función estática, ahora no recuerdo bien pero dependiendo de como hagas la llamada igual no funciona y los this creo que no funcionan.

1 respuesta
Dekard89

#24 Pues como yo no lo he escrito primeramente, no te se decir. Pero si me dices donde mirarlo te lo busco en un momento y te lo digo.

1 respuesta
TeNSHi

#25 Tiene que revisar como llama a ese método, aquí tienes algún ejemplo:

http://php.net/manual/es/language.oop5.static.php

Yo creo que el error no puede estar en ese método porque funcionar funciona, otra cosa es que exista un error en la llamada o al tratar el resultado devuelto por el método.

1 respuesta
BLZKZ

llego tarde, pero yo hago algo así de manera super rudimentaria, por si a alguien le sirve

function adapta_link($string){
		$array = array(
					'/à|á|â|ã|ä|å|æ|ª/' => 'a',
					'/À|Á|Â|Ã|Ä|Å|Æ/' => 'A',
					'/è|é|ê|ë|ð/' => 'e',
					'/È|É|Ê|Ë|Ð/' => 'E',
					'/ì|í|î|ï/' => 'i',
					'/Ì|Í|Î|Ï/' => 'I',
					'/ò|ó|ô|õ|ö|ø|º/' => 'o',
					'/Ò|Ó|Ô|Õ|Ö|Ø/' => 'o',
					'/ù|ú|û|ü/' => 'u',
					'/Ù|Ú|Û|Ü/' => 'U',
					'/ç/' => 'c',
					'/Ç/' => 'C',
					'/ý|ÿ/' => 'y',
					'/Ý|Ÿ/' => 'Y',
					'/ñ/' => 'n',
					'/Ñ/' => 'N',
					'/[\W¿¡]+/' => '_',
					'/^\-/' => '',
					'/\-$/' => ''
		);
		$patron = '/[\W¿¡]+/';
		return preg_replace(array_keys($array), array_values($array), htmlspecialchars($string, ENT_QUOTES));
		//return preg_replace($patron, "-", $string);
		
}
Dekard89

#26 Bueno, lo he vuelto a instalar todo y parece que con:

public static function friendlyURL($str)
    { 
        setlocale(LC_ALL,'es_ES.UTF8');
        $delimiter  = '-';
        $clean      = iconv('UTF-8', 'ASCII//TRANSLIT', $str);
        $clean      = preg_replace("/[^a-zA-Z0-9\/_|+ -]/", '', $clean);
        $clean      = strtolower(trim($clean, '-'));
        $clean      = preg_replace("/[\/_|+ -]+/", $delimiter, $clean);

    return $clean;
}

se sustituyen todos los carácteres con acentos por carácteres sin acentos(y las ñs por ns), aunque queda por solucionar el problema de las stopwords, plan artículos y preposiciones.
Pero ya hemos avanzado un buen trecho :).

1 respuesta
TeNSHi

#28 Bueno eso no es muy difícil, lo puedes hacer con preg_replace pasandole un array de las palabras que no quieres y cambiarlas por '', vamos quitarlas como haces en el primer preg_replace.

1 respuesta
Dekard89

#29 ¿Puedo usar la línea del primer preg-replace, o es mejor que cree un nuevo $clean:...?

1 respuesta