2009-05-19 8 views
2

Ich benutze diese Funktion, um SEO freundliche Titel zu generieren, aber ich denke, dass es verbessert werden kann, möchte jemand versuchen? Es macht ein paar Dinge: reinigt gemeinsame Akzent Buchstaben, überprüfen Sie gegen eine "verbotene" Array und prüfen Sie optional gegen eine Datenbank der verwendeten Titel.Verbessere meine Funktion: generiere SEO freundliche Titel

/** 
    * Recursive function that generates a unique "this-is-the-title123" string for use in URL. 
    * Checks optionally against $table and $field and the array $forbidden to make sure it's unique. 
    * Usage: the resulting string should be saved in the db with the object. 
    */ 
    function seo_titleinurl_generate($title, $forbidden = FALSE, $table = FALSE, $field = FALSE) 
    { 
     ## 1. parse $title 
     $title = clean($title, "oneline"); // remove tags and such 

     $title = ereg_replace(" ", "-", $title); // replace spaces by "-" 
     $title = ereg_replace("á", "a", $title); // replace special chars 
     $title = ereg_replace("í", "i", $title); // replace special chars 
     $title = ereg_replace("ó", "o", $title); // replace special chars 
     $title = ereg_replace("ú", "u", $title); // replace special chars 
     $title = ereg_replace("ñ", "n", $title); // replace special chars 
     $title = ereg_replace("Ñ", "n", $title); // replace special chars 

     $title = strtolower(trim($title)); // lowercase 
     $title = preg_replace("/([^a-zA-Z0-9_-])/",'',$title); // only keep standard latin letters and numbers, hyphens and dashes 

     ## 2. check against db (optional) 
     if ($table AND $field) 
     { 
      $sql = "SELECT * FROM $table WHERE $field = '" . addslashes($title) . "'"; 
      $res = mysql_debug_query($sql); 
      if (mysql_num_rows($res) > 0) 
      { 
       // already taken. So recursively adjust $title and try again. 
       $title = append_increasing_number($title); 
       $title = seo_titleinurl_generate($title, $forbidden, $table, $field); 
      } 
     } 

     ## 3. check against $forbidden array 
     if ($forbidden) 
     { 
      while (list ($key, $val) = each($forbidden)) 
      { 
       // $val is the forbidden string 
       if ($title == $val) 
       { 
        $title = append_increasing_number($title); 
        $title = seo_titleinurl_generate($title, $forbidden, $table, $field); 
       } 
      } 
     } 
     return $title; 
    } 
    /** 
    * Function that appends an increasing number to a string, for example "peter" becomes "peter1" and "peter129" becomes "peter130". 
    * (To improve, this function could be made recursive to deal with numbers over 99999.) 
    */ 
    function append_increasing_number($title) 
    { 
     ##. 1. Find number at end of string. 
     $last1 = substr($title, strlen($title)-1, 1); 
     $last2 = substr($title, strlen($title)-2, 2); 
     $last3 = substr($title, strlen($title)-3, 3); 
     $last4 = substr($title, strlen($title)-4, 4); 
     $last5 = substr($title, strlen($title)-5, 5); // up to 5 numbers (ie. 99999) 

     if (is_numeric($last5)) 
     { 
      $last5++; // +1 
      $title = substr($title, 0, strlen($title)-5) . $last5; 
     } elseif (is_numeric($last4)) 
     { 
      $last4++; // +1 
      $title = substr($title, 0, strlen($title)-4) . $last4; 
     } elseif (is_numeric($last3)) 
     { 
      $last3++; // +1 
      $title = substr($title, 0, strlen($title)-3) . $last3; 
     } elseif (is_numeric($last2)) 
     { 
      $last2++; // +1 
      $title = substr($title, 0, strlen($title)-2) . $last2; 
     } elseif (is_numeric($last1)) 
     { 
      $last1++; // +1 
      $title = substr($title, 0, strlen($title)-1) . $last1; 
     } else 
     { 
      $title = $title . "1"; // append '1'  
     } 

     return $title; 
    } 
+0

Was Sie Ihre Annahmen hier stützen auf? Warum sind Leerzeichen in Titeln nicht "SEO-freundlich"? Was ist der Zweck der Verwendung von fortlaufenden Nummern, um die Titel zu unterscheiden? – Sparr

Antwort

2

Sie könnten die verlieren:

$title = ereg_replace(" ", "-", $title); 

Und diese Zeilen mit dem schnelleren str_replace() ersetzen:

$title = str_replace(" ", "-", $title); 

Von der PHP-Handbuch Seite für str_replace():

Wenn Du brauchst keine Phantasie Ersetzen Regeln (wie reguläre Ausdrücke), sollten Sie immer diese Funktion anstelle von ereg_replace() oder preg_replace() verwenden.

EDIT:

I verbessert Ihre append_increasing_number($title) Funktion, es tut genau das gleiche, nur ohne Begrenzung auf die Anzahl der Ziffern am Ende (und es ist schöner :):

function append_increasing_number($title) 
{ 
    $counter = strlen($title); 
    while(is_numeric(substr($title, $counter - 1, 1))) { 
     $counter--; 
    } 
    $numberPart = (int) substr($title,$counter,strlen($title) - 1); 
    $incrementedNumberPart = $numberPart + 1; 
    return str_replace($numberPart, $incrementedNumberPart, $title); 
} 
2

karim79 Antwort Folgen, kann der erste Teil gemacht werden, besser lesbar und einfacher, so zu halten:

ersetzen

$title = ereg_replace(" ", "-", $title); // replace spaces by "-" 
$title = ereg_replace("á", "a", $title); // replace special chars 
$title = ereg_replace("í", "i", $title); // replace special chars 

mit

$replacements = array(
    ' ' => '-', 
    'á' => 'a', 
    'í' => 'i' 
); 
$title = str_replace(array_keys($replacements, array_values($replacements), $title); 

Der letzte Teil, wo append_increasing_number() ist schlecht aussieht verwendet. Sie könnten wahrscheinlich die ganze Funktion zu löschen und nur etwas tun, wie

while ($i < 99999){ 
//check for existance of $title . $i; if doesn't exist - insert! 
} 
+0

+1 für die Verwendung von Array-Argumente mit str_replace, aber die while() - Loop-Idee ist kein Gewinner. –

+0

Einverstanden, obwohl lesbarer als der aktuelle Code. Vielleicht habe ich falsch verstanden, was es tut - es ist schwer zu lesen! –

4

Es scheint eine Race-Bedingung zu sein, weil Sie eine SELECT um zu sehen, tun, wenn der Titel bereits verwendet wurde, zurückkehr es dann, wenn nicht (vermutlich der aufrufende Code wird dann in die DB einfügen). Was passiert, wenn ein anderer Prozess das Gleiche tut, aber zwischen SELECT und INSERT eingefügt wird? Ihre Einfügung schlägt fehl. Sie sollten wahrscheinlich ein garantiert-eindeutiges Token zur URL hinzufügen (vielleicht ein "Verzeichnis" im Pfad, eine Stufe höher als der SEO-freundliche Name, ähnlich wie es bei StackOverflow der Fall ist), um das Problem der SEO-freundlichen URL zu vermeiden überhaupt einzigartig sein.

Ich würde auch die append_increasing_number() Funktion neu schreiben, um lesbarer zu sein ... habe es programmatisch feststellen, wie viele Zahlen am Ende sind und angemessen arbeiten, anstelle von einem riesigen if/sonst, es herauszufinden. Der Code wird klarer, einfacher und möglicherweise sogar schneller.

+1

Es ist interessant zu sehen, wie jeder darauf zugreift. Jeder hat es schneller und schöner gemacht, du hast es zum Laufen gebracht. Abgestimmt. –

+1

Ein eindeutiges Token wie Rmeador vorgeschlagen ist eine gute Idee, dies könnte auch als eine einzigartige Einschränkung für die Datenbankspalte implementiert werden, um das nachfolgende Einfügen fehlschlagen zu lassen. – karim79

1

können Sie auch Arrays verwenden, um mit str_replace(), so dass Sie könnte

$replace = array(' ', 'á'); 
$with = array('-', 'a'); 

Die Position im Array tun entsprechen.

Das sollte ein paar Zeilen aus, und ein paar Millisceonds rasieren.

Sie sollten auch alle Interpunktion berücksichtigen, es ist erstaunlich, wie oft, verschiedene Sätze von Anführungszeichen und!? Usw. in URLs. Ich würde eine Preg_replace auf \ W (kein Wort)

.
preg_replace('/\w/', '', $title); 

Das sollte Ihnen ein bisschen helfen

Phil

4

Die str_replace oben genannten Vorschläge sind ausgezeichnet Zusätzlich Sie diese letzte Funktion mit einer einzigen Zeile ersetzen:.

function append_increasing_number($title) { 
    return preg_replace('@([0-9]+)[email protected]', '\1+1', $title); 
} 

Sie können noch besser machen und die Abfrage-in-a-Loop-Idee ganz und etwas tun, wie

"SELECT MAX($field) + 1 FROM $table WHERE $field LIKE '" . mysql_escape_string(preg_replace('@[0-9][email protected]', '', $title)) . "%'"; 

Lauf SELECTs in einer Schleife wie das Entfernen nur hässlich.

+0

+1 Sehr intelligente Vorschläge –

+0

+1, um die Unterabstimmung dieser Antwort anzupassen. Karmisches Gleichgewicht wiederhergestellt. – karim79

3

Es sieht so aus, als hätten andere die meisten wichtigen Punkte erreicht (vor allem hinsichtlich der Erhöhung des Suffixes und der Ausführung von SQL-Abfragen rekursiv/in einer Schleife), aber ich sehe immer noch ein paar große Verbesserungen.

Erstens, versuchen Sie nicht, Ihre eigenen Diakritika-zu-ASCII-Ersatz zu finden; Sie werden nie alle fangen und es gibt bessere Werkzeuge. Insbesondere lenke ich Ihre Aufmerksamkeit auf die "TRANSLIT" -Funktion von iconv. Sie können von UTF-8 zu konvertieren (oder was auch immer Codierung für Ihren Titel verwendet wird) auf einfache alten 7-Bit-ASCII wie folgt:

$title = strtolower(strip(clean($title))); 
$title = iconv('UTF-8', 'ASCII//TRANSLIT', $title); 
$title = str_replace("'", "", $title); 
$title = preg_replace(array("/\W+/", "/^\W+|\W+$/"), array("-", ""), $title); 

Beachten Sie, dass dies auch einen Fehler in Ihrem ursprünglichen Code fixiert, wo der Raum-zu -dash Ersatz wurde vor trim() aufgerufen und ersetzt alle Läufe von Nicht-Buchstaben/-number/-undercores durch einzelne Bindestriche. Zum Beispiel wird " Héllo, world's peoples!""hello-worlds-peoples". Dies ersetzt den gesamten Abschnitt 1.

Zweitens Ihre $forbidden Schleife neu beschrieben werden kann, effizienter zu sein und Rekursion zu beseitigen:

if ($forbidden) 
{ 
    while (in_array($title, $forbidden)) 
    { 
     $title = append_increasing_number($title); 
    } 
} 

Dieser ersetzt Abschnitt 3.

Verwandte Themen