seo vriendelijk met PHP

Door josvane op zondag 3 juni 2012 20:30 - Reacties (16)
Categorie: -, Views: 7.354

SEO vriendelijke URL
Wellicht voor vele bekend, je hebt een hobby en probeert dit steeds groter en vooral beter aan te pakken. Naast dat ik het dus erg leuk vindt om te racefietsen is een van de andere dingen waar ik van kan genieten het bouwen van een CMS.

Doorgaands (eigenlijk altijd) maak ik gebruik van PHP en MySql dit alles wordt af en toe ondersteund door Jquery. Persoonlijk ligt de uitdagingen altijd om een mooi maar vooral functioneel te programmeren. Met mooi bedoel ik dan voornamelijk het design. Naarmate ik meer ben gaan programmeren stijgt ook de drang om de code ook netjes te maken. Dus niet rouwe code achter el elkaar, maar gecommentarieerde code, en uiteraard gebruik makend van OOP.

Het CMS heeft zijn weg inmiddels gevonden naar een aantal klanten/vrienden van mij. Belangrijk om te weten is dat ik het nooit commercieel verkocht heb, en dat is ook helemaal niet mijn intentie.

Voor mijn eigen websites maak ik natuurlijk ook gebruik van mijn eigen CMS. Het huidige CMS is geschreven in PHP en maakt gebruik van PEAR, met daarbij de modules DB en DataObject. Juist van de laatste module heb ik nu spijt. Dit is een drama om op andere systemen werkend te krijgen. Vooral als de desbetreffende hoster DataObject er niet op wil zetten. De template wordt beheerd met Smarty. Dit met als doel om een terugkerend patroon zoals formulieren en tabellen universeel te laden.

Op de websites zelf wordt er gebruik gemaakt van SEO vriendelijke url’s. Dus: www.example.com/over/contact

Dit principe wil ik nu ook gaan gebruiken voor mijn CMS, hier loop ik nu tegen problemen aan. De opbouw van url betekend niet altijd hetzelfde. Waar op de website zelf het patroon altijd hetzelfde is, dus www.example.com/catagorie/subcatagorie is dit in het cms wel anders. Tenminste zoals ik het nu zie.

Een basis frontcontroller heb ik al. Deze code heb ik overigens niet volledig zelf geschreven.

Bron: http://www.pfz.nl/wiki/frontcontroller/

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
class FrontController 
{ 
    function __construct () 
    { 
        global $path_length,$root_path;
        if ($_SERVER['REQUEST_URI'] != '/') 
        { 
            /*
            * Maak van de url een array
            */
            $parts = explode ( '/', strtolower ( trim ( $_SERVER['REQUEST_URI'], '/' ) ) ); 
            /*
            * Folder en index.php uit de array halen
            */
            for($i = $path_length; $i < count($path); $i++) 
            {
                $v = $path[$i]; 
                $parts[] .= $v; 
            }
            switch(count($parts))
            {
                case 0:
                    /*
                    * Standaard waardes als er niets ingegeven wordt
                    */
                    $controller = 'dashboard';
                    $action = 'index';
                    $vars = array('home');
                    break;
                
                /*
                * Alles groter als 2
                */
                default:
                    $controller = (current($parts));
                    /*
                    * Alles anders dan custom_handling naar content.php
                    */
                    if (!file_exists ( $root_path . $controller . '.php' ))
                    {
                        $controller = 'dashboard';
                        $action = 'index';
                        /*
                        * Rest van array door de pagina af handelen
                        */
                        $vars = $parts;
                    }
                    else
                    {
                        $controller = ( current ( $parts ) ) ? array_shift ( $parts ) : 'dashboard';
                        $action = (current ( $parts ) ) ? array_shift ( $parts ) : 'index';
                        /*
                        * Rest van array door de pagina af handelen
                        */
                        $vars = $parts;
                    }
                    break;
            }
            
        } 
        else
        {
            $controller = 'dashboard';
            $action = 'index';
            $vars = array('home');
        }
        $this ->dispatch ( $controller, $action ,$vars); 

    } 
    
    
    function dispatch ( $controller, $action, $vars = null) 
    {
            global $full_path;
            /*
            * Het verwachtte bestand bestaat 
            */ 
            require_once ( $full_path . $controller . '.php' ); 
            
            $controllername = ucfirst ( $controller ); 

            /*
            * Controleren of de controller bestaat
            */
            if ( class_exists ( $controllername ) ) { 
                if ( in_array ( $action, get_class_methods ( $controllername ) ) ) { 
                    /*
                    * Als de functie bestaat dan uitvoeren
                    */
                    $controllerobject = new $controllername(); 
                    
                    $controllerobject->$action($vars); 
                    /*
                    * Na uitvoering afsluiten
                    */
                    return; 
                } 
            }
        /*
        * Als de functie niet bestaat in ťťm van custom_handlers uitzondering dan naar 404
        */ 
        $error = 'Verkeerde parameters. Ongeldige controller. Vier nul vier, dus';
        $this->show_404($error);
    } 
    
    function show_404($error = null)
    {
        global $vars;   
        /*
        * Zelf bepalen hoe mij 404 er uit ziet
        */
        $this->template = new TemplateSystem('error.phtml');
        $smarty = $this->template->smarty;
        $smarty->assign('error', 'Not Found');
        $smarty->assign('data', 'De pagina kon niet gevonden worden. Klik <a href="http://www.eijsdentelecom.nl">hier</a> om terug te gaan.');
        $this->template->display();
    }



Om duidelijk te blijven onderstaande url als voorbeeld, waarbij je moet bedenken dat mijn CMS een menu boven heeft en een menu aan de linkerzijde. Bovenin het met keuze als bijvoorbeeld websites, webshops en dashboard. Het linkermenu kan bijvoorbeeld bevatten websites beheren, menu beheer, afbeeldingen beheren e.d.
http://www.example.com/level_1/level_2/level_3/level_4/level_5

level_1 = grove keuze (websites,webshops e.d.)
level_2 = fijne keuze (website beheer, content beheer e.d.)

level_3, level_4 en level_5 kan meerdere dingen doen.
Bijvoorbeeld een overzicht opvragen van alle sites gesorteerd op naam
http://www.example.com/websites/beheer-websites/naam/asc

een website bewerken zou er dan zo uit moeten zien.
http://www.example.com/websites/beheer-websites/edit/1

Het idee is dus dat de url binnen het cms ook seo vriendelijk wordt. Het biedt natuurlijk geen voordelen voor bijvoorbeeld google, maar het toont gewoon erg netjes.

De vraag is dus ook zijn er andere mensen die dit probleem opgelost hebben of kunnen we werken aan een breed gedragen systeem die universeel ingezet kan worden, voor allerlei andere systemen.

Het is dus duidelijk niet mijn bedoeling om het CMS gezamenlijk te schrijven, puur en alleen de frontcontroller.

Nou is dit een vraag die ook had kunnen stellen op het forum, maar juist wil ik de discussie op gang brengen om te zien hoe andere dit doen, en wellicht het zover schoppen om het algemeen beschikbaar te stellen van de techniek.

Volgende: Verder met PHP 08-'12 Verder met PHP
Volgende: Gehackt, het is ook nooit goed, 04-'12 Gehackt, het is ook nooit goed,

Reacties


Door Tweakers user X_lawl_X, zondag 3 juni 2012 20:33

Ik denk dat de meeste mensen gewoon gebruik maken van een framework. Overigens moet je geen global vars gebruiken.

Door Tweakers user ACM, zondag 3 juni 2012 21:34

En het is ook niet heel erg aan te bevelen om zonder inputvalidatie (desnoods domweg ctype_alpha($controller)) je files op disk te aan te spreken met een user-parameter.

Door Tweakers user T.H. Lassche, zondag 3 juni 2012 21:41

Ik zou twee lagen diep gaan: Je eerste request arg map je naar de controller, de tweede naar de bijbehorende methode. De overige request arg's geef je mee aan de methode als argument. Zo wordt het in de meeste MVC's gedaan.

Dit komt elke keer terug:

PHP:
1
2
3
$controller = 'dashboard'; 
$action = 'index'; 
$vars = array('home');


Wat mij betreft wil je dit uit een config halen, of uit een class constant.

Verder inderdaad je input checken.

[Reactie gewijzigd op zondag 3 juni 2012 21:44]


Door Tweakers user josvane, zondag 3 juni 2012 21:56

Thanks iedereen voor de ideŽn

@x_lawl_x
Wat is een alternatief voor global?

@ACM
Wat dient dat voor als ik op http://php.net/manual/en/function.ctype-alpha.php kijk dan voorkomt dit alleen cijfers.
Niet dat ik functies heb met cijfers maar verhoogt dit de veiligheid en zo ja waar?

@T.H. Lassche, klinkt logisch en voor een deel doe ik dit ook al, maar de eerste 2 items zetten ook mijn menu's op actief. Hoe kan ik dit dan aanpakken. Zou het beter zijn om vanuit de methode te bepalen welk menu een css active class krijgen?

Door Tweakers user ACM, zondag 3 juni 2012 22:03

Of je cijfers wilt kunnen gebruiken of niet maakt me niet zo uit, maar je wil vooral niet dingen als .., / en $ enzo binnenkrijgen ;)
Kortom, je wil alleen een variabele krijgen die precies voldoet aan jouw eisen, niet een die in een onvoorziene corner case ineens ander gedrag veroorzaakt.

Door Tweakers user josvane, zondag 3 juni 2012 22:05

Okey duidelijk

Door Tweakers user curvemod, zondag 3 juni 2012 23:06

Met T.H. Lassche, ik zou die 'default routes' idd in een config file verwachten. Verder is het gebruiken van globals gewoon geen goed idee, dus eruit smijten die hap :)

Misschien dat je voor je frameworkje ook eens gebruik kan maken van Symfony 2 componenten zoals HTTPFoundation, HTTP Kernel en Routing. Daar zit een hoop nuttige functionaliteit in (http://symfony.com/components).

Fabien Potencier (van Symfony 2) heeft ook een nuttig artikel hierover geschreven, misschien dat je daar wat aan hebt http://fabien.potencier.o...ymfony2-components-part-1

Bottom-line: Cool dat je hieraan begonnen bent, IMO kan je er enorm veel van leren en het is erg leuk om te doen! Probeer alleen wel goed te zoeken op het internet, zodat je niet overal zelf het wiel voor hoeft uit te vinden. Succes!

Door Ronald, maandag 4 juni 2012 00:28

Naarmate ik meer ben gaan programmeren stijgt ook de drang om de code ook netjes te maken
Ik raad je aan om hier wat literatuur over te lezen
zie bijvoorbeeld 'clean code'

je schrijft bijvoorbeeld dat je je code 'netjes documenteerd',
Het idee achter netjes programmeren is dat dit juist niet zoveel meer nodig is, wanneer je je code begrijpbaar hebt geschreven.

Voorbeeld:
  • een methode of function mag nooit meer dan 7 a 8 regels code bevatten (een clean code regel die in jouw voorbeeld behoorlijk wordt overtreden)./li]
  • magic strings (wat is bijvoorbeeld: $v)/li]
Geloof me, dit is leuke stof om te lezen

maarre.... keep up the good work :-)

Ronald

Door Tweakers user curvemod, maandag 4 juni 2012 08:31

Ronald schreef op maandag 04 juni 2012 @ 00:28:
een methode of function mag nooit meer dan 7 a 8 regels code bevatten (een clean code regel die in jouw voorbeeld behoorlijk wordt overtreden)
Volgens mij is dit niet erg praktisch, dan ben je constant bezig om alles op te splitsen om dit niet te overtreden. Het is een leuke guideline, maar ik zou hier persoonlijk niet te veel waarde aan hechten (ťn ja, ik heb het boek gelezen :))

Door Tweakers user Afvalzak, maandag 4 juni 2012 08:37

jhuiting schreef op maandag 04 juni 2012 @ 08:31:
[...]

Volgens mij is dit niet erg praktisch, dan ben je constant bezig om alles op te splitsen om dit niet te overtreden. Het is een leuke guideline, maar ik zou hier persoonlijk niet te veel waarde aan hechten (ťn ja, ik heb het boek gelezen :))
Je moet het ook niet te letterlijk nemen maar de code onder de switch zou ik zelf graag onderverdelen in functies.
Maar het is aan een ieder om het op zijn manier te doen;)

Door Tweakers user curvemod, maandag 4 juni 2012 08:47

afvalzak schreef op maandag 04 juni 2012 @ 08:37:
[...]
Je moet het ook niet te letterlijk nemen maar de code onder de switch zou ik zelf graag onderverdelen in functies.
Mja daar ben ik het mee eens hoor, maar ik denk dat je dit soort guidelines beter pas wat later bij hem kan introduceren omdat er nu veel belangrijkere dingen zijn wat hij aan het leren is. Plus dat ik 7/8 lines wel erg weinig vind, daar ga je bijna met iedere functie overheen IMO.

Door Tweakers user sfranken, maandag 4 juni 2012 12:00

Tip:
Doe het met .htaccess en zet in je front controller dit:

$args = $_GET['args'];

Via $args kun je daarna eindeloos doorgaan. VOorbeeld:

voorbeeld.nl/key1/value1/key2/value2/enz/2

Door Tweakers user -RetroX-, maandag 4 juni 2012 13:35

een hele reeks args in je url heeft natuurlijk niets met seo te maken. Een zoekmachine heeft er erg weinig aan als je een url hebt die je voor algemene zaken danwel class/controllers gebruikt. Bijvoorbeeld voor /account/cart/item/edit & /account/cart/item/delete

ook voor weergave opties moet je even goed nadenken. Want wat heeft een url als dit voor zin?:
/products/category/sampleproducts/page/3/sort_size/asc/sort_delivery/asc/filter_size/123/filter_weight/346/

Door Tweakers user Lemming, maandag 4 juni 2012 17:34

-RetroX- schreef op maandag 04 juni 2012 @ 13:35:
een hele reeks args in je url heeft natuurlijk niets met seo te maken. Een zoekmachine heeft er erg weinig aan als je een url hebt die je voor algemene zaken danwel class/controllers gebruikt. Bijvoorbeeld voor /account/cart/item/edit & /account/cart/item/delete

ook voor weergave opties moet je even goed nadenken. Want wat heeft een url als dit voor zin?:
/products/category/sampleproducts/page/3/sort_size/asc/sort_delivery/asc/filter_size/123/filter_weight/346/
Zoiets heb ik idd vaker gezien :P
Bij mijn spul is het:
nieuws: http://adres.tld/catogorie/id/?argumenten
webapps: http://adres.tld/actie/?argumenten (hoewel ik haast nooit GET gebruik maar bijna altijd POST)

Door Tweakers user skabouter, maandag 4 juni 2012 19:01

* Alles groter als 2
:'(

Door Tweakers user phex, maandag 4 juni 2012 19:11

Zoals ik het nu zie kun je elke klasse aanspreken en uitvoeren.


PHP:
1
2
3
4
class Setup {
    public function deleteAll() {
    }
}



Dus: http://localhost/setup/deleteall/
en poef alles weg.

Anyway, ten eerste zou ik gebruik maken van abstract of interfaces. Controleer of de controller die je aanspreekt ook een instance van de interface is.

Daarnaast alle globals eruit gooien en gebruik maken van private vars


PHP:
1
2
3
4
5
6
7
class FrontController implements ControllerInterface {
    private $queryArgs;

    public function __construct() {
        var_dump($this->queryArgs);
    }
}




Ook zie ik dat je een error krijgt als iets niet klopt. Hierbij zou je kunnen kijken naar exceptions zodat je kan filteren wat er fout gaat, ipv direct een 404 te laten zien (die de error message niet overneemt? :S). Is wel zo gebruiksvriendelijk.
Zeker als je focussed op SEO, lijkt mij een 404 nog het laatste resultaat dat je wil geven aangezien die pagina dan niet geÔndexeerd wordt.

Ook zou ik de 404 in de abstract of in een losse klasse zetten. Mocht je een 404 tegenkomen in een andere klasse wil je niet de stack aflopen om de FrontController aan te spreken om een 404 te kunnen tonen.

[Reactie gewijzigd op maandag 4 juni 2012 19:21]


Reageren is niet meer mogelijk