Zend Framework Documentation: Constants for General Date Functions (reformatted)
Oké, was er klaar mee. De documentatie van Zend Framework is prima maar de pagina met Zend_Date constants is gewoon onmogelijk. Misschien dat ze hem in de toekomst wat mooier maken maar voor nu hier de 'quick & dirty' hackoplossing: zend_date_reformatted.html
Niets spannends. Gewoon wat breder, hier en daar wat paddings en wat zebrastreepjes voor de leesbaarheid. Enjoy!
Office 365: Aliases, Outlook Web App & Outlook 2010
Veel mensen maken gebruik van e-mail aliassen welke geen aparte mailboxen dienen te krijgen maar wel mails moeten verzenden. Een voorbeeld hiervan is bijvoorbeeld een kleinere organisatie waarbij de eigenaar vanaf zowel info@ als vanaf zijn persoonlijke adres wil mailen maar wel alles centraal in één mailbox wil ontvangen. Dit is in Office 365 te configureren middels distributiegroepen en wat configuratie via de powershell. Voor dit voorbeeld gaan we even uit van de situatie van een info@ mailbox en een henk@ voor de eigenaar.
Office 365 panel
Allereerst richten we een normale mailbox in voor henk@domeinnaam.nl. Ik ga er even vanuit dat dit geen probleem vormt verder. Daarna maken we via het panel een distributiegroep aan voor de gewenste alias. In dit geval dus info@domeinnaam.nl. Als identiteit geven we deze groep de naam 'info_domeinnaam_nl' zodat we hem makkelijk kunnen herkennen in de Powershell (mocht dat nog nodig zijn in de toekomst). We maken gebruiker 'henk' eigenaar en lid van deze groep zodat alle mails verzonden aan dit adres naar zijn mailbox toe worden gezonden. Wel een belangrijk punt van aandacht: Vergeet niet aan te vinken dat deze distributiegroep vanaf 'onbekende' adressen gemaild mag worden, standaard staat hij namelijk geconfigureerd als een box voor intern gebruik waarbij alleen bekende mailadressen welkom zijn.
Powershell
Via de powershell gaan we nu gebruiker 'henk' rechten geven om te verzenden namens de distributiegroep. Dit doe je met het volgende commando:
Add-RecipientPermission "info_domeinnaam_nl" -Trustee "henk" -AccessRights SendAs
Outlook Web App & Outlook
De outlook Web App is nu in principe klaar voor de nieuwe situatie. Bij het opstellen van een nieuw bericht kun je bij het kopje 'opties' een vinkje zetten voor het veld 'van weergeven' zodat je kunt kiezen namens wie je wilt mailen. Als je wilt wisselen tussen de verschillende afzenders (in dit geval dus henk@domeinnaam.nl en info@domeinnaam.nl) dan klik je op het 'van' veld en krijg je een lijstje met verschillende afzenderopties. Dubbelklik en bevestigen en je verzend nu namens een andere naam.
Outlook op de PC/Mac is wat lastiger op dit vlak. Normaliter is het niet mogelijk mail te versturen via een mailbox die niet is aangemaakt als mailaccount. Omdat het een distributiegroep betreft is het erg lelijk hem altijd te tonen. Voor nu zijn er echter geen echte opties voor, alleen 'workarrounds'. Enkele mogelijkheden zijn;
- De distributiegroep ook als POP3 account aanmaken naast je normale exchange identiteit in Outlook zodat je nu ook kunt verzenden namens deze mailbox
- Het niet erg vinden dat er 'verzending namens' komt te staan in je mails (dit krijg je als je in Outlook het 'van' veld activeert en een afzender gebruikt die niet als account is aangemaakt)
- Toch ervoor kiezen losse gebruikers ervan te maken
Firefox freezes
De afgelopen weken had ik een diepgaand conflict met mijn Firefox. Om onduidelijke redenen bleef hij soms tientallen keren per dag om onheldere redenen 'hangen'. Bijvoorbeeld als je klikte ergens op een pagina of 'view source' deed. Mijn eerste veronderstelling was dat er misschien extensies of plugins waren die de boel verstoorden. Als fervent Firefox liefhebber en als webdeveloper heb je vaak toch al snel aardig wat onmisbare tooltjes (Firebug, Web developer, Delicious bookmarks en ShowIP om maar iets te noemen). Mijn eerste poging op weg naar herstel van een gezonde werkomgeving was het uitschakelen van alles wat ik maar kon missen en meer. Ik was overtuigd dat dit de oplossing was maar dit bleek niet het geval. Zelfs zonder enige plugin of extensie deed hij vervelend.
En toen?
Aangezien er nooit tijd is voor dit soort 'problemen', ik in enkele weken mijn pc wil herinstalleren en ik Opera ook het beste gun dacht ik 'ik kan best een paar weken met Opera gaan werken en wie weet bevalt het wel'. Opera geupdate, alternatieven voor mijn favoriete Firefox plugins gezocht en de meest belangrijke tabjes toegevoegd als 'app' (sinds ik dit ontdekt heb in Firefox is dit echt een primaire levensbehoefte geworden). Voor de meeste zaken waren prima alternatieven. Zo heeft Opera een geweldige, ingebakken, developer omgeving (Dragonfly, niet gezien? Zeker eens testen). Met mijn visie dat iets wat standaard in software zit ingebouwd altijd beter is dan iets wat je los installeert leek me dit het testen waard (en beviel me prima trouwens). Maar hoe sexy Opera ook was, hoe prettig Dragonfly ook was, ik miste mijn vertrouwde Firefox. Keer op keer opende ik toch automatisch weer Firefox om iets te testen en voor mijn geliefde Delicious extensie kon ik geen waardig alternatief vinden. Daar ik een trouw Delicious gebruik ben (ca 350 links) miste ik deze heel erg. Alles wat ik tegenkom tijdens onderzoek en belangrijk vindt wil ik in mijn Delicious stoppen. Kort samengevat; Opera is fantastisch maar ik mis Firefox.....
Op zoek naar een oplossing
Een beetje googlen bracht mij bij een weblog wat me hoop gaf. Ik was sowieso niet de enige en er was misschien een oplossing. Het zou namelijk kunnen komen door een verstoring van de database van Firefox die soms in een soort loop zou schieten. Vol goede moed de instructies gevolgd en vol verwachting mijn browser herstart maar helaas, de problemen waren niet weg.
Firefox 8 beta
Bij gebrek aan verdere opties, en bij het vinden van veel meer mensen met soortgelijke 'vage' klachten, toch maar even getest of het draaien van Firefox 8 beta dit op zou lossen. Dit bleek in mijn geval de oplossing. Ben er niet heel gelukkig mee dat ik op mijn primaire werkomgeving met een beta versie werk maar het werkt 100x beter dan Firefox 7 deed dus ben er blij mee. Mocht jij soortgelijke problemen hebben dan zou ik adviseren om eerst de poging te doen met het weblog. Beter een herstelde versie 7 dan een 8 beta lijkt me zo. Als het bij jou ook niet werkt dan is Firefox 8 beta dus een mogelijk goede oplossing.
CSS3 box shadow en Internet explorer <9
Nu CSS3 steeds meer onderdeel wordt van het dagelijks leven blijf je altijd weer met Internet explorer zitten. Alle meestgebruikte versies ondersteunen een hoop leuke CSS3 zaken niet. Vandaag was mijn irritatiepuntje de box shadow. Ik wilde deze met zo min mogelijk moeite werkend krijgen in IE zonder allerlei ingrepen. Nu zijn op zich de meeste zaken wel mogelijk zoals positieve, of negatieve offsets door middel van Microsoft filters. Alleen ik wilde een drop shadow langs alle kanten. Dit leek me zo voor de hand liggend maar het heeft me toch even gekost voor ik enige zinnige implementaties en voorbeelden hiervan had gevonden.
Ik heb voor het gemak even 3 heldere voorbeelden van drop shadows uiteen gezet met CSS code erbij (-webkit, -moz, CSS3 tag zelf en IE alternatief).
Resultaat in Internet explorer 8
Het resultaat in Firefox
Klik hier om de demo te bekijken
Een stap verder
Er zijn nog leukere mogelijkheden maar die vergen iets meer verdieping. Zo kun je bijvoorbeeld met een extra div voor de shadow om je primaire div heen ook nog gekkere dingen doen. Op css-tricks.com staat dit heel helder uitgelegd.
Office 365: Shared mailbox license required
Als Office 365 fans hebben wij de laatste tijd al een hoop gespeeld met de configuratie. Een probleem wat terug blijft komen (en ook erg veel terug te vinden is op het internet) is de vreemde werking van shared mailboxes in combinatie met licenties. De documentatie van Microsoft geeft op meerdere plaatsen zeer helder aan dat een shared mailbox geen licentie nodig heeft. Alleen gebruikers die deze mailbox willen openen moeten een licentie hebben (en mogen geen kiosk-account hebben).
Wat gaat er mis?
Stel je beschikt over een standaard P1 account en je maakt via de powershell een shared mailbox aan. Het lijkt een redelijke tijd goed te gaan maar ergens gaat het bij een hoop gebruikers fout als ze via de OWA proberen de mailbox te benaderen. Je krijgt dan een error ivm. te weinig toegekende licenties. Het rare is sowieso dat hij wel werkt via bijvoorbeeld Outlook 2010 en mails komen er ook gewoon in.
Na gisteren een ruim uur met een zeer vriendelijke medewerker van Microsoft dit probleem te onderzoeken heb ik zojuist als test een gedeelde mailbox opnieuw aangemaakt. Eerder had ik namelijk een beetje soep gemaakt van de mailboxen door ze ook als een user via het Office 365 admin panel aan te maken.
Mogelijke oorzaken
Omdat het via Outlook wel werkt maar via de OWA niet krijg je al vraagtekens. Wie heeft er gelijk en via welke route gaat er gewoon iets mis in het bepalen van licenties. Mijn eerste idee zou zijn dat de OWA een onjuiste manier gebruikt om de licenties te controleren. Waarom anders zouden er zoveel mensen zijn met dit probleem en er geen concrete oplossingen zijn nog. Het lijkt meer een bug dan een echt licentieprobleem te zijn. Daar de Microsoft medewerkers al enkele keren tussen neus en lippen hebben aangegeven dat zij denken dat Office 365 te snel gelanceerd is en nog best wat kinderziektes bevat ga je nog meer in deze richting neigen. Maar tot Microsoft een oplossing heeft wil je natuurlijk nadenken hoe dit probleem mogelijk kan worden omzeild. Enkele theorieen over waarom deze licentieproblemen getriggerd worden zijn:
- P1 licenties hebben geen security groups (zoals in de E licenties wel het geval is)
Als hier de oorzaak zit kan het nog wel eens lastig worden dit ooit werkend te krijgen - Standaard krijgt een shared mailbox normale quotas mee terwijl hij licentievrij maar 5 GB mag zijn
Zou eenvoudig oplosbaar moeten zijn maar denk niet dat dit het probleem geeft. - Standaard wordt er met het maken van een mailbox ook een useraccount gemaakt in het Office365 panel
Wat lastiger verhaal maar zou wel logischer zijn inzake het probleem via OWA. OWA loopt over de "office365 lagen" terwijl je lokale Outlook direct op Exchange rechten niveau werkt
Oplossingen?
Nog niet echt al denk ik ook dat dit meer een applicatie probleem is dan een configuratieprobleem aan de gebruikerskant. Ik zal de komende tijd in iedere geval alles kritisch in de gaten houden en nog wat tests uitvoeren en mocht het probleem zich niet meer voordoen bij specifieke configuraties dan zal ik hier zeker een nieuwe blogpost aan wijden.
WordPress style save confirmation
WordPress heeft bij het bewerken of aanmaken van een nieuwe blogpost een melding die je om bevestiging vraagt als je probeert de pagina te verlaten zonder iets op te slaan. Nooit echt bewust over nagedacht maar leek me een leuke toevoeging qua user experience in een nieuw project. Even een beetje nagedacht hoe ik dit in mijn Jquery wereld kon "opbergen" zonder dat het in de weg zou zitten en kwam met de volgende oplossing;
// Set the default state to false
jQuery.data(document.body, 'confirmationPrompt', false);
// On a keypress in any form field set confirmation to true
$('input,textarea').keypress(function() {
jQuery.data(document.body, 'confirmationPrompt', true);
});
// On change of a select or any other form element (like radio buttons etc)
// Set confirmation to true
$('input,select').change(function() {
jQuery.data(document.body, 'confirmationPrompt', true);
});
// On any form submit set confirmation to false
$('form').submit(function() {
jQuery.data(document.body, 'confirmationPrompt', false);
});
// Check if confirmation is needed before unloading
window.onbeforeunload = function(){
if(jQuery.data(document.body, 'confirmationPrompt')){
return 'Are you sure?';
}
};
Dit dekt op zich aardig de lading zo. De reden dat ik jquery.data() gebruik en niet gewoon een losse variabel is dat ik op deze manier ook vanuit andere functies de confirmationPrompt var op false kan zetten. Bijvoorbeeld als je sommige forms middels een AJAX call opslaat waardoor er geen formele form submit voorbij komt.
Zend Form security (basics)
Ook bij een "gesloten" applicatie kun je nooit teveel doen aan de beveiliging van je formulieren. Voor een "standaard" omgeving wil je in iedere geval basisbescherming opzetten tegen;
- Formulier spam
- Fake/overmatige form posts
- Ongewenste gegevens
Met Zend Framework heb je op zich al best wat leuke mogelijkheden tot je beschikking voor het valideren en filteren van inputvelden en een stukje bescherming tegen CSRF.
Formulier spam
Voor een eenvoudige site zal een spammer niet veel moeite doen. Enige wat je wilt is een drempel die het voor "standaardscripts" onmogelijk maakt je systeem te vervuilen en tegelijkertijd niet teveel werk is om te implementeren. Een mogelijkheid is het toevoegen van een veld wat je met CSS (of JavaScript) verbergt voor normale gebruikers en wat "false" is als deze een waarde bevat. Een normale gebruiker die geen CSS en JavaScript heeft aan staan is zeldzaam maar mocht die toch voorkomen dan kun je die eventueel met een label nog informeren over het feit dat dit een veld is speciaal om spambots uit te sluiten.
Fake/overmatige form posts
Zend_Form_Element_Hash biedt hiervoor op zich in basis een goede bescherming tegen. Bij het aanmaken van je form neem je een veld op met het type "hash". Dit veld kun je van parameters voorzien zoals een timeout etc. Bij het aanmaken van het form maakt Zend een session aan met deze hash erin. Bij de post van het form wordt deze gevalideerd tegen de hash. Als hij verlopen is geeft de form isValid false terug. Hier zit wel gelijk een "let op!" momentje in; als je in je structuur ergens de ongelukkige setup hebt waarbij het form meerdere keren gevalideerd wordt zal deze bij de 2e ronde false geven op deze hash.
Hieronder een simpele setup voor dit element in je form:
$this->addElement('hash', 'csrf_hash', array(
'salt' => 'justSomeRandomSalt',
'timeout' => 600,
));
ps. de documentatie op de Zend Framework website is niet erg diepgaand op dit vlak. Als je in de broncode van de Form/Element/Hash.php kijkt zie je dat er meer parameters zijn die je mee kunt geven.
- setSalt($salt)
String met salt. Geef je niets mee dan gebruikt hij standaard de string "salt" - setSession($session)
Zend_Session_Namespace $session als je zelf een session wilt meegeven. - setTimeout($ttl)
Int met timeout welke standaard op 300 staat.
Ongewenste gegevens
Hoe ver je hiermee gaat hangt een beetje van de aard van de data af, de plek waar het form zit (publiek of besloten) en of de data bijvoorbeeld naar een database gaat of alleen gemaild wordt naar een persoon. Tevens laat ik hierin de beveiliging van de opslag, verzending of wat dan ook van de data buiten wegen. Het gaat me nu even puur om de formulier-afhandeling.
Met Zend_Filter en Zend_Validator kun je krachtige combinaties maken welke de data strippen op alleen het nodige na en het resultaat hiervan valideren. Stel je hebt een select veld:
$this->addElement('select', 'is_lovingchocolate', array(
'label' => 'Do you love chocolate?',
'multiOptions' => array(
1 => 'Yes',
0 => 'No',
),
'filters' => array('int'),
));
Wat je hiermee doet is in iedere geval gelijk de formulierwaarde die terugkomt met de POST typecasten naar INT. Met de verschillende Zend_Filter classes kun je op die manier al heel veel ellende tegenhouden. Als je ingewikkeldere data-patronen hebt kun je ervoor kiezen met eenvoudige Zend_Filters alle ongewenste data eruit te halen om daarna met Zend_Validate_Regex de data tegen een hele strict patroon te matchen.
Een voorbeeld hiervan:
$this->addElement('text', 'zipcode', array(
'label' => 'Zipcode (Dutch notation)',
'required' => true,
'maxlength' => 7,
'validators' => array(
array('NotEmpty', true),
array(
'regex', false, array('/^[0-9]{4} [A-Z]{2}$/',
'messages' => array('regexNotMatch' => 'Incorrect zipcode notation. Should look like 2222 AA.'))
),
),
'filters' => array('StripTags', 'stringToUpper'),
));
Wat we doen met de filters is alles eruit halen wat we nu even niet willen en gelijk de letter naar hoofdletters converteren voor een uniforme dataopslag later. Na deze stap valideren we het resultaat met een reguliere expressie voor de postcode. Even los van het feit of deze expressie aansluit bij jouw idee van een goede postcode maar denk dat het idee wel helder is zo.
Jquery fadeIn loop (supersimpel)
Wilde net even twee blokken met tekst in elkaar laten overlopen. Leek me overkill hiervoor een cycle plugin te gebruiken dus ging even kijken wat voor leuks ik nog niet had toegepast/ontdekt in Jquery. Nu blijkt dat je met delay() functie in combi met fadeIn/out erg leuke dingen kunt doen.
HTML:
<div id="blockHolder">
<div id="block1">Tekst 1</div>
<div id="block2">Tekst 2</div>
</div>
CSS:
#blockHolder {
width: 100px;
height: 200px;
border: 1px solid red;
position: relative;
}
#block1,
#block2 {
background-color: white;
position: absolute;
left: 0;
top: 0;
}
Jquery code:
function fadeLoop(){
$('#block1').fadeIn().delay(3000).fadeOut('slow', fadeLoop).delay(3000);
}
$(document).ready(function() {
fadeLoop();
});
Op zich redelijk basic maar werkt wel leuk zo. Wat de fadeLoop() nu doet is eigenlijk #block1 transparant maken, 3 seconde wachten, weer zichtbaar maken, 3 seconde wachten en weer zichzelf aanroepen voor een herhaling. Dit werkt prima met blokken die over elkaar gepositioneerd staan via CSS en waarbij de voorste transparant/niet-transparant wordt waardoor de achterste zichtbaar wordt.
BMI calculator met Jquery
Voor een project wat nog in ontwikkeling is moest ik een BMI calculator maken. Ik had er ooit wel eens één gemaakt maar die werkte via een POST en 'berekende' alles met PHP. Het leek me leuk dit keer Jquery te gebruiken.
De oude BMI calculator
Zoals je ziet op zich prima maar een beetje statisch. Tevens niet echt superduidelijk. Er zit een 1 px wit lijntje wat je huidige BMI aanduidt maar je moet wel goed opletten om die te zien.
De nieuwe BMI calculator
Zoals je ziet wel wat overeenkomsten (zelfde opdrachtgever dus moest zelfs alles een beetje gelijk houden) maar toch net even wat frisser. Een duidelijkere pointer voor je BMI en in plaats van invulvelden en een submitbutton gewoon twee Jquery UI sliders.
De code
Wat heb je in iedere geval nodig?
- Jquery
- Jquery UI
- Een BMI afbeelding voor de achtergrond
- Eventueel een leuke afbeelding voor de pointer
Voor het gemak kun je het hele gebruikte pakketje voor deze implementatie hier downloaden.
De te includen bestanden in de header
- reset.css
- screen.css
- jquery-ui-1.8.16.custom.css
- jquery.1.6.1.min.js
- jquery-ui-1.8.16.custom.min.js
- bmi.js
De HTML
Dit is de kale HTML voor de slider met tabel etc.
<div id="lengthSlider"></div>
<label for="length">Uw lengte is <input type="text" id="length" /> centimeter</label>
<div id="weightSlider"></div>
<label for="weight">Uw gewicht is <input type="text" id="weight" /> kilogram</label>
<div id="bmiScale">
Uw Body Mass Index is
<div id="bmiScalePointer"></div>
</div>
<div id="bmiInformation">
<h4>Wat is een gezonde BMI?</h4>
<table border="0" cellpadding="0" cellspacing="0" width="500">
<tbody>
<tr>
<td width="10"><img src="</assets/images/bmi-yellow.gif" alt="ondergewicht" height="10" width="10"></td>
<td width="130">Tussen 16 - 20</td>
<td width="240">Uw BMI is iets te laag</td>
</tr>
<tr>
<td><img src="/assets/images/bmi-green.gif" alt="gezond gewicht" height="10" width="10"></td>
<td>Tussen 20 - 25</td>
<td>gezond gewicht</td>
</tr>
<tr>
<td><img src="/assets/images/bmi-yellow.gif'" alt="normaal - licht overgewicht" height="10" width="10"></td>
<td>Tussen 25 – 27</td>
<td>normaal - licht overgewicht</td>
</tr>
<tr>
<td><img src="/assets/images/bmi-orange.gif" alt="normaal - overgewicht" height="10" width="10"></td>
<td>Tussen 27 -29</td>
<td>normaal - overgewicht</td>
</tr>
<tr>
<td><img src="/assets/images/bmi-red-orange.gif'" alt="overgewicht" height="10" width="10"></td>
<td>Boven de 30</td>
<td>overgewicht</td>
</tr>
<tr>
<td><img src="/assets/images/bmi-red.gif" alt="ernstig overgewicht" height="10" width="10"></td>
<td>Boven de 40</td>
<td>ernstig overgewicht</td>
</tr>
</tbody>
</table>
</div>
De Jquery code
De volgende code berekend de BMI, verplaatst de pointer etc.
Zie ook de opmerkingen ertussen.
// Function to calculate the BMI using lenght in centimeters and weight in kilograms
function calculateBMI(lenght, weight)
{
// Calculate the BMI and round at 1 decimal
var result = Math.round(weight / (lenght/100 * lenght/100)*10)/10;
// Determine the left position of the bmiScalePointer (and subtract 50% of it's width)
var leftPos = (result*10)-22;
// If the leftpos is > 450 it would run out of the scale so stop it here
if(leftPos > 450) {
leftPos = 450;
result = Math.round(result);
}
// Update the bmiScalePointer value
$('#bmiScalePointer').html("BMI<br/><br/>" + result);
// Move the bmiScalePointer to it's new position
$('#bmiScalePointer').css('left', leftPos);
}
$(document).ready(function() {
// Just plain Jquery UI slider functionalitiy
$("#lengthSlider").slider({
value: 175,
min: 130,
max: 220,
step: 1,
slide: function( event, ui ) {
// Initiate the calculation function on sliding
calculateBMI(ui.value, $('#weight').val());
$("#length").val(ui.value);
}
});
$("#length").val($("#lengthSlider").slider("value"));
$("#weightSlider").slider({
value: 75,
min: 24,
max: 250,
step: 1,
slide: function( event, ui ) {
// Initiate the calculation function on sliding
calculateBMI($('#length').val(), ui.value);
$("#weight").val(ui.value);
}
});
$("#weight").val($("#weightSlider").slider("value"));
// Do a initial calculation
calculateBMI($('#length').val(), $('#weight').val());
});
Nogmaals voor het gemakt: Het hele gebruikte pakketje voor deze implementatie kun je hier downloaden.




