[PHP] mod_rewrite vriendelijke URL's

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
Ik wil graag dat mijn CMS'je "vriendelijke URL's" genereert, bijvoorbeeld:

http://www.website.com/activiteiten/reizen/ardennen

Ik heb na wat nadenken wel een idee hoe ik dit moet oplossen, maar wil dit graag (vereenvoudigd) aan jullie voorleggen voordat ik daadwerkelijk aan de slag ga. Mijn idee is om een tabel te maken van de vorm:
code:
1
2
3
4
5
6
7
8
9
10
11
+----------------------+
| nodes                |
+------------+---------+
| node_id    | INT     |
+------------+---------+
| node_url   | VARCHAR |
+------------+---------+
| node_title | VARCHAR |
+------------+---------+
| node_body  | TEXT    |
+------------+---------+

Hierbij bevat node_title de uitgebreide titel van een pagina ("Welkom op de pagina met activiteiten"), node_body het eigenlijke artikel (met HTML opmaak via in-browser editor) en node_url een unieke URL naam voor elk artikel (in het voorbeeld hierboven: activiteiten, reizen en ardennen).

Stel dat iemand de url http://www.website.com/activiteiten aanroept, dan zoek ik met behulp van mod_rewrite uit welk artikel aan het eind van de url staat. Vervolgens zoek ik in de tabel "nodes" op ...WHERE node_url = "activiteiten". Ik haal de title en body op en laat het artikel zien.

Is dit de standaard manier om dergelijke URL's met een database te matchen? Ik kan me voorstellen dat er problemen ontstaan als je in de nodes-tabel twee artikelen hebt met de titel "ardennen", namelijk:

http://www.website.com/activiteiten/reizen/ardennen
http://www.website.com/natuurgebieden/ardennen

Artikel 1 gaat over reizen naar de ardennen, artikel twee gaat over een heel ander onderwerp. In de database ziet het er bv. als volgt uit:
code:
1
2
3
4
5
6
7
8
9
+------------------------------------------------+
| nodes                                          |
+------------------------------------------------+
| node_id | node_url | node_title | node_body    |
+---------+----------+------------+--------------+
| 4       | ardennen | reizen!    | lekker weg.. |
+---------+----------+------------+--------------+
| 17      | ardennen | natuur!    | in het bos.. |
+---------+----------+------------+--------------+


Hoe los ik dit nu op? Mijn idee is om een node_parent_url toe te voegen aan de tabel. Zo kan ik zien dat ik in het tweede geval moet zoeken op WHERE node_url = "ardennen" AND node_parent_url = "natuurgebieden", maar dan heb ik nog steeds een probleem als de gebruiker onder dezelfde parent twee verschillende artikelen wil plaatsen met dezelfde node_url. Dit zal in de praktijk haast niet voorkomen, maar het is een mogelijkheid. Hoe is dit te ondervangen? Denk ik helemaal verkeerd of zetten jullie gewoon een restrictie op twee dezelfde artikelen onder 1 parent? Kent iemand wellicht een artikel over dit onderwerp?

[ Voor 7% gewijzigd door Reveller op 25-06-2004 01:01 . Reden: even netjes maken ]

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • Morax
  • Registratie: Mei 2002
  • Laatst online: 20-09 00:30
Wat je wel kan doen, is controleren op het aantal resultaten. Is dat er 1, dan is dat geen probleem en laat je het gematchde artikel zien.
Is mysql_num_rows echter groter dan 1, dan laat je de 2 mogelijkheden zien die er zijn, met daarbij bijvoorbeeld de titel en de eerste x tekens van de tekst die het artikel bevat.

Dit lijkt me ook wat gebruiksvriendelijker, want als men info zoekt over de ardennen, en je hebt meerdere soorten artikelen over de ardennen, dan krijgt men bij het intikken van alle mogelijke info op jou site met betrekking tot de ardennen en kan men uitzoeken waar men naar op zoek is :)

Ik hoop dat je hier iets aan hebt :)

What do you mean I have no life? I am a gamer, I got millions!


Acties:
  • 0 Henk 'm!

  • MTWZZ
  • Registratie: Mei 2000
  • Laatst online: 13-08-2021

MTWZZ

One life, live it!

Je kunt natuurlijk je hele nodes tabel een beetje splitsen en een aparte "sections" tabel maken. Je kunt dan door te kijken naar het 1e deel wat na je www.website.com staat om uit te vogelen wat je "section" is en daarin een "startpagina" aangeven.
Op die manier hoef je niet ingewikkeld te doen met dubbele rijen in je nodes tabel.

HTH

offtopic:
Waarom gebruik je mod_rewrite? Is het niet makkelijker om een Alias te maken, zoiets als:
Alias /content "/opt/apache/htdocs/index.php"
Dan heb je meteen alle Apache vars in je php script.

[ Voor 29% gewijzigd door MTWZZ op 25-06-2004 08:41 ]

Nu met Land Rover Series 3 en Defender 90


Acties:
  • 0 Henk 'm!

  • Skaah
  • Registratie: Juni 2001
  • Laatst online: 16-09 18:38
Op ALA hebben ze het opgelost door geen 'virtuele mappen' te gebruiken, maar gewoon ieder artikel één woord te geven. Dus dan komt twee keer ardennen niet voor. Dit kun je natuurlijk ook afdwingen.

Je zou ook het hele pad in de database kunnen opslaan, dus /activiteiten/natuurreizen/ardennen.

Je kan ook alles recursief opzoeken, dus eerst "activiteiten", kijken of daar een "natuurreizen"-child bij hoort, kijken of daar een "ardennen"-child bijhoort,

Je kan het misschien handigere van de andere kant aanpakken, dat scheelt je performance. De eerst "ardennen", en dan kijken of daar een parent "natuurreizen" bijhoort, is dat één, dan geen probleem, zijn er meer, dan nog een keer omhoog (dus, hoort er bij natuurreizen dan "activiteiten"?).

Ik hoop dat je snap van ik bedoel.
MTWZZ schreef op 25 juni 2004 @ 08:38:
offtopic:
Waarom gebruik je mod_rewrite? Is het niet makkelijker om een Alias te maken, zoiets als:
Alias /content "/opt/apache/htdocs/index.php"
Dan heb je meteen alle Apache vars in je php script.
Je hebt (lang) niet altijd toegang tot httpd.conf of mod_rewrite, op een standaard hosting-pakketje.

[ Voor 25% gewijzigd door Skaah op 25-06-2004 10:31 ]


Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
@MTWZZ - het is een CMS waarin mensen in principe oneindig diepe boomstructuren moeten kunnen aanleggen. Vooraf slechts twee lagen definieren is geen oplossing.

@Skaah - waar staat ALA voor?
@Skaah - zou je me op weg kunnen helpen hoe ik recursief kan checken welke pagina ik uit de database moet halen? Ik kom er zelf niet goed uit.

Neem het volgende voorbeeld:

www.website.com/producten/fruit/appels/prijzen/nederland
www.website.com/producten/fruit/peren/prijzen/nederland

Ik heb nu het volgende (met in m'n .htaccess een rewriterule die alles na de rootslash in een variabele q stopt):
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
if (isset ($_GET['q'])) {
  $q = $_GET['q'];
}

$path = explode('/',$q);
$nodes = array();

for ($i = 0; $i < count($path); $i++) {
    if ($path[$i] != '') {
        $nodes[] = $path[$i];
    }
}

print_r($nodes);

In het eerste geval levert dit op:

code:
1
2
3
4
5
6
7
8
Array
(
    [0] => producten
    [1] => fruit
    [2] => appels
    [3] => prijzen
    [4] => nederland
)


Hoe kom ik nu efficient uit bij de pagina die ik nodig heb (stel dat in het bovenste voorbeeld "nederland" een database entry is met node_id = 33. In het tweede geval (www.website.com/producten/fruit/peren/prijzen/nederland) is de pagina "nederland" de pagina met node_id = 47)?

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • chuxiej
  • Registratie: Februari 2001
  • Laatst online: 13-07-2020
Volgens mij bedoeld hij dat je een extra veld moet toevoegen in je database bv node_child waarmee je aangeeft waar die node een 'child' van is

Bv:

node_url: nederland
node_child: prijzen

en de node prijzen heeft child appels
en er is nog een veld die ook prijzen heet en als child peren heeft

dan doe je ongeveer zo (niet getest + tis laat)
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<?
if(isset($_GET['q']))
{
    $q = $_GET['q'];
}

$path   = explode('/', $q);
$nodes  = array();

foreach($path AS $input)
{
    if(!empty($input))
        $nodes[]    = $input;
}
/*
output:
Array
(
    [0] => producten
    [1] => fruit
    [2] => appels
    [3] => prijzen
    [4] => nederland
)
*/
$copy   = $nodes;

$query  = mysql_query("SELECT 
                        node_id, 
                        node_child 
                       FROM 
                        nodes
                       WHERE
                        node_url    = '". array_pop($copy); ."'");
if(mysql_numrows($query) == 1)
{
    // code om pagina weer te geven
} else
{
    // meer dan 1 match
    while($data = mysql_fetch_array($query))
    {
        if(in_array($data['node_child'], $nodes))
        {
            // deze node is het
            // moet nog verder doorgaan, beetje te laat om over oneindig diepe boomstructuren na te denken ;)
        }
    }
}
?>

www.dannyhiemstra.nl


Acties:
  • 0 Henk 'm!

  • T-MOB
  • Registratie: Maart 2001
  • Laatst online: 14:27
Je zult zowieso in je tabel moeten gaan aangeven wie de 'ouder' is van elke node. Stel dat je dat veld 'node_parent' zou noemen dan levert dit stukje code het id van de laatste node op door elke stap van het url langs te lopen. Om het efficiënt te houden kun je het dus beter alleen uitvoeren als er meerdere mogelijkheden zijn....
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$firstnode_query = mysql_query("SELECT node_id
                                FROM nodes 
                                WHERE node_url = '" .$nodes[0] ."' 
                                LIMIT 1");
$firstnode = mysql_result($firstnode_query, 0);

for ($i=1; $i<count($nodes);$i++)
{
    $parent = (!isset($lastnode)) ? $firstnode : $lastnode;

    $query = mysql_query("SELECT node_id 
                        FROM nodes 
                        WHERE node_url    = '". $nodes[$i] ."' 
                          AND node_parent ='" .$parent ."'");

    $lastnode = mysql_result($query, 0);
}
// $lastnode is het id van de laatste pagina

[ Voor 8% gewijzigd door T-MOB op 01-07-2004 09:49 ]

Regeren is vooruitschuiven


Acties:
  • 0 Henk 'm!

  • chuxiej
  • Registratie: Februari 2001
  • Laatst online: 13-07-2020
Waarom gebruik je in plaats van foreach() for() ?
Heb je hier een speciale reden voor ? want volgens mij is foreach veel makkelijker en scheelt code.

En ja was foutje van mij node_parent ipv node_child ;)

www.dannyhiemstra.nl


Acties:
  • 0 Henk 'm!

  • T-MOB
  • Registratie: Maart 2001
  • Laatst online: 14:27
chuxiej schreef op 01 juli 2004 @ 11:20:
Waarom gebruik je in plaats van foreach() for() ?
Heb je hier een speciale reden voor ? want volgens mij is foreach veel makkelijker en scheelt code.
Omdat ik de eerste node over wil slaan (laat de for beginnen bij 1 ipv 0). Met foreach kun je dat natuurlijk ook voor elkaar krijgen, maar ach: er zijn meer wegen naar rome ;)

Regeren is vooruitschuiven

Pagina: 1