Posts by FangorN

    Is dit een call to action richting beheerders? Moeten beheerders vervolgens zelf handmatige stappen doorlopen zoals updates selecteren en op een installeer- of update-knop drukken?


    Als er niets te melden valt of wanneer beheerders verder geen invloed kunnen uitoefenen op dit proces dan zou ik hun (initieel) niet lastig vallen met boodschappen. In het laatste geval stel je hun namelijk voor een voldongen feit: "Update xyz geinstalleerd", als je elke keer dit soort boodschappen moet gaan wegklikken -of simpelweg lezen omdat ze op je scherm getoond worden-, dat gaat snel vervelen.


    En wanneer het handmatige updates zijn, hoe zorg je er dan voor dat de updates in de goede volgorde plaatsvinden? Het lijkt mij dat er ook afhankelijkheden tussen updates zitten?


    Ik heb een tijdje gewerkt met Magento, en wat daar gebeurt vond ik wel goed werken, al is het niet heel erg gebruiksvriendelijk, maar het doel lijkt mij het attent maken op updates.


    Enerzijds wordt er op een soort "backend frontpage" de openstaande "notificaties" getoond met een "mate van ernst", meestal gerelateerd aan security (low, medium, high ofzo). Hiermee geef je ook meteen een indicatie of het zaak is dat je direct een ingreep doet, of dat je deze kunt opsparen ofzo.


    Daarnaast is er een apart "notifications" paneel wat in feite ook een soort van changelog /to-update list is. Dit is volgens mij ook de enige plek waar je de notificatie als "gelezen" kunt markeren en/of kunt verwijderen (maar dat helpt je historie eigenlijk om zeep). Dit zorgt er wel voor dat het haast onmogelijk is dat je een notificatie mist, waarbij het eerdergenoemde doel dus wordt bereikt.


    Ik zou eerst eigenlijk kijken of het mogelijk is om (toch) alles volledig te automatiseren zonder het ingrijpen van beheerders, ik neem aan dat die updates toch geinstalleerd moeten worden? Het lijkt mij geen optie om niet te updaten/deels te updaten? De changelog is dan nog steeds een goed idee, omdat je daar een totaaloverzicht hebt (zou je daar in geinteresseerd zijn) die bijvoorbeeld ook zou kunnen aangeven wanneer een update is geinstalleerd.


    Als er geen handmatig ingrijpen van beheerders nodig is (de updates gaan vanzelf) dan zou ik hier geen boodschappen over tonen, ze kunnen hier namelijk helemaal niks mee :). En als ze dan toch willen weten wat er allemaal op de achtergrond gebeurt kunnen ze de changelog raadplegen.


    Of toon een kleine boodschap "Er zijn X updates beschikbaar" die je doorverwijst naar de "changelog" pagina waar je ook de updates kunt installeren / negeren ofzo. (a la Windows Update)


    Of werk met kleuren die aangeven wat de status is van verscheidene onderdelen (a la Norton). Groen = goed, oranje = opletten, rood = aandacht vereist.

    Waar komen $naam, $onderwerp en $email vandaan? Gebruik superglobals ($_POST, $_GET et cetera). Het is niet nodig om variabelen te kopiëren ($naam = $_POST['naam']) en ook niet om deze te unsetten ingeval deze fout zijn.


    De bovenstaande scriptfragmenten zijn in ieder geval nogal wollig. Volgens mij kan dit alles een stuk korter, wat het ook beter leesbaar en makkelijker interpreteerbaar maakt.


    En het zijn fragmenten. Dit is niet het hele script. Vaak is het onhandig als je slechts enkele stukjes aanlevert en dan vervolgens verwacht dat we de hele puzzel oplossen.

    Wellicht is het toch verstandiger om een Version Control System te gebruiken, je hebt dan namelijk ook een historie van vorige versies en wijzigingen. Mocht er dan onverhoopt iets fout gaan als je je code pusht kun je weer terug naar een vorige versie.


    Waarschijnlijk/hopelijk heb je daarnaast al allerlei voorzieningen getroffen die de kans op problemen minimaliseren:
    - continuous integration (push vaak (kleine) wijzigigen in plaats van af en toe mega-updates)
    - backwards compatible ontwikkelen (alle code die je schrijft conflicteert niet met bestaande code maar is (bij voorkeur) backwards compatible)
    - ontwikkel- en testomgeving benaderen zo goed mogelijk de productie-omgeving (platform, versies van gebruikte technologieën et cetera)


    @MiCa- interessant idee, maar ik weet niet of het handig is dat wijzigingen automatisch gepusht worden naar live; zelfs al heb je hiervoor een aparte (master) branch, mogelijk moet je voordat je iets live zet toch al dingen handmatig regelen, dus het moment dat updates binnen komen wil je wellicht zelf bepalen. Daarnaast is er na afloop (als het goed is) ook een zekere controle of alles goed is overgekomen. Het zou niet echt een goed idee zijn om je wijzigingen te committen en er dan maar vanuit te gaan dat alles goed staat op productie :s.

    Apple software heeft volgens mij niet zo'n beste reputatie.


    Daarnaast, je hebt een OS met unicode support, maar een case insensitive filesysteem. Sure, je kunt een case sensitive variant installeren maar iedereen raadt dit volgens mij met klem af, omdat dan niet geganradeerd is dat alle software nog goed werkt.


    Doe je het bijna helemaal goed en dan...


    * cues in Alanis Morissette - Ironic *

    Het is altijd een goede zaak als er actief ontwikkeld wordt aan een community-site.


    Ik heb nog wel twee suggesties:
    1. Op dit moment zijn -naar mijn mening- codeblokken nogal slecht leesbaar. Linewrapping leest echt niet fijn, mogelijk is het een verbetering als je regels niet wrapt maar je overflow op scroll zet? Daarnaast lijken leading spaties gestript te worden. Dit lijkt mij niet de bedoeling? Daarmee help je effectief enige opmaak (inspringen) in code om zeep :/. Ter vergelijking: bekijk deze pagina eens (met name de codeblokken) en maak het scherm horizontaal eens heel klein. De code overflowt dan. Ondanks het feit dat je heel weinig (horizontale) ruimte hebt, is deze code nog steeds redelijk goed leesbaar. Op deze website leest code lang niet zo fijn naar mijn mening. Gewrapte code ziet er toch een beetje uit als een treinbotsing :D.
    EDIT: hey, op lagere resoluties gebruik je wel overflow, waarom niet altijd?


    2. In het verleden heb ik dit wel eens eerder gemeld geloof ik; als ik een tijdje mijn browser (Firefox) open heb staan en dan probeer een reactie te typen in de dialoog waar ik nu ook aan het typen ben, dan zorgt iets ervoor dat ik een enorme cursor-lag heb. Mijn CPU-usage begint naar verloop van tijd (enorme) pieken te vertonen, waarschijnlijk allerlei JavaScript processen die op de achtergrond aan het pollen zijn ofzo. Nu zit ik meestal achter mijn laptop -die al weer enigszins gedateerd is-, maar om in deze dialoog te kunnen typen moet ik echt serieus geregeld mijn browser opnieuw opstarten (ik kan anders simpelweg niet typen), dat lijkt mij niet helemaal de bedoeling. (edit: mijn suggestie is dus om dit -als duidelijk is dat dit iets is wat aan jullie kant op te lossen valt- te verhelpen :))

    Hier een voorbeeld van een toevoegen / wijzigen formulier.


    En hieronder alle code die hier voor nodig is (ook de opbouw die gebruikt wordt voor paginaopbouw en -routing, dat voert eigenlijk al verder dan het formulier zelf):


    Als je formuliersysteem een beetje slim in elkaar zit hoef je dingen niet dubbel te doen.


    EDIT: omg, wat doet dit forum met ingesprongen regels :/. Bleeeehhhh. Beter om dit te copy pasten in een apart bestand, want dit is zo onleesbaar geworden.


    Chrome stript zelfs spaties :/. wtf.


    Nota bene, als je een process pagina ververst dan krijg je een error 500 pagina te zien omdat er dan een exception wordt geproduceerd omdat je CSRF-token niet meer bestaat. Normaal wordt je vanaf de process-pagina altijd ergens naartoe doorgestuurd volgens het POST / redirect / GET principe.

    Twee punten:
    (OVERHEAD) Ik denk niet dat als goederen zo vaak van handen wisselen tussen bron en eindbestemming dat de tracking zo soepel zal gaan :). Als ergens het stokje (de tracking van het overdragen) vergeten wordt door te geven in deze estafette...


    (KWALITEIT, KWANTITEIT) Mogelijk zie je dit ook al in Nederland: de postbezorging is een soort van free-for-all-when-you-want feest geworden, het is een loterij wanneer een verzending aankomt. Beter is om één, of zo min mogelijk (professionele) partijen de bezorging te laten verrichten.


    Het is overigens ontwrichten ;).

    Uhm, houdt dit in dat je voor elk nieuw formulier een nieuwe validation check moet schrijven? Dat lijkt mij een beetje zonde van het programmeerwerk.


    Hier een schematische aanpak van hoe ik een formulier opzet:


    Vervolgens heb ik een print() methode om het formulier (de HTML code) te genereren en af te drukken, een initialize() methode om het formulier te initialiseren met eerder ingevulde waarden. Daarmee verloopt het invoeren van nieuwe entries (ADD) en het wijzigen van bestaande entries (EDIT) op precies dezelfde wijze, hiervoor hoeft geen code bijgeschreven te worden.


    Bij het opslaan roep ik $form->validate() aan die alle velden afloopt, die vervolgens weer alle "rules" inspecteert. Als alles ok is retourneert deze methode een array met de gevalideerde data. Dit gebeurt altijd op dezelfde wijze, dus hier is ook nooit nieuwe/aparte code voor nodig.


    De enige code die ik dus hoef te schrijven voor het maken van een formulier is:
    - de definitie van het formulier zelf
    - de afhandeling van de verwerking


    De rest is al (eenmalig) geschreven. Dit is wat ik bedoelde met "het volgen van een handige opzet" zodat:
    - de code die je moet schrijven voor het opzetten van een formulier minimaal is
    - het weinig tot geen inspanning kost om wijzigingen of toevoegingen aan het formulier te doen; als ik een veld wil bijvoegen prik ik een addField() methode bij en pas ik de verwerking aan, dat is in < 5 minuten gepiept en ik hoef dit niet uitgebreid te controleren (al kan een test geen kwaad natuurlijk) omdat dit systeem modulair is opgezet met klassen. Het enige moment dat je echt uitgebreid moet testen is als je nieuwe formulier-element-typen gaat bouwen.


    EDIT: ik zal morgen eens een voorbeeldje posten, en de code die ik daarvoor moet schrijven.

    Het bovenstaande is dus onderdeel van een soort van formuliersysteem ofzo?


    Een formuliersysteem kan een krachtig middel zijn mits deze goed is opgezet, je kunt dan zeer snel (standaard) formulieren (bestaande uit standaard componenten) opzetten.


    Ook zul je moeten definiëren wat een "formulierveld" omvat. Dit kan best verder voeren dan een inputveld of selectbox. Met wat fantasie (en wat JavaScript) kun je met standaard elementen complexere formuliervelden bouwen die je vervolgens aan je formulier (object) kunt ophangen via een vaste methode (addField(naam, type, instellingen)).


    Denk bijvoorbeeld aan een multiselect (hoe vaak ben jij de instellingen van een enkele select met meerdere selecties kwijt geraakt doordat je de Ctrl-toets niet inhield?):


    Of een simpele teller:

    Of een change password veldpaar:


    Of een access control list opgebouwd uit geserialiseerde predicaten in Poolse (prefix) notatie (shameless self-plug):


    (dit gebruik ik echt voor mijn rechtenmanagement :)).


    Ik zou hiervoor wat classes in het leven roepen (denk aan Form, FormField (abstract), de verschillende FormField spinoffs (de concrete formuliervelden)) en de veld-specifieke validaties onderbrengen bij deze velden zelf. Wanneer je de invoer van het formulier wilt valideren loop je door deze velden heen en roep je de validatie-methoden aan die je hebt ingesteld.


    Het kan trouwens best voorkomen dat één veld méérdere validatieregels heeft, bijvoorbeeld een textveld zou je de validatieregels "verplicht" en "email" kunnen geven. Hiermee geef je aan dat dit veld ingevuld moet worden, en tevens een e-mailadres moet zijn. Je hoeft dus niet voor elk type veld een nieuwe FormField child klasse in het leven te roepen - je kunt ook een specifiek veldtype (in dit geval een text-input veld) hergebruiken door hier nieuwe validatieregels voor te schrijven.

    @MiCa- ik denk dat je in je Security class een aantal zaken op één hoop gooit die niet echt met elkaar te maken hebben.


    Jouw class verzorgt enerzijds output escaping middels de xssEscape() methode en anderzijds zit hier functionaliteit in die middels een token-constructie de kans op CSRF kleiner maakt (maar niet uit sluit).


    Toegegeven, het heeft allebei met security te maken, maar het zijn wel twee compleet verschillende dingen. Ook zie ik niet helemaal waarom je een object van de Security class zou moeten maken? Waarom geen static helper methodes? getToken() ga je ook niet zo vaak gebruiken omdat je een page-request verder bent als je tokens uit $_POST en $_SESSION gaat vergelijken?


    Daarnaast zitten hier naar mijn mening twee (kapitale) fouten in:
    - je escapet hier input; het devies is filter INPUT, escape OUTPUT. Ik ben het eigenlijk wel eens met de stelling dat het op voorhand escapen van input een slecht idee is; wat als je dadelijk deze data wilt bewerken? Moet je dan de omgekeerde bewerking uitvoeren? Of er vanuit gaan dat er overal braaf is ge-escaped aan de invoerkant? Je voert ook strip_tags op de input uit, je gooit dan op voorhand al zaken weg; ook is de toestand van de data in je database niet heel erg duidelijk: is de xssEscape() al overal uitgevoerd? hoe kun je dit garanderen? Nee, het lijkt mij een veeeeeeeeeel beter plan om je data gewoon rauw op te slaan in je database en deze standaard niet te vertrouwen (het blijft user input), bij het afdrukken van deze data gebruik je pas functies zoals htmlspecialchars(); dit is wat bedoeld wordt met escape OUTPUT; tenzij het geauthenticeerde gebruikers zijn die je vertrouwt die deze data invoeren en/of wanneer je echt HTML wilt afdrukken (iets wat je met jouw insteek ook niet gaat bereiken); deze toepassing zal dan expliciet gedocumenteerd moeten worden (de reden dat je niet escapet) Maar dan moet je wel je opties openhouden en niet op voorhand het kind met het waswater weggooien


    - je roept htmlspecialchars() aan zonder de belangrijkste parameters! Je stelt geen flags in, dit is default ENT_COMPAT | ENT_HTML401 terwijl de "veiligste" variant ENT_QUOTES is (daarbij moet je er zorg voor dragen dat je HTML correct is en waarden van attributen tussen "dubbele quotes" staan; Daarnaast, en nog veel belangrijker, dit vormt haast de spil in output escaping in verschillende contexten (database, HTML), is: je specificeert geen character encoding; pas vanaf PHP 5.4 is dit standaard UTF-8 (daarvoor niet!), maar het lijkt mij veel veiliger om geen enkele ruimte voor eigen interpretatie open te laten en dit soort zaken altijd expliciet in te stellen; ik zeg het nogmaals: output escaping werkt alleen goed als alles omtrent character encoderingen klopt als een bus, anders kun je simpelweg niet garanderen dat je output escaping goed werkt!


    Twee statische helper functies (generateToken() en escapeHtml() of iets dergelijks) volstaan dus prima ter vervanging van bovenstaande class.


    @MBCompany ik zou eerder meer zorg besteden aan code die errors/exceptions voorkomt (die dus tegen een stootje kan / robuust is) dan investeren in uitgebreide error handling / logging.

    Dus neem aan dat sql injection niet meer mogelijk is...

    Dat is een misverstand, daarnaast, er vanuitgaan dat je "veilig bent" is het do... onveiligste wat je kunt doen.


    PDO maakt gebruik van prepared statements. Dit houdt in dat je de variabele DATA-delen in een query indirect invoegt via de bindParam() of bindValue() methoden, of meegeeft als argument van je execute() statement.


    Als je dit omzeilt door rechtstreeks data in te voegen in je SQL-string (denk bijvoorbeeld -maar niet uitsluitend- aan data afkomstig uit $_POST of $_GET) dan omzeil je daarmee de spelregels van prepared statements en is het nog steeds zeer goed mogelijk dat er SQL injectie plaatsvindt.


    Soms is het bovenstaande (het niet via bindParam() / bindValue() / execute invoegen van DATA) noodzakelijk, omdat er geen andere manier voor is. Dan is het zaak dat je je invoer controleert op toegestane waarden (je vergelijkt dit dus met een "whitelist").


    Verder is het zaak dat je character encoderingen op orde zijn. Je output (HTML pagina), je broncode (bij voorkeur ook), de connectie met je database, de tabel- en kolomtypen van je database en de data in de database zelf dienen alle dezelfde character encoding te hebben. Dit verdient de sterke voorkeur omdat er dan geen vertalingen uitgevoerd hoeven te worden, er geen verwarring kan ontstaan welke CE iets zou moeten hebben, en de kans op het corrupt raken van data geminimaliseerd wordt.


    Daarnaast, en misschien nog veel belangrijker, kun je er alleen vanuit gaan dat je output escaping (dit is o.a. wat via prepared statements gebeurt) goed werkt mits je character encoderingen goed zijn ingesteld. Dit is een noodzakelijke voorwaarde.


    Dan stopt het beveiligen van je website(s) niet bij het enkel escapen van de invoer. De data in je database is nog steeds voor een groot deel user input. Vertrouw nooit user input. Wat je dus ook moet doen als je data weer afdrukt op je scherm is deze escapen omdat hier mogelijk HTML, JavaScript of andere ongein in zit wat weer andere inbraakmogelijkheden beschikbaar maakt (cross site scripting et cetera).


    Een algemeen devies is nog steeds filter input, escape output. Daarnaast moet je security niet zien als één enkele ondoordringbare muur die je ergens opwerpt, en verder niets meer beveiligt "want de muur is toch ondoordringbaar". De beste manier van beveiligen is werken met (meerdere) lagen.


    En wat kan ik doen aan :
    catch(PDOException $e){ echo $e->getMessage();}

    Zorgen dat heel je applicatie met exceptions werkt, en niet enkel je database. Vervolgens zet je één (of meer) try-catch blokken om je hele applicatie heen en bepaal je afhankelijk van het type gebruiker wat er moet gebeuren. Bijvoorbeeld een developer / IP-adres van de ontwikkelende partij ziet exceptions direct op het scherm, een bezoeker ziet een nette foutpagina of iets dergelijks.


    Ook moet je je het volgende realiseren: PDO is niet geschreven voor gebruik van een specifieke database. Dit heeft tot gevolg dat PDO op voorhand niet (optimaal) is geconfigureerd voor gebruik van database-type X.


    PDO heeft meerdere drivers voor verschillende database-typen. Ik neem aan dat je van plan bent om PDO te gebruiken om met MySQL-databases te communiceren? Het eerste wat ik zou doen is je verdiepen in de PDO_MYSQL driver. Het is een misconceptie om te denken dat PDO makkelijk is. Sure, je hebt een handjevol methoden die je (her)gebruikt, maar daar zit ook niet de leercurve. Deze zit in het je eigen maken van een correct gebruik van de driver(s) die je gebruikt.


    En dan nog iets over exceptions, ik denk dat je rekening moet houden met het volgende: een exception treed op als er iets onverwachts gebeurt. Maar dat houdt niet per se in dat je de exception dan en daar moet afhandelen met een catch-blok.


    Bij het opzetten van je MySQL-connectie via PDO kun je aangeven hoe fouten afgehandeld moeten worden (middels de parameter PDO::ATTR_ERROR_MODE PDO::ATTR_ERRMODE). Als je (in het algemeen) gebruik maakt van exceptions dan stel je de deze parameter in met de waarde PDO::ERRMODE_EXCEPTION. Dit zorgt ervoor dat als er een fout optreedt dat er (naast het instellen van errorcodes) een exception wordt gegenereerd.


    Exceptions moeten opgevangen worden, als dit niet gebeurt wordt er een fatal error geproduceerd. Wanneer je dus een applicatie hebt waarin exceptions worden gebruikt en dus kunnen optreden zal er dus ergens een try-catch blok moeten staan. Dit kun je bijvoorbeeld doen op applicatie-niveau. Als er op het database-niveau iets misgaat, dan hoef je niet per se een database-exception op dat niveau af te handelen als dit maar ergens in een bovengelegen laag gebeurt. Met het genereren van een exception zeg(t) je (code) in feite: "Ik weet niet wat ik hiermee aan moet, kan iemand dit mij vertellen?". Ergens moet er een antwoord op deze vraag gedefinieerd zijn.

    Met die instellingen heb ik geen problemen in Directadmin.
    Dit zou kunnen liggen aan sommige instellingen ervan. Maar valt wel op te lossen...

    Ook als deze instellingen geregeld moeten worden via httpd.conf of equivalent (waar je dus op shared hosting niet bij komt)?

    Iets wat ik compleet ruk vind aan DA is dat deze een aantal URL-paden lijkt te claimen (zoals /config, /icons, /error (had met deze laatste ook problemen geloof ik) en mogelijk meer). Ik weet niet of dit out-of-the-box instellingen zijn of dat mijn hoster verzonnen heeft dat dit handig zou zijn.


    Deze paden zijn ook niet aan te passen als je op shared hosting zit (als ik mijn hoster mag geloven, tis allemaal moeilijk danwel onmogelijk om dit te veranderen omdat dit allemaal aan de serverzijde geregeld dient te worden).


    Ik kan hier echt niet bij, je beheerpaneel zou onafhankelijk moeten kunnen opereren van je website en vice versa.

    ik denk dat je me verkeerd begrijpt mijn latin1 coalaties in velden zijn meestal gwn int, decimal, float of date velden wrbij ik soms ook gewoon true of false doorspeel a.h.v. een int value.

    Euh, ik denk niet dat het wat uit maakt wat voor collations je geeft aan numerieke of date(time)velden. Numerieke velden volgen (uiteraard) een numerieke sortering, en date(time) velden (die in wezen string velden zijn geloof ik) volgen deze door hun opbouw en karaktergebruik in wezen ook. Collations gaan over het matchen en de sortering van textuele velden.


    Zoals ik al eerder aangaf is het waarschijnlijk niet verstandig om uit te gaan van een default, het is gewoon verstandiger om zelf expliciet een character encoding in te stellen, veel ondubbelzinniger dan dat wordt het niet.


    Je zou als volgt (zie ook het eerdergenoemde artikel) een vlugge check uit kunnen voeren met twee functies:


    Aan de MySQL-kant de functie HEX(). Deze retourneert de hexadecimale waarde van (een getal of) een string.


    Aan de PHP-kant de functie bin2hex(). Deze converteert binaire data naar een hexadecimale representatie. Merk hierbij op dat PHP strings ziet als simpelweg "byte sequences" (dit is dus in feite binaire data).


    Het mooie van deze functie is is dat deze character encoding unaware zijn, oftewel, het maakt niet uit van welke character encoding je gebruik - de vertaling is altijd hetzelfde.


    DE TEST
    Staat ook min of meer beschreven in het artikel: haal met een query een tekstkolom op, en tevens de HEX() waarde van deze tekst. Zorg uiteraard dat er wat "exotische" karakters in zitten, anders maakt het allemaal niet zoveel uit (standaard ASCII karakters hebben in de meeste character encoderingen dezelfde representatie op byte-niveau).


    Vervolgens druk je de tekst af, de HEX()-variant van deze tekst (eventueel opgedeeld in leesbare regels met chunk_split() ofzo) en tevens de bin2hex() variant van de tekst (ook hier kun je weer een chunk_split() gebruiken om eea leesbaar te maken).


    Als de HEX()-variant AFWIJKT van de bin2hex() variant (afgezien van uppercase/lowercase dan he) dan wil dit zeggen dat MySQL voor jou een vertaalslag heeft uitgevoerd omdat er ergens een verschil in character encoderingen is geconstateerd.


    Wanneer deze twee verschillen dan heb je een GROOT PROBLEEM, al is dat niet direct evident.


    Persoonlijk vind ik de stellingname "in mijn applicatie werkt alles, dus ik ga niets repareren" niet heel erg goed verdedigbaar (te meer omdat je niet weet of je data wel goed is geformatteerd). Stel bijvoorbeeld dat jij data (met tekst uiteraard eh) uit een tabel ergens anders moet importeren waar alles wel goed is geconfigureerd, dan gaat dat naar alle waarschijnlijkheid niet vliegen. Je (corrupte) data is op voorhand niet meer compatibel met andere systemen.


    Of uitwisseling van data via webservices? Of dus in het algemeen: wanneer je data deelt. Je kunt wel doen alsof iets UTF-8 is, maar als dat niet het geval is dan komt dat snel genoeg naar buiten (denk maar aan RSS feeds).


    Just because something works, does not make it right.


    Het minste wat je kunt doen is nagaan of alles klopt, dat is namelijk op dit moment nogal onzeker, en nog beter zou zijn om (eerst te testen en vervolgens) expliciet een CE in te stellen.


    Je kunt nu in ieder geval niet meer zeggen dat je hier niet(s) van (af) wist :).

    ik zou echter wel UTF8 kunnen gaan gebruiken maar mijn database is voornamelijk latin1_swedish_ci

    latin1_swedish_ci is een collation, geen character encoding! Dit zijn twee verschillende dingen.


    De collation is de manier waarop karakters worden vergeleken (wanneer zijn symbolen gelijk) en gesorteerd (welke symbolenreeks komt alfabetisch voor een andere symbolenreeks bij het sorteren op een tabelkolom).


    De character encoding bepaalt de manier waarop symbolen op byte-niveau worden opgeslagen (lees: ge-encodeerd). Twee teksten op je scherm die dezelfde symbolenreeks weergeven kunnen compleet verschillende character encoderingen hebben.

    PDO zorgt ervoor dat de charset toegewezen in de database waarden van het veld automatisch worden gebruikt.

    Het is altijd beter om expliciet in te stellen wat een character encoding zou moeten zijn, in plaats van er van uitgaan dat een default de juiste character encoding selecteert of automagisch raadt. In het geval deze aanname / verwachting niet klopt / uitkomt heb je potentieel (op termijn) grote problemen.


    EDIT: Ik denk dat je het als volgt moet zien. Met het aanroepen van set_charset() maak je in wezen een afspraak met je database. Hierin:
    - beloof je enerzijds informatie aan te leveren in de afgesproken character encoding (en je database gaat hier ook van uit)
    - tracht je database anderzijds data terug te geven in deze character encoding (waarbij de database een oprechte poging doet om vertalingen uit te voeren indien deze nodig zouden zijn)


    Als je deze afspraak zelf niet expliciet maakt, weet je simpelweg niet wat er afgesproken is met je database! Ook als de data niet op de juiste manier wordt aangeleverd of de data niet op de juiste manier in de database staat opgeslagen is de kans zeer groot dat er een spraakverwarring ontstaat wanneer er data wordt weggeschreven of opgehaald, vaak met desastreuze gevolgen.

    ik houd mijn standaard (niet HTML of geen speciale karakters) velden liever in latin1.

    Ik denk dat je jezelf daarmee tekort doet. Tegenwoordig is UTF-8 volgens mij wel de de facto standaard. Daarnaast beperk je jezelf enorm qua "beschikbare karakters" want de letterbak van latin1 is nogal klein, die van UTF-8 is vele malen groter. Strict genomen is latin1 volgens mij ook geen standaard, UTF-8 wel.

    EDIT: daarbij zit ook mogelijk nog de complicatie dat (de oorspronkelijke) UTF-8 data mogelijk gelezen wordt als latin1, dus mogelijk wordt je data hierdoor extra door de mangel gehaald. MySQL voert wel de "omgekeerde bewerking" uit wanneer deze weer wordt uitgelezen maar de data in je database is in wezen corrupt.

    Dit heb ik nog even nagekeken en zoals ik dacht/vreesde/eigenlijk al wist ga je dit niet oplossen met een simpele utf8_decode() nadat je je _set_charset() goed hebt ingesteld ofzo.


    Je kunt dus ook niet zomaar terugschakelen naar de juiste charset in de communicatie met je database omdat de DATA in je database eerst gerepareerd moet worden. Je zit nu in wezen met latin1-encoded-data-in-een-utf8-database, beter bekend als "de gebakken peren" :).


    Dit kan nog meevallen als je helemaal geen speciale karakters in teksten hebt zitten, dus als de karakters in je DATA het normale ASCII-repertoire niet ontstijgen dan is mogelijk geen conversie nodig, maar als je een knettergrote database hebt dan wordt het wellicht lastig om hier garanties voor af te geven (better safe than sorry).


    De omschakeling naar de juiste charset is ook het moment dat je de conversie moet uitvoeren zodat je een "clean break" hebt tussen latin1-encoded-data-in-een-utf8-database (die je dus gaat repareren) en nieuwe data die er mogelijk (na de omschakeling) weer bij gaat komen (waarvan de encodings wel kloppen). Je bent eigenlijk helemaal genaaid als kloppende en niet-kloppende data door elkaar loopt, want wat moet je dan converteren? Dan zou je per tabel moeten vaststellen wat wel en wat niet geconverteerd dient te worden.


    En dan de conversie zelf. Die is nog niet zo makkelijk. Indien je geinteresseerd bent heb ik daar een artikeltje over geschreven (shameless self plug). Scroll naar de paragraaf "How to fix utf8 tables with latin1 encoded data".


    LET WEL HEEL GOED OP HET VOLGENDE: Het allereerste wat er moet gebeuren is HET MAKEN VAN EEN GRONDIGE ANALYSE van wat er in jouw geval aan de hand is! Het kan heel goed zijn dat er in jouw situatie hele andere dingen aan de hand zijn. Mogelijk is je connectie en DATA in orde, maar geef je in je Content-Type header of metatag geen, of niet de goede character encoding door. Ook kun je al in de situatie verzeild zijn geraakt dat je DATA zowel kloppende als corrupte records heeft.


    Hopelijk is iedereen (die dit leest) nu wat beter doordrongen van het belang van kloppende / in lijn zijnde character encoderingen want niemand zit waarschijnlijk op zo'n conversietraject te wachten waarin je je corrupte data fixt, hiervoor zul je namelijk je applicatie / website tijdelijk offline moeten halen voor publiek om te garanderen dat dit allemaal goed verloopt (en daarvoor zul je uitgebreid moeten testen of de conversie lukt, backups moeten maken et cetera).


    Ik hoef waarschijnlijk niet uit te leggen wat downtime weer voor consequenties kan hebben (onbereikbare site, mogelijk omzetverlies, reputatieverlies etc.).


    VOORKOMEN > GENEZEN

    Of maak eerst een soort van functionele spec (waar wil je dit voor in gaan zetten, wat moet het allemaal doen en kunnen) en bepaal dan welke technische oplossing je gebruikt.


    Oftewel: je gereedschap hangt af van de klus.


    Je kunt ook besluiten om zelf iets simpels in elkaar te zetten.

    Nog geen problemen ondervonden met men beiden classes, ook heb ik nog andere data classes met ook weel functies en ze doen het allemaal prima, ik voorkom in mijn script wel meerdere connecties maar het gebruik van meerdere data objecten lijkt mij geen problemen te geven, vooral bij een project waar maar 1 database word gebruikt.

    Dit komt omdat MySQL zelf ook redelijk intelligent is - deze voert automatisch vertalingen uit.


    Voorbeeld: je hele website is UTF-8 en ook je MySQL database-tabellen zijn utf8, echter bij het maken van een connectie stel jij geen character encoding in. MySQL gaat wellicht van een andere default (bijvoorbeeld latin1) uit. Als jij dan iets wegschrijft naar een tabel ziet MySQL "Hee, mijn connectie is latin1, maar mijn tabel is utf8, laat ik deze data omzetten naar utf8". Maar als je je data al aangeleverd had als utf8 (immers, je website was al UTF-8), dan staat nu je data DUBBEL GE-ENCODEERD (EDIT: dit klopt niet helemaal, in wezen is je data nu gewoon corrupt) in je tabel. Dit merk je wellicht in eerste instantie niet, omdat als je data weer opvraagt vanuit MySQL, dan constateert MySQL "Hee, mijn connectie is latin1, maar mijn data is utf8, laat ik deze weer terugvertalen". Je gaat dan weer terug van een dubbele naar een enkele UTF-8 encodering en daarom LIJKT het goed te gaan.


    EDIT: daarbij zit ook mogelijk nog de complicatie dat (de oorspronkelijke) UTF-8 data mogelijk gelezen wordt als latin1, dus mogelijk wordt je data hierdoor extra door de mangel gehaald. MySQL voert wel de "omgekeerde bewerking" uit wanneer deze weer wordt uitgelezen maar de data in je database is in wezen corrupt.


    Wanneer je de manier van communiceren met je database repareert openbaren deze problemen zich pas. Dan lijkt het mij handiger dat je op voorhand overal dezelfde character encoderingen hanteert. Dit is ook efficienter, want MySQL hoeft niets te vertalen.

    ERROMODE_EXCEPTION heb ik erbij geplaatst om geen SQL error maar een standaard message weer te geven bij een mislukte database verbinding.

    Dat snap ik, maar de syntax van setAttribute() is setAttribute(OPTIE, WAARDE). Wat jij doet is op de plek van een OPTIE (nog) een WAARDE invullen. Om te bereiken wat jij probeert te doen zul je dus zoiets moeten doen:

    PHP
    // stel via de optie PDO::ATTR_ERROR_MODE de waarde PDO::ERRMODE_EXCEPTION in
    $this->con->setAttribute(PDO::ATTR_ERROR_MODE, PDO::ERRMODE_EXCEPTION);

    Hoe stel je voor om mijn data class te gaan schrijven om slechts 1 data object te gebruiken voor al mijn functies ?

    Dat stel ik niet voor, ik stel voor om één instance van DBConfig te creeren die (op een manier) "globaal" (lees: overal) op te vragen is zodat je deze als parameter mee kunt geven bij creatie van je data-objecten. Objecten zijn call-by-reference, dus er wordt niets gedupliceerd. Dit lijkt mij stukken efficienter dan in elk data-object een nieuwe instance creeren van de DBConfig class (ook al wordt onder water van dezelfde fysieke database-verbinding gebruik gemaakt omdat je DSN overal hetzelfde is).


    Je geeft dus in de __construct() methode van je UserDAO class een (eerder -en eenmalig- aangemaakt) object van de klasse DBConfig() mee als parameter in plaats van dat je dit object creeert in de __construct() routine zelf. Volgens mij is dit een voorbeeld van dependency injection, waarmee het mogelijk / makkelijker wordt om "losse koppelingen" te maken. Dit in tegenstelling tot hardcoded definities, zoals nu het geval is.


    Nu ik er over nadenk, ik snap niet helemaal waarom UserDAO extend van DBConfig?