PHP Namespace

Idag tänkte jag gå igenom PHP Namespace funktionaliteten som kom med PHP 5.3. Om du arbetat med C# eller Java så känner du till konceptet namespace, men för andra icke invigda så är det helt enkelt ett sätt att undvika namn-kollisioner genom att skapa en sorts mapphierarki för namnen, för du kan t.ex. ha exempel.php i två olika mappar men du kan inte ha dom i samma.

Okej, vi tar ett exempel:

namespace A;

class B {
   // 
   function doit() {
      return __NAMESPACE__;
   }
}

\A\doit();

 

 

Installera Composer på OS X

Composer är ett plattformsberoende manager för PHP-bibliotek, den installera paket som man behöver i ett specifikt projekt med ett enda kommando. I denna artikel kommer jag att förklara hur man ska Installera Composer på OS X, och sedan lägga till en alias, så den kan användas från överallt på datorn utan att behöva skriva in den fulla sökvägen vid varje kommando.

 

Installation

Det första steget är så klart att ladda ner Composer, som då samtidigt kommer att skapa en PHP Arkiv (phar) som heter composer.phar.

Öppna terminal appen, och kör följande kommando:

curl -SS https://getcomposer.org/installer | php

 

Installations fel

I vissa fall kan du få följande felmeddelande:

Some settings on your machine make Composer unable to work properly.
Make sure that you fix the issues listed below and run this script again:

The detect_unicode setting must be disabled.
Add the following to the end of your `php.ini`:
detect_unicode = Off

A php.ini file does not exist. You will have to create one.
If you can not modify the ini file, you can also run `php -d option=value` to modify ini values on the fly. You can use -d multiple times.

För OS X 10.8, bör php.ini filen ligga i /private/etc/. Om du inte redan har ett, kan du kopiera den förvalda:

sudo cp /private/etc/php.ini.default php.ini

Därefter, redigera filen genom att lägg till följande:

detect_unicode = Off

Spara filen och kör curl kommandot som installerar Composer ovan.

 

Köra Composer

Den resulterande filen kommer att kallas composer.phar, ett PHP Arkiv som kan exekveras direkt via PHP. Men vi vill att Composer ska vara tillgänglig globalt, så att vi kommer åt den genom att endast skriva composer istället för hela sökvägen. För att göra detta, flytta composer.phar till /usr/bin/ och skapa ett alias för den:

sudo mv composer.phar /usr/bin/
nano ~/.bash_profile

Lägg detta till din .bash_profile. Som kan vara tom eller inte ens finnas, så det är bara att skapa en:

alias composer="php /usr/bin/composer.phar"

Starta om din terminal nu kommer du att kunna komma åt Composer helt enkelt genom att skriva composer i Terminalen. Då får du följande output:

Composer output i Terminal.app
Composer output i Terminal.app

För att installera Composer på Windows kan man bara ladda ner installationsprogrammet Composer-Setup.exe och köra.

 

Så där, det var det. Hoppas att du lärt dig något och till nästa gång koda smart 😉

 

Dynamisk Webbsida Med PHP

Idag ska vi skapa en dynamisk webbsida med PHP och du ska redan kunna en del PHP, HTML och CSS för att få ut det mesta av den här guiden.

 

PHP

PHP står för PHP: Hypertext Preprocessor, och är ett av dom populäraste scriptspråk som körs på webbservrar för att driva webbsidor med dynamiskt innehåll (d.v.s. innehåll som genereras från t.ex. en databas, validering av formulärdata mm.) PHP är ett scriptspråk som tolkas av en interpretator som heter Zend Engine. Man använder PHP tillsammans med HTML och SQL (plus en del andra tekniker) för att generera innehåll.

 

Syntax

Man skriver PHP antingen i egna filer eller så blandar man med HTML. Koden skriver man mellan PHP avgränsare. Skriv in följande i en fil och spara den med filändelsen .php i din webbrot [1]:

<?php
// Detta är en kommentar på en rad, och skrivs inte ut

/*
Detta är också en kommentar, 
men på flera rader
*/

echo 'echo är en så kallad språk konstrukt som skriver ut strängar i webbläsaren'; 

# Detta är också en kommentar på en rad
?>

[1] Webbroten » om du kör WAMP är det C:/WAMP/www/ och för MAMP är det /Applications/MAMP/htdocs/ och för en LAMP (Linux Apache MySQL PHP) installation är det /var/www/html.

Kommentarer syns inte i utskrift och kan skrivas på tre sätt:

  1. på en rad, med hashtag #
  2. på en rad, med dubbla snedstreck //
  3. eller på flera rader, mellan /* och */.

Strängar skrivs mellan enkla eller dubbla citationstecken. Men enkla citationstecken bearbetas snabbare, är säkrare och är mindre benägna att orsaka programmeringsfel i PHP. Det finns dock undantag, som t.ex. om man vill få med en PHP-variabel i utskriften använder man dubbla för att slippa man konkatenera den till strängen (vilket skulle bearbetas saktare), utan kan istälet skriva in den direkt i strängen så här:

$someString = 'sträng';
// om vi echo ut en sträng tillsammans med variabeln använder vi dubbla citationstecken
echo "En PHP-variabel i en $someString";

 

En liten sida

Jag tänkte vi skulle skapa en liten sida och lära oss lite på vägen. Börja med att skapa en PHP-fil och skriva in följande och spara som index.php:

<!doctype html>
<html lang="sv-SE">
<head>
	<meta charset="UTF-8" />
	<title>Dynamisk Webbsida Med PHP | cr8gr8designs.com</title>
        <link rel="stylesheet" href="style.css" />
</head>
<body>
	<div class="menu-wrapper">
		<label for="toggle" class="menu-icon">☰</label>
		<input type="checkbox" id="toggle" />
		<aside class="sidebar-menu">
			<nav class="main-menu">
				<ul>
					<li class="menu-item active"><a href="#">Hem</a></li>
					<li class="menu-item"><a href="#">Portfolio</a></li>
					<li class="menu-item"><a href="#">Galleri</a></li>
					<li class="menu-item"><a href="#">Kontakt</a></li>
				</ul>
			</nav>
		</aside>
	</div><!--  /.menu-wrapper -->
        <section class="main-section">
                <!-- PHP kod ska in här senare -->
        </section>
</body>
</html>

…och en CSS-stilmall, med den här koden:

* {
    box-sizing: border-box;
    -moz-box-sizing: border-box;
    -webkit-box-sizing: border-box;
    margin: 0;
    padding: 0;
    border: 0;
    font-size: 100%;
    font: inherit;
    vertical-align: baseline;
}
 
/* HTML5 display:block reset för äldre webbläsare */
article, aside, details, figcaption, figure, 
footer, header, hgroup, menu, nav, section {
    display: block;
}

body {
	font:100 1rem/150% Futura, 'Avenir Next', Avenir, sans-serif;
	width:100%;
	min-height:1000px;
	background-color:rgb(252,252,252);
}
.sidebar-menu {
    	transition: all 0.4s;
    	-webkit-transition: all 0.4s;
	position:fixed;
	top:0;
	left:-120px;
	z-index:1;
	width:120px;
	height:100%;
	padding:38px 38px 38px 20px;
	background:rgb(20,20,20);
}
.menu-item a {
	font:100 1rem/250% Futura, 'Avenir Next', Avenir, sans-serif;
	color:rgba(255,255,255,.9);
	text-decoration:none;
	display:block;
}
.menu-item a:hover {
	color:rgba(255,100,100,.8);
}
.active a {
	color:rgba(255,100,100,.8);
}
.active a:hover {
	color:rgba(255,100,100,.8);
}
.menu-icon {
	text-decoration:none;
	position:fixed;
	top:20px;
	left:200px;
	font-size:2.5rem;
	color:rgb(0,0,0,.9);
}
.menu-icon:hover {
    cursor: pointer;
}
#toggle {
	display: none;  /*hide */
	
}
#toggle:checked + .sidebar-menu {
	left:0;
}

Nu har vi en startsida som vi kan arbeta med. För att göra sidan dynamisk börjar vi med att modifiera menyn genom att modifiera href attributen så här:

<li class="menu-item active"><a href="?page=hem">Hem</a></li>
<li class="menu-item"><a href="?page=portfolio">Portfolio</a></li>
<li class="menu-item"><a href="?page=galleri">Galleri</a></li>
<li class="menu-item"><a href="?page=kontakt">Kontakt</a></li>

Här lägger vi till en variabel page som ändras beroende på vilken länk man klickar på. Testa att klicka på länkarna och kolla i adressfältet, där du bör se följande:

page variabeln syns i adressfältet när man klickar på menylänkarna
page variabeln syns i adressfältet när man klickar på menylänkarna

Det här kan vi använda oss av eftersom det går att komma åt page variabeln med PHP superglobaln $_GET. Vi kan nu servera innehåll, beroende på vilket värde page variablen har. Vi skapar nya filer i en ny mapp som vi ger namnet templates, där vi skapar fyra nya filer som ska heta:

  1. hem.php
  2. portfolio.php
  3. galleri.php
  4. kontakt.php

I dessa kan vi nu skriva in vad vi vill visa. Du ska få göra det själv då det inte har någon betydelse för guiden, men jag kan visa ett exempel på en mallsida/template:

<div>
    <h1>Välkommen till cr8gr8designs.com</h1>
    <span>Skapad av <a href="mailto:mail@cr8gr8designs.com">Daniel K</a></span>
    <p>
        Front-end och back-end är begrepp som används inom informationsteknik för att beteckna den bearbetning som sker av eller nära användaren (användargränssnittsorienterad bearbetning – front-end) och själva basbearbetningen (ofta på servernivå – back-end).
        I modern datateknik associeras ofta front-end med webbaserade mjukvarumoduler baserade på HTML, CSS och JavaScript, där utvecklarna av dessa delar kallas webbutvecklare eller webbdesigners.
        Sättet att bygga uppdatorsystem enligt front-end och back-end kallas också two-tier architecture. (källa <a href="http://sv.wikipedia.org/wiki/Front-end_och_back-end">Wikipedia</a>)
    </p>
</div>

Vi behöver inte deklarera <doctype html>, <head> och <body> m.fl. då vi redan har grunden i index.php där denna del av sida ska visas. Så, nu skapar vi en sträng som ändras beroende på vilket värde page har. Skriv in följande mellan <section> taggarna:

<section class="main-section">
<?php
// vi deklarerar en PHP-variabel som får värdet från page
// i PHP behöver man inte ange specifik typ för variabler -
// för det sköter PHP automatiskt
$page = $_GET['page'];

// vi skapar en sträng med sökvägen till template fil,
// som ändras beroende på page variabeln, lägg märke till att man konkatenerar -
// strängar med en punkt istället för + som är en annan operator -
// du kan kolla på all här http://php.net/manual/en/language.operators.php
$filename = "templates/" . $page . ".php";

// om filen finns
if (file_exists($filename)) {
    // renderar vi den
    include_once $filename;
} else {
    // annars har page variabeln inte ett värde är
    // och då är användaren på hemsidan eftersom ingen länk ännu klickats
    include_once 'templates/hem.php';
}
?>

Nu har vi skapat en enkel template system som serverar sida beroende på vilken sida användaren är på.

 

Separera Logik & Presentation

Det är dock inte god kodningsstandard att blanda logik och presentation, utan man ska försöka till så stor del som möjligt separera dom. Därför ska vi skapa en ny mapp som heter functions, och däri en PHP-fil som heter likadant:

Mappstruktur
Mappstruktur

Vi flyttar PHP koden från index.php till en funktion i functions.php:

<?php

/**
 * Renderar sidoinnehåll
 * @param string $page
 */
function renderPage($page) {
    $filename = "templates/" . $page . ".php";
    
    // om page har ett värde och filen finns
    if (file_exists($filename)) {
        // renderar vi sidan
        include_once $filename;
    } else {
        // annars visas hemsidan
        include_once 'templates/hem.php';
    }
}

…och så skriver vi inkluderingen av function.php och deklarationen av $page variabeln på toppen av sidan:

<?php
require_once 'functions/functions.php';
$page = $_GET['page']; ?>
<!doctype html>
<!-- och så vidare -->

Okej, nu kan du använda funktionen genom att anropa den, så byt ut all PHP-kod mellan <section> taggarna i index.php mot det här:

<?php
renderPage($page); 
?>

 

Dynamisk Meny

Jag har även satt ihop en funktion som skapar en dynamisk meny. Den använder sig av en kort if sats, och används på det här sättet:

// detta är inte riktig kod utan visar bara hur det fungerar
(villkor ? sant : falskt);

Där villkor kan vara vilken jämförelse  som helst, t.ex. a === b och om det är sant gäller sant och om det är falskt så gäller den sista som här är ordet falskt. Ett praktiskt exempel med båda if-satserna:

if(a === b) {
   echo $c;
}else {
   echo $a + $b;
}

// samma villkorliga sats med den korta varianten

echo ($a === $b ? $c : $a + $b);

Här kommer koden till createMenu() funktionen:

/**
 * Skapar en dynamisk menu som lägger till klassen active på aktiv länk
 * @param array $links -> array() med menylänkar
 * @param type $active -> $_GET['page']
 */
function createMenu($links, $active) {
    // initiera sträng som ska innehålla menyn
    $menu = '<ul>';

    // en foreach loop skapar menyn
    foreach ($links as $link) {
        $menu .= '<li class="menu-item';
        // ange klass för aktiv länk, eller ( || ) om $_GET['page'] inte har ett värde än så är man på hemsidan
        $menu .= ($active === $link || ($link === 'hem' && $active === NULL) ? ' active' : '');
        $menu .= '"><a href="?page=' . $link . '">' . ucfirst($link) . '</a></li>';
    }
    echo $menu . '</ul>';
}

…som används så här:

<nav class="main-menu">
    <?php
    // anropa funktionen med en array av dom länkar man vill ha 
    // och $page variabeln som vi deklarerade på toppen av sidan
    createMenu(array('hem', 'galleri', 'portfolio', 'kontakt'), $page);
    ?>
</nav>

Okej, det var allt för den här gången, och till nästa gång koda smart 😉

Välj inte Payson!!!

Jag gjorde en transaktion med Payson vilket visade sig bli ett riktigt djävla fiasko!

Till att börja med låste dom kontot på morgonen efter att jag valde att flytta över pengarna till mitt bankkonto. Sedan försökte jag få tag på dom varje dag men dom hörde inte av sig. Först ville dom ha ett personbevis för bankärenden, vilket jag skickade in. Sedan skulle dom ha ett köpekvitto där jag signerat och kollat köparens ID-kort och sedan fått dennes underskrift. Detta hade jag inte gjort. Så då väljer dom att se det som ett bedrägeri och makulerar transaktionen.

Dom ber mig kontakta polisen så att jag möjligen ska kunna få tillbaka varan.

Nä, fy fan vad arg jag blir när dom hjälper till att fullfölja ett bedrägeri.

Välj inte Payson!!!

Säker Inloggning med LightOpenID

LightOpenID är ett script som låter en användare identifiera sig genom sitt Google konto (plus ett gäng andra, inklusive OpenID), och vi kommet att jobba med en variant som används tillsammans med PHP (finns för andra språk också). Du kan ladda ner den senaste versionen härifrån. Det går att logga in med flera olika tjänster, som;  är ett väldigt säkert alternativ.

Ett annat alternativ för PHP är ett projektet som använder LightOpenID; HybridAuth vilken använder sig av sociala inloggningar med; OpenID, Facebook, Twitter, LinkedIn, Google, Yahoo, Windows Live, Foursquare och AOL och många fler. Du kan hitta en lista över dom i dokumentationen.

Användaren kommer att refereras till som » A

 

Vi börjar med att skriva in följande i huvudmenyn:

// skriv in det här i din huvudmeny
if (!$_SESSION['email']) {
    // om A inte loggat in än, visa "Logga in" länk
    echo '<li><a href="login.php">Logga in</a></li>';
} else {
    // om A har loggat in visas logga ut i menyn
    echo '<li><a href="logout.php">Logga ut</a></li>';
}

…och nästa steg blir att sätta in följande i din login.php:

// login.php
// skapa en ny instans av LightOpenID, med länk till din webb-rot
$openId = new LightOpenID('http://localhost/~dok/login_google/');

// vi använder oss av Google:s inloggning
// den här adressen hämtas till menyn lite längre ner på sidan
$openId->identity = 'https://google.com/accounts/oB/id';

// här specifierar vi vad vi vill veta => förnamn, email och land 
$openId->required = array(
'namePerson/first',
'contact/email',
'contact/country/home'
);

// och så anger vi en return URL som A ska skickas till efteråt
$openId->returnUrl = 'account.php';
?>

<h1>Logga in på sidan</h1>

<!-- och en inloggningslänk > Länk till Google login -->
<a href="<?php $openId->authUrl() ?>">Logga in med Google</a>

<!-- och en vanlig inloggningsformulär -->
<form action="login.php" method="POST">
    <label for="username">Användarnamn:</label><br />
    <input type="text" name="username" /><br />
    <label for="pass">Lösenord</label><br />
    <input type="password" name="pass" /><br />
    <input type="submit" value="Logga in" />
</form>

…och efter att A har klickat på verifiera med Google och verifierat att A låter oss använda A:s email och namn, skickas A till account.php:

// account.php
require_once 'includes/openid.php';

$openId = new LightOpenID('http://localhost/~dok/login_google/');

if ($openId->mode) {
    if ($openId->mode == 'cancel') {
        echo 'Error: användare avbröt inloggning';
    }  elseif ($openId->validate()) {
        // hämta alla attribut för A som vi fick från Google
        $data = $openId->getAttributes();
        $email = $data['contact/email'];
        $fist = $data['namePerson/first'];
        $homeCountry = $data['contact/country/home'];
        
        // sätt attributen till session variabler
        $_SESSION['email'] = $email;
        $_SESSION['firstname'] = $fist;
        $_SESSION['home'] = $homeCountry;

        // skicka A tillbaka till hemsidan
        header('Location: http://localhost/~dok/login_register/');
    }  else {
        echo 'Error: Användare har inte loggat in';
    }
}  else {
    echo 'Error: Gå till hemsidan för att logga in';
}

…nu skickas A till index.php, och där kollar vi om A loggat in och visar lämplig länk i menyn:

if (!$_SESSION['email']) {
    // om användaren avbröt verifiering visas Logga in
    echo '<li><a href="' . $openId->authUrl() . '">Logga in</a></li>';
} else {
    // logga ut länk visas nu istället
    echo '<li><a href="login.php">Logga ut</a></li>';
}

…och i logout.php ska följande in:

// skapa en session så vi kommer åt alla sessions
session_start();

// "förstör" alla sessions
session_destroy();

// skicka tillbaka till hemsidan
header('Location: http://localhost/~dok/login_register/');

Så där nu ska du kunna komma igång med LightOpenID. Och till nästa gång, koda smart 😉

 

Webbshop med PayPal

Ansvarsfriskrivning – Jag kan tyvärr inte garantera att den här artikeln resulterar i en felfri och säker applikation, och det är därför ditt ansvar att kontrollera din kod mot dokumentationen.

I den här artikeln ska vi skapa en – webbshop med PayPal och applikationen kommer att baseras på Classic API. Som du kanske såg i förra avsnittet av den här serien – Skapa Din Egen Nätbutik, så finns det tre steg i en transaktion på nätet:

  1. Kundvagn > ska samla in information om köpet, som kortnummer, adress, namn mm.
  2. Betalningsgateway > krypterar informationen och skickar den till säljarkonto
  3. Säljarkonto > processar informationen och sätter in pengarna på kontot

Vi kommer att använda oss av PayPal:s säljarkonto i den här artikeln.

 

Utvecklingsprocess

Utvecklingsprocessen för en applikation som använder PayPal:s API, har följande steg:

  1. Registrera dig som PayPal utvecklare.
  2. Integrera PayPal-funktionalitet till din webbplats och eventuella mobila applikationer.
  3. Testa dina PayPal transaktionsrutiner i PayPal:s Sandbox.
  4. Gå live med applikationen.
  5. Underhålla och uppgradera applikationen.

 

 

Skapa Utvecklar-konto

Så, till att börja med behöver du skapa ett utvecklar-konto hos PayPal, och du kan göra det här. Där behöver du sedan skapa autentiseringsuppgifter, vilket du kan se hur du ska göra här. Det finns två typer av autentiseringsuppgifter:

  • Signature API autentiseringsuppgifter
  • Certificate API autentiseringsuppgifter

Båda kan användas men PayPal rekommenderar Certificate av säkerhetsskäl. Båda varianterna innehåller tre autentiserings-värden:

  • API Användarnamn
  • API Lösenord
  • Certifikat

Det är dessa som skickas tillsammans med anrop till PayPal API.

Tänk på! Du måste ha ett PayPal Business-konto för att göra anrop till PayPal:s live servrar.

 

Olika Betalningsalternativ

PayPal har ett antal olika betalningsalternativ och det gäller att välja den som passar bäst för just din sida. Men detta kan vara minst sagt förvirrande, då det finns så många alternativ.

 

  • Express Checkout – Med den främsta PayPal tjänsten: Express Checkout kan du få betalningar utan att ha ett konto och utan att behöva fylla speciella kriterier förutom att verifiera ditt PayPal konto (antingen via ett bankkonto eller ett kreditkort). Tidigare kunde man endast ta Express Checkout betalningar från registrerade PayPal-användare, men PayPal har lagt till en kreditkorts alternativ för icke-PayPal-användare, vilket gör denna tjänst tillgänglig för praktiskt taget vem som helst som har ett av dom större kreditkorten (VISA, MasterCard, osv.)
    • Tänk på: Express Checkout processen sker på PayPals plattform och kan därför aldrig bli helt integrerade i din webbplats användargränssnitt.
  • Direct Checkout – Direktbetalnings metoden gör det möjligt att ta emot kreditkortsbetalningar direkt via ett API-anrop. Detta gör att du kan genomföra hela betalningsprocessen på din webbplats, vilket möjliggör en mer komplett shoppingupplevelse för kunderna.
  • Recurring Payments – Detta gör att du kan ställa in ett återkommande transaktion (dvs. en abonnemangs betalning).
  • Mass Payments – Denna metod gör att man kan föra över pengar till flera konton på samma gång.
  • Adaptive Payments – Här är ett annat API för att skicka pengar till flera mottagare, med vissa skillnader från Massbetalnings API:n.

Listan är inte helt komplett, men den innehåller dom populäraste alternativen (se dokumentationen för fler produkter).

 

 

Att Göra API Anrop

PayPal stödjer två huvudsakliga format över HTTP, nämligen: NVP och SOAP. NVP står för ”Name, Value Pair”, och SOAP står för ”Simple Object Access Protocol”. Jag kommer att använda mig av NVP, eftersom SOAP trots sitt namn har ett relativt komplex syntax.

Var och en a dessav API-metoder har olika parametrar, men de båda delar på vissa grundläggande parametrar, som används för att identifiera API kontot och underteckna transaktionen.

Dessa innefattar:

  • USER Din PayPal API användarnamn.
  • PWD Din PayPal API lösenord.
  • VERSION Versions nummer för NVP API service; 95.0 (som är den senaste vid skrivande stund).
  • SIGNATURE Din PayPal API signatur sträng. Denna parameter är valfri om man använder ett certifikat för autentisering.
  • Den sista parameter som krävs är METHOD, vilken deklarerar den API metod vi anropar.

 

Klass för anrop

Anrop görs över HTTPS. Vi använder cURL för att bygga förfrågan, och kapslar in hela processen i en klass:

<?php

class Paypal {
    /**
     * Sista error meddelande(n)
     * @var array
     */
    protected $_errors = array();

    /**
     * API autentiseringsuppgifter
     * Använd korrekt autentiseringsuppgifter (Live / Sandbox)
     * @var array
     */
    protected $_credentials = array(
        'USER' => 'seller_1227648999_cr8gr8designs.com',
        'PWD' => '1297608792',
        'SIGNATURE' => 'A3g66.FS11HYAf1mkHkkl3BDopE3kN.ddRE1wMrInvUEqO3UaLOvity47p',
    );

    /**
     * API endpoint
     * Live - https://api-3t.paypal.com/nvp
     * Sandbox - https://api-3t.sandbox.paypal.com/nvp
     * @var string
     */
    protected $_endPoint = 'https://api-3t.sandbox.paypal.com/nvp';

    /**
     * API Version * @var string */
    protected $_version = '74.0';

    /**
     * Skapar API förfrågan
     * @param string $method sträng för API metod som ska anropas
     * @param array $params Ytterligare anrops parametrar
     * @return array / boolean Svars array / boolean false vid misslyckande */
    public function request($method, $params = array()) {
        $this->_errors = array();
        if (empty($method)) { // Kolla så att API metod inte är tom
            $this->_errors = array('API metod fattas');
            return false;
        }
        // Våra anrops parametrar
        $requestParams = array(
            'METHOD' => $method,
            'VERSION' => $this->_version
                ) + $this->_credentials;
        // Bygg NVP sträng
        $request = http_build_query($requestParams + $params);

        //cURL inställningar
        $curlOptions = array(
            CURLOPT_URL => $this->_endPoint,
            CURLOPT_VERBOSE => 1,
            CURLOPT_SSL_VERIFYPEER => true,
            CURLOPT_SSL_VERIFYHOST => 2,
            CURLOPT_CAINFO => dirname(__FILE__) . '/cacert.pem',  //CA cert fil 
            CURLOPT_RETURNTRANSFER => 1,
            CURLOPT_POST => 1,
            CURLOPT_POSTFIELDS => $request
        );
        $ch = curl_init();
        curl_setopt_array($ch, $curlOptions);
        // Skicka förfrågan - behåll API respons
        $response = curl_exec($ch);
        // Kolla efter cURL error
        if (curl_errno($ch)) {
            $this->_errors = curl_error($ch);
            curl_close($ch);
            return false;
            //Hantera fel
        } else {
            curl_close($ch);
            $responseArray = array();
            parse_str($response, $responseArray);
            // Break the NVP string to an array
            return $responseArray;
        }
    }
}

Svaret tillbaka kommer att vara i NVP-format, och vi formatera om den till en array innan vi returnerar den.

Parameter ACK innehåller status för förfrågan:

Success

..eller:

SuccessWithWarning

…när förfrågan lyckas, och:

Error

…eller:

Warning

… när förfrågan misslyckas.

En förfrågan kan misslyckas av många anledningar, och det finns många olika skäl för varje API-metod, och dessa beskrivs i detalj i manualen. Vi ska gå igenom sätt att hantera dem lite senare. Kom ihåg att parametervärdena är skiftlägeskänsliga (skiljer på stora och små bokstäver).

 

Express Checkout

En av de mest populära API är Express Checkout, som gör att du kan ta emot betalningar utan att öppna en Website Payments Pro-konto (som endast är tillgänglig för verifierada USA konton) eller hosta själva transaktionen själv (vilket kräver ytterligare säkerhet).

Express Checkout processen fungerar på följande sätt:

1. Vi förfrågar efter en checkout token från PayPal med hjälp av transaktionsuppgifter;
2. Om det lyckas, ska vi omdirigera användaren till PayPal Checkout tillsammans med den mottagna TOKEN.
3. Användaren slutför eller avbryter betalningen på PayPal-plattformen och omdirigeras Tillbaka till Vår hemsida;
4. Vi slutför transaktionen, antingen när användaren omdirigeras tillbaka eller via en Instant Payment Notification (IPN).

PayPal - Express Checkout process
PayPal – Express Checkout process

 

 

 

1. Begär Checkout Token

Vi initiera Express Checkout processen genom att skicka in orderuppgifter till PayPal API, och får då tillbaka en token sträng som identifierar ordern. Denna token ska användas i nästa steg när vi ska omdirigera användaren till PayPal.

Här följer de parametrar som krävs:

  • METHOD
    Detta är API metod som vi använder (dvs. SetExpressCheckout).
  • RETURNURL
    Den URL som användaren kommer att omdirigeras till efter att betalningen är klar.
  • CANCELURL
    Den URL som användaren kommer att omdirigeras till efter att ha avbrutit betalningsprocessen.
  • PAYMENTREQUEST_0_AMT
    Transaktionens totala beloppet. Detta måste ha två decimaler och decimaltecknet är en punkt, och den valfria tusentalsavgränsare måste vara ett kommatecken.
  • PAYMENTREQUEST_0_ITEMAMT
    Den totala kostnaden för objekten i ordning, exklusive frakt, skatter och andra kostnader. Om det inte finns några extra kostnader, så borde det vara samma värde som PAYMENTREQUEST_0_AMT.

Vi kan ange ytterligare parametrar att lägga till mer information om ordern, varav vissa har standardvärden:

  • PAYMENTREQUEST_0_CURRENCYCODE
    Betalnings valuta, en kod på tre bokstäver. Standard är USD, för Svenska kronor är det SEK och du hittar en lista över giltiga koder på sidan Currency Codes i dokumentationen.
  • PAYMENTREQUEST_0_SHIPPINGAMT
    De totala fraktkostnaden för denna order.
  • PAYMENTREQUEST_0_TAXAMT
    Det totala skattebeloppet för denna order. Detta krävs om per-post skatten specificeras (se nedan).
  • PAYMENTREQUEST_0_DESC
    Order beskrivning.

Vi kan även lägga till information om enskilda artiklar i ordern:

  • L_PAYMENTREQUEST_0_NAMEm
    Artikelns namn.
  • L_PAYMENTREQUEST_0_DESCm
    Artikelns beskrivning.
  • L_PAYMENTREQUEST_0_AMTm
    Artikelns kostnad.
  • L_PAYMENTREQUEST_0_QTYm
    Mängden av en artikel

Variableln m identifierar en enskild artikel. (Använd samma variabel för alla detaljer i samma artikel.)

Det finns många andra valfria parametrar, som finns i API-dokumentationen. Vi kommer att använda metoden request() som vi skrev i klassen Paypal, för att bygga anropet till SetExpressCheckout:

// Parametrar till Paypal->request()
$requestParams = array(
    /* URL användaren ska skickas tillbaka till efter slutförd betalning */
    'RETURNURL' => 'http://www.yourdomain.com/payment/success',
    /* URL användaren ska skickas tillbaka till om denne avbryter betalning */
    'CANCELURL' => 'http://www.yourdomain.com/payment/cancelled'
);
$orderParams = array(
    'PAYMENTREQUEST_0_AMT' => '500', 
    'PAYMENTREQUEST_0_SHIPPINGAMT' => '4', 
    'PAYMENTREQUEST_0_CURRENCYCODE' => 'GBP', 
    'PAYMENTREQUEST_0_ITEMAMT' => '496'
);
$item = array(
    'L_PAYMENTREQUEST_0_NAME0' => 'iPhone', 
    'L_PAYMENTREQUEST_0_DESC0' => 'White iPhone, 16GB', 
    'L_PAYMENTREQUEST_0_AMT0' => '496', 
    'L_PAYMENTREQUEST_0_QTY0' => '1'
);
$paypal = new Paypal();
$response = $paypal->request('SetExpressCheckout', $requestParams . $orderParams . $item);

 

2. Omdirigera till PayPal

Om anropet till metoden är framgångsrikt, kommer vi att få en Checkout token som finns i TOKEN parametern av respons-arrayn.

if (is_array($response) && $response['ACK'] == 'Success') {
    // Anrop lyckades 
    $token = $response['TOKEN'];
    // skicka tillbaka användaren
    header('Location: https://www.paypal.com/webscr?cmd=_express-checkout&token=' . urlencode($token));
}

Användaren går nu igenom köpprocessen på PayPals webbplats. När PayPal bekräftar eller avbryter transaktionen, kommer användaren att återvända till en av de webbadresser som vi har angett i förfrågan.

 

 

3. Slutför Transaktion

Förutsatt att användaren bekräftar transaktionen, kommer dom att omdirigeras till vår hemsida genom PayPal. Nu bör vi använda två API metoder: DoExpressCheckoutPayment som kommer att slutföra transaktionen, men innan dess, kanske vi vill kanske få ytterligare information om köparen med hjälp av GetExpressCheckoutDetails.

PayPal omdirigerar användaren tillbaka från köpet tillsammans med checkout token, som vi kommer att använda för att anropa dessa metoder. Denna token kommer att finnas tillgänglig i URL-query parametern via token parametern. Vi kommer att kontrollera för dess existens i bekräftelse URL och sedan skicka våra API anrop om vi hittar den.

GetExpressCheckoutDetails metod krävde endast checkout
token. DoExpressCheckoutPayment kräver ett par ytterligare parametrar:

  • PAYMENTREQUEST_0_PAYMENTACTION
    Detta är åtgärden betalningen. Det ska vara inställd på Sale om vi inte har angett en annan åtgärd i SetExpressCheckout metoden (möjliga värden inkluderar Authorization och Capture).
  • PAYERID
    Detta är en unik identifikation för PayPal-konto. Även detta, returneras i URL-query parametrar (i PAYERID parameter) och kan även hämtas från detaljerna som returneras av GetExpressCheckoutDetails.
if (isset($_GET['token']) && !empty($_GET['token'])) { 
    // Token parameter finns
    // Hämta checkout detaljer, inklusive köparens information.
    // Vi kan spara den för framtida referens eller cross-checka med den data vi har 
    $paypal = new Paypal();
    $checkoutDetails = $paypal->request('GetExpressCheckoutDetails', array('TOKEN' => $_GET['token']));
    // Slutför checkout transaktion
    $requestParams = array(
        'TOKEN' => $_GET['token'],
        'PAYMENTACTION' => 'Sale',
        'PAYERID' => $_GET['PayerID'],
        'PAYMENTREQUEST_0_AMT' => '500', // Same amount as in the original request
        'PAYMENTREQUEST_0_CURRENCYCODE' => 'GBP' // Same currency as the originalrequest
    );
    $response = $paypal->request('DoExpressCheckoutPayment', $requestParams);
    if (is_array($response) && $response['ACK'] == 'Success') { 
        // Betalning lyckades
        // Vi hämtar transaktions-ID för intern bokföring
        $transactionId = $response['PAYMENTINFO_0_TRANSACTIONID'];
    }
}

 

 

Direkt betalning

Med Direct Payment API kan man ta emot betalningar direkt på sin webbplats/applikation, vilket ger fullständig kontroll över utcheckningsprocessen. PayPal tenderar att pusha på användare att registrera och använda ett PayPal-konto, vilket ju är förståeligt men det strider mot våra intressen, som ju är att göra betalningsprocessen som smärtfri och tydlig som möjligt för våra kunder. Av denna anledning är full kontroll över utcheckningen att föredra, och det ger oss också fler alternativ för att optimera försäljningen och genererar mer försäljning.

PayPal - Direct Payment
Processen för PayPals Direct Payment

Processen är lite enklare än Express Checkout, eftersom hela interaktionen sker på vår egen hemsida, och vi behöver endast utföra ett API-anrop för att bearbeta en normal betalning: DoDirectPayment.

Tips: Ett par fler API begäran krävs om man vill utföra en transaktion som faktureras i efterhand (till exempel när man skickar produkten eller bekräftar odrertillgänglighet). Dessa skulle vara Authorization & Capture API metoder, som jag inte kommer gå igenom i det här inlägget, men alternativet finns.

 

doDirectPayment

Direkt betalning kräver andra parametrar än Express Checkout. Medan parametrar för transaktionsdetaljer liknar varandra, kräver metoden även kreditkort och adressinformation.

doDirectPayment grundläggande parametrar:

  • METHOD
    Detta är DoDirectPayment.
  • IPADDRESS
    Detta är IP-adressen för kunden. I PHP, kan vi hämta det med hjälp av superglobaln $_SERVER[’REMOTE_ADDR’]. Du måste göra lite mer arbete för att få IP-adress när det handlar uppställningar som har en proxy mellan PHP processen och utanför nätet (t.ex. nginx).
  • PAYMENTACTION
    Detta är den typ av åtgärder som vi vill utföra. Ett värde på Sale indikerar en omedelbar transaktion. Värdet Authorization indikerar att denna transaktion inte kommer att utföras omedelbart, utan snarare kommer att fångas senare använder Authorization & Capture API nämnde tidigare.

Kreditkortsuppgifter:

  • CREDITCARDTYPE
    Kredit-korttyp (Visa, Mastercard, etc.). Se API-dokumentation för hela listan.
  • ACCT
    Den kreditkortsnummer. (Inte du älskar dessa förkortade nyckelnamn?) Detta måste överensstämma med den speciella formatet kortets typ.
  • EXPDATE
    Den utgångsdatum, i MMÅÅÅÅ format (dvs ett tvåsiffrigt månad och ett år fyrsiffrigt, som en sträng).
  • CVV2
    The ”kortverifieringsvärdet” eller säkerhetskod, som det ibland kallas.
  • Information om betalaren och adressparametrar:
  • FIRSTNAMELASTNAME
    Betalarens förnamn och efternamn, respektive (i separata fält). Du kan också ange en e-postadress i ett e-post parameter, men det är inget krav.
  • CITY, STATE, COUNTRYCODE, ZIP
    Stad, stat, landskod (kod på två bokstäver) och postnummer är delar av adressen som alla behövs.
  • STREET, STREET2
    Skapar två linjer för adressen (endast det första krävs).

Denna adress kommer att användas i address verification system (AVS). Du får en specifik felkod om en transaktion har misslyckats på grund av en adressverifierings misslyckande.

Betalningsinformation parametrarna är desamma som de för Express Checkout, men med lite olika namn (AMT, ITEMAMT, CURRENCYCODE, SHIPPINGAMT, TAXAMT och fallande) och utan PAYMENTREQUEST_0_ prefix. Se föregående avsnitt eller API-dokumentation för specifika detaljer om dem.

Likaså artikelinformation parametrar liknande dem i Express Checkout. Dessa inkluderar L_NAMEm, L_DESCm, L_AMTm och L_QTYm, vilket ger dig detaljerad kontroll över posten detaljer i ordning sammanfattningen. Den m heltal variabel används för att redovisa flera objekt (ersätt med 0, 1 och så vidare för numrerade poster i ordning). Se API-dokumentationen för en omfattande lista med artikelinformation.

 

Utföra Transaktion

Att sända en en query med vår funktion request() är mycket likt GetExpressCheckoutToken. Vi passerar alla parametrar in i queryn fungerar exakt som förut, fast med metod satt till DoDirectPayment.

$requestParams = array(
    'IPADDRESS' => $_SERVER['REMOTE_ADDR'], 
    'PAYMENTACTION' => 'Sale'
);
$creditCardDetails = array(
    'CREDITCARDTYPE' => 'MasterCard', 
    'ACCT' => '9229801207473993', 
    'EXPDATE' => '012021',  /* MMÅÅÅÅ */
    'CVV2' => '977'
);
$payerDetails = array(
    'FIRSTNAME' => 'Daniel', 
    'LASTNAME' => 'Karjanlahti', 
    'COUNTRYCODE' => 'SWE', 
    'STATE' => '',
    'CITY' => 'Södertälje', 
    'STREET' => 'Prästgårdsvägen 10.', 
    'ZIP' => '15161'
);
$orderParams = array(
    'AMT' => '500',  /* Den totala kostnaden för transaktionen till köparen. */
    'ITEMAMT' => '496',  /* Summan av kostnaden för alla Artiklar denna beställning. */
    'SHIPPINGAMT' => '4',  /* Totala fraktkostnader för denna beställning. */
    'CURRENCYCODE' => 'SEK'
);
$item = array(
    'L_NAME0' => 'iPhone',
    'L_DESC0' => 'White iPhone, 16GB', 
    'L_AMT0' => '496',
    'L_QTY0' => '1'
);
$paypal = new Paypal();
$response = $paypal->request(
        'DoDirectPayment', 
        $requestParams + 
        $creditCardDetails + 
        $payerDetails + 
        $orderParams + 
        $item
);
if (is_array($response) && $response['ACK'] == 'Success') { 
    // Betalning lyckades
    // Vi hämtar transaktions-ID för intern bokhållning
    $transactionId = $response['TRANSACTIONID'];
}

Det finns gott om parametrar, men dom är relativt enkla.

 

Felhantering

I en perfekt värld skulle detta avsnitt inte ens existerar. I verkligheten kommer du att hänvisa till det ganska mycket. PayPal kan misslyckas en transaktion för en mängd olika skäl, inte alla som kan du kontrollera.

Den $responsvariabel som vi återvänt från vår paypalApiRequest() funktionen kan innehålla ett annat värde än Success för ACK parameter. Detta värde kan vara:

  • Success
    Indikerar en lyckad operation.
  • SuccessWithWarning
    Indikerar en framgångsrik verksamhet och att meddelanden returneras i det svar som du bör undersöka.
  • Failure
    Indikerar en misslyckad operation, och att svaret innehåller en eller flera felmeddelanden som förklarar misslyckandet.
  • FailureWithWarning
    Indikerar en misslyckad operation, och att meddelanden returneras i det svar som du bör undersöka.
    Detta ger oss två framgångs status och två fel status. Den mock koden ovan tester för Success värdet bara, men vi kunde ändra det för att leta efter SuccessWithWarning också; och kom ihåg att vi måste ta reda på vad varningen är. Ett vanligt scenario är att en Direktbetalnings avgift har tagits med framgång, men kreditkortsföretaget svarar att transaktionen har misslyckats, oavsett orsak.

Fel från PayPal returneras i responsen som fyra parametrar:

  • L_ERRORCODE0
    En numerisk felkod, som kan refereras mot PayPal’s error kodlista (som är omfattande).
  • L_SHORTMESSAGE0
    En kort felmeddelande som beskriver problemet.
  • L_LONGMESSAGE0
    En längre felmeddelande som beskriver problemet.
  • L_SEVERITYCODE0
    Svårighetsgrad.

Noll-delen i dessa parametrar är ett ökande heltal för multipla felmeddelande (1, 2, etc.).

Här är några vanliga fel du kan stöta på:

  • 10002
    Autentisering eller tillstånd misslyckades. Detta tyder oftast ogiltiga API meriter eller referenser som inte matchar den typ av miljö du arbetar i (t.ex. en levande eller sandlåda miljö).
  • 81 ***
    Saknad parameter. Det finns en hel del av dessa, allt börjar med 81. Varje hänvisar till en specifik obligatorisk parameter som saknas i förfrågan.
  • 104 **
    Ogiltigt argument. Detta tyder på att en av de medföljande parametrar har ett ogiltigt värde. Varje argument har specifika fel, allt börjar med 104. En vanlig man är 10413, som innebär att den totala kostnaden för de varukorg poster matchar inte beställningens belopp (dvs. den totala mängden parametern, AMT, inte lika posterna totala plus sjöfart, hantering, skatter och andra avgifter).

 

Ta Hand om Felmeddelanden!

PayPal:s felmeddelanden varierar och kan innehålla privat information som du garanterat inte vill att dina användare att se (t.ex. en ogiltig försäljar-konfiguration). Om så är fallet, ska man inte visa dessa felmeddelanden direkt till användarna, även om vissa av dem kan vara användbara.

I de flesta fall skulle jag göra följande:

  1. Sätt upp en vit-lista rad fel som kan visas på ett säkert sätt (t.ex. en saknad kreditkortsnummer och utgångsdatum);
  2. Kontrollera svarskoden mot den arrayen;
  3. Om felmeddelandet inte är i den vita listan, visa ett generiskt felmeddelande, till exempel ”Ett fel inträffade under hanteringen av din betalning. Försök igen om några minuter, eller kontakta oss om detta är en återkommande fråga. ”

Om ett fel inte finns i den vita-listade arrayn, ska man logga det till en fil på servern och skicka ett mail till administratören, tillsammans med alla detaljer så att denne känner till misslyckade betalningar. Att loggar PayPal förfrågningar och svar är god praxis oavsett om dom innehåller felmeddelanden, så att man kan övervaka och felsöka betalnings misslyckanden.

 

Okej, det här borde få dig att komma igång med dom två populäraste PayPal alternativen Express Checkout och Direct Checkout. Till nästa gång, koda smart 😉

 

Ansvarsfriskrivning – Jag kan tyvärr inte garantera att den här artikeln resulterar i en felfri och säker applikation, och det är ditt ansvar att kontrollera din kod mot dokumentationen.

 

Huvudsaklig Källa

Att Sälja på Nätet

För att göra transaktioner på nätet behöver webbplatsen kunna utföra tre steg och det tredje steget finns har man två alternativ att välja mellan.

 

Med egen säljarkonto

  1. Cart (kundvagn) > ska samla in information om köpet, som kortnummer, adress, namn mm.
  2. Payment gateway (betalningsgateway) > krypterar informationen som samlats in och skickar den till säljarkonto.
  3. Merchant account (säljarkonto) > processar informationen och sätter in pengarna på kontot.

 

Med tredjeparts säljarkonto

  1. Kundvagn > ska samla in information om köpet, som kortnummer, adress, namn mm.
  2. Betalningsgateway > krypterar informationen och skickar den till säljarkonto
  3. Tredjepart säljarkonto > PayPal, Google Checkout m.fl. > processar informationen och sätter in pengarna på kontot

 

Det här är en första utdrag ur en serie om att skapa en nätbutikoch nästa artikel kommer alldeles strax. I den går jag igenom hur man integrerar PayPal på sin webbsida.

ER Diagram

ER Diagram är ett sätt att visualisera data och dess relationer. ER står för Entity-Relationship, vilket ungefär blir ”saker” och ”samband”. En entity i sammanhanget databaser, representerar en tabell. Relationsmodellen går ut på att data lagras i relationer, och en relation är lika med en tabell, med rader och kolumner.

 

Tupler och Attribut

Raderna brukar kallas tupler och kolumnerna attribut:

Tupler och attribut
Tupler och attribut

Så varje tupel innehåller data för en attribut. Vi ska inte gå djupare i det just nu, utan går vidare med själva visualiseringen av entiteter.

 

Exempel på ER-Diagram

Om vi nu vill visa en relation med ett ER-diagram mellan följande:

  • Fotograf kan ta flera foton
  • Foton måste tas av en fotograf
  • Foton måsta lagras på ett minneskort
  • Minneskort kan lagra många kort

…som har följande entiteter:

  • Entitet = fotograf
  • Entitet = foto
  • Entitet = minneskort

…så kan det se ut så här:

ER Relationsmodellen; fotograf, foto och minneskort
ER Relationsmodellen; fotograf, foto och minneskort

Lägg märke till linjerna mellan entiteterna, som anger på vilket sätt dom är relaterade. Här använder jag så kallade ”crow feet” eller kråkfötter, vilka man tolkar på följande sätt:

Så kallade crow feet eller kråkfötter anger relationen mellan entiteter
Så kallade crow feet eller kråkfötter anger relationen mellan entiteter

Som du ser betyder en cirkel att det är villkorligt medan ett streck betyder måste. Och det streck som är närmast entiteten betyder 1 och en gaffel betyder många. Som du såg fanns i varje entitet en övre attribut som heter id. Det är primär nyckel i fotograf,  genom den som entiteterna är kopplade till varandra.

 

Variant

En annan variant på ER-diagram ser ut så här:

ER-Relationsmodellen en annan version
ER-Relationsmodellen en annan version

I det här diagrammet används en diamant form för att specificera sambandet mellan entiteterna, och här representerar en 1:a som en och M står för många. En dubbel linje betyder att det måste vara ett/många och en enkel att det kan vara. Vidare kan du se att fotograf_namn länkar till fotograf_fnamn, och fotograf_enamn vilket betyder att man kan välja att ha med dom två andra eller bara använda fotograf_namn.

 

 

Primary Key & Foreign Key

För att kunna bygga förhållanden måste databasen vara skapad i innoDB och båda kolumnena måste vara indexerade. Och när man skapar en koppling i en databas på det här sättet så är det oftast en relatetion mellan en primary key och foreign key.

Foreign key är en nyckel som relaterar tillbaka till en primary key. En foreign key är ett fält (eller samling av fält) i en tabell som unikt identifierar en rad (primary key) i en annan tabell. Foreign key etablerar en relation, eller constraint, mellan två tabeller/entiteter. Och om man har en foreign key i en tabell måste den ha en matchande primary key i en annan tabell.

 

Typer av relationer

Det finns tre olika typerna av relationer:

  • Ett-till-ett
  • Ett-till-många
  • Många-till-många
ER Relationsmodellen; dom tre olika relationerna
ER Relationsmodellen; dom tre olika relationerna

Nu har du grundkunskaperna i hur man skapar ER-diagram och kan därför lättare planera en databas med tillhörande tabeller. Hoppas att du får användning av det här i framtiden och till nästa gång koda smart 😉

 

Lämna gärna kommentarer och om ni hittar fel ta gärna kontakt med mig.

PHP Klasser, metoder & Medlemsvariabler

Idag ska vi gå igenom PHP Klasser med tillhörande Medlemsvariabler. Och med medlemsvariabler menar jag variabler som deklareras i en klass.


Klasser & KlassNamn

När det kommer till namngivning av klasser, så ska man enligt allmänna riktlinjer och regler tänka på följande:

  • Namn måste börja med bokstav eller understreck ( _ ).
  • Och det följande tecknen måste vara; bokstäver, nummer och understreck ( _ ).
  • Det finns inga begränsningar på hur lång namnet får vara.
  • Man brukar använda ”upper camel case”, d.v.s. man skriver ihop flera ord, och första bokstaven i varje ny ord börjar med stor bokstav, då får det sammansatta ordet pucklar på ryggen som en kamel.
  • Undvika ordet class i namnet.

Att skapa en klass är enkelt och den består av 3 delar plus innehållande metoder och medlemsvariabler:

Nyckelordet class, följt av själva namnet på klassen (här ska nyckelordet extends läggas om man utökar en klass) och sedan ett par klammerparentes – {}:

class KlassNamn {
   /*** metoder och medlemsvariabler ***/
}

Här följer ett par exempel på namngivning av klasser:

class Namn {}
class EttNamn {}
class Ett_Namn {}
/* Alla 3 Följer god praxis, då varje ord börjar med stor bokstav */

class ett_namn {}
/* detta är giltigt men följer inte god praxis */

class 1_Namn {}
/* inte ett giltigt klassnamn, då den börjar med en bokstav */

Medlemsvariabler

Medlemsvariabler är variabler som skrivs in i klasser, och förefås alltid av nyckelordet; public, protected eller private. Om man utelämnar nyckelordet får man en ”parse error” och PHP avbryter exekvering. Så, vad ska man välja? Det är här metoder kommer in i bilden och fungerar som klassens reglage, och behöver därför oftast vara public, medan medlemsvariabler bör skyddas med protected eller private så att ingen kommer åt dom avsiktligt eller oavsiktligt.

  • Precis som klasser måste dom börja med en bokstav eller ett understreck ( _ ).
  • Följande tecken måste vara; bokstäver, nummer och understreck.
  • Och det finns ingen begränsning på längd
  • Man brukar använda ”lower camel case”, där det första ordet skrivs med små bokstäver och varje ny ord börjar med stor bokstav.
  • När det kommer till understreck i början så används det för att tydliggöra att en variabel har begränsad synliget, d.v.s. använder nyckelordet portected eller private

För att modifiera egenskaper använder man sig av getter och setter metoder.

Exempel på setter och getter metoder:

Vi börjar med att skapa en klass som vi kan bygga under den här artikeln. Den ska representera en fysisk adress, så det naturliga namnvalet blev Adress, och eftersom man så gott som alltid namnger på Engelska blir det Address

PHP Validerings klass

 Inspiration från boken ”PHP Object Oriented Solutions” av David Powers

Detta är andra delen i serien – PHP Validering. Idag fortsätter vi där vi slutade förra gånge och börjar bygga på en PHP validerings klass, så att man slipper hålla på med alla komplicerade arrayer med alternativ och konstanter. För trots filterfunktionernas komplexitet, så är deras förmåga att filtrera eller validera flera variabler i ett enda moment väldigt användbar. Vad vi behöver är en anpassad klass för att bygga flerdimensionella arrayer som avgör hur varje variabel ska behandlas. När arrayen har byggtsär det bara en fråga om att föra den till den lämpliga filterfunktionen och fånga resultatet. Genom att kapsla varje steg i processen inne i klassen, kommer vi att sluta med ett valideringsverktyg som är enklare att använda, då den lämnar allt det hårda arbete till filterfunktionerna.

Först av allt, låt oss överväga vilken funktionalitet klassen ska ha.

 

Bestämma vad klassen ska göra

Om man tittar på dom tillgängliga filtren kan man snabbt komma underfund med vad klassen bör kunna validera:

  • Heltal
  • Flyttal
  • Booleska värden
  • Email adresser
  • URL adresser
  • Och matcha reguljära uttryck

…den måste också kunna ta bort HTML-taggar och omvandla specialtecken. Följande uppgifter behövs ofta vid validering av indata från användaren:

  • Kontrollera att alla obligatoriska fält har ett värde.
  • Kontrollera om en array är numerisk.
  • Ange ett lägsta och högsta antal tecken vid textinmatning.

…slutligen behövs en metod som gör ingenting! Den lägger helt enkelt en oförändrad värde till det filtrerade resultat, som man sedan kan bearbeta separat.
Efter att indata från användaren har validerats, ska klassen producera tre arrayer på följande sätt:

  • De filtrerade resultat.
  • Namnen på obligatoriska fält som fattades.
  • Eventuella felmeddelanden som genererades under valideringsprocessen.

…okej nu räcker det, eftersom det här betyder en hel del kodning och vill du, kan du lägga till egna metoder senare.

 

Planera klassen

Då var det dags att planera klassen. Eftersom den bör kunna ta emot flera värden åt gången behöver den baseras på antingen filter_var_array() eller filter_input_array() och om man behöver filtrera endast ett värde kan man göra det i en array med endast ett element. Så till att börja med skapar vi en klass som hanterar input från $_POST och $_GET och skulle man behöva hantera input från någon annanstans så kan man lägga till den funktionaliteten senare.

Hela syftet med klassen är att dölja komplexiteten av arrayn med dess filter-konstanter, flaggor och alternativ, så dess huvudfunktion blir att bygga den arrayn bakom kulisserna, och sedan passera det till filter_input_array(), och fånga resultatet. Så klassen behöver följ dessa tre steg:

  1. Instantiering (konstruktorn)
    Hämta data från $_POST eller $_GET arrayn.
    Kontrollera om några obligatoriska fält saknas.
  2. Valideringsmetoder
    Skapa ett arrayelement för varje fält med lämpliga filterkonstanter, flaggor och alternativ.
    Generera felmeddelanden.
  3. Validering
    Kontrollera så attvarje obligatoriskt fält har passerat valideringstestet.
    Lämna över array med filter-konstanter, flaggor och alternativ till filter_input_array().
    Lagra det filtrerade resultat, felmeddelanden och namn på uteblivna obligatoriska fält.

Nu när vi har en plan för klassen, är det dags att börja med själva koden.

 

 

Namnge fält & definiera konstruktorn

När vi nu beslutat vilka egenskaper vi behöver definiera så är det inte alltid praktiskt möjligt att se vad som behövs i början, men på ett minimum, behöver vi ett sätt inne i klassen, att hänvisa till följande:

  • Var inmatningen kommer ifrån; $_POST eller $_GET arrayn (vi namnge medlemsvariabeln $_inputType).
  • Den ofiltrerade inmatningen ($_submitted).
  • En lista över obligatoriska fält ($ _required).
  • Den array av filter, alternativ och flaggor som ska skickas till filter_input_array() (med namnet $_filterArgs).
  • Den filtrerade inmatningen ($_filtered).
  • En lista över obligatoriska fält som fattades ($_missing).
  • Felmeddelanden genererade av validator ($_errors).

 

class My_Validator

My_Validator klassen kommer att innehålla följande medlemsvariabler och metoder:

/**
class My_Validator {
  MEDLEMSVARIABLER
  protected $_inputType
  protected $_submitted
  protected $_required
  protected $_filtered
  protected $_missing
  protected $_errors
  protected $_filterArgs
  protected $_booleans

  KONSTRUKTOR
  function __construct($required = array(), $inputType = 'post') {}

  PUBLIC
  public function isInt() {}
  public function isFloat() {}
  public function isNumericArray() {}
  public function isEmail() {}
  public function isFullURL() {}
  public function isURL() {}
  public function isBool() {}
  public function matches() {}
  public function removeTags() {}
  public function removeTagsFromArray() {}
  public function useEntities() {}
  public function checkTextLength() {}
  public function noFilter() {}
  public function validateInput() {}
  public function getMissing() {}
  public function getFiltered() {}
  public function getErrors() {}

  PROTECTED 
  protected function checkDuplicateFilter($fieldName) {}
  protected function setInputType($type) {}
  protected function checkRequired() {}
}
*/

 

 

Medlemsvariabler

Till att börja med skapar vi en fil som heter my_validator.php definierar klasssen i den. Sedan skriver vi in alla medlemsvariabler
Sätt in följande kod my_validator.php:

<?php
class My_Validator {
    protected $_inputType;
    protected $_submitted;
    protected $_required;
    protected $_filterArgs;
    protected $_filtered;
    protected $_missing;
    protected $_errors;

    public function __construct() {
        
    }
}

Detta definierar My_Validator klassen med medlemsvariabler och en tom konstruktor. Vid validering av inmatning, är det viktigt att förhindra eventuell yttre påverkan från att förvränga datan, så alla egenskaper har deklarerats som protected (och alla namn börjar med en understreck som en påminnelse om deras synlighet).

 

 

__construct()

Konstruktorn ska initiera medlemsvariablerna som ska innehålla listan över nödvändiga objekt; $_required och den för vilken typ av inmatning det gäller; $_inputType. Det även också se till att filterfunktioner finns tillgängliga på servern (utan dem, kommer klassen inte att fungerar). Konstruktorn ska också kontrollera att alla obligatoriska fält i $_required har ett värde, måste man passera en array som innehåller namnen på de obligatoriska fälten till konstruktorn som sedan lagras i $_required. Klassen kommer att hantera antingen en $_POST eller $_GET array, därför behöver man även passera det som argument till konstruktorn. Men det är möjligt att man ibland inte vill att några fält måste vara obligatoriska, och därför bör argumentet vara valfritt. För att göra klassen lite mer flexibel, gör vi även inmatningstypen till ett valfritt argument, genom att ge det ett standardvärde ’post’ som syftar till INPUT_POST.

Modifiera konstruktorn så här:

public function __construct($required = array(), $inputType = 'post') {
    $this->_required = $required;
    $this->setInputType($inputType);
}

De två argument, $required och $inputType, har samma namn som sina motsvarande egenskaper, men utan understreck. Detta är en påminnelse om att deras värden kommer från utanför klassen. $required är satt som standard till en tom array, och $inputType till ”post”. Vilket gör båda argumenten frivilliga, men om andra värden passeras till konstruktorn, kommer dessa användas i stället.

Att ställa in värdet för $_required är okomplicerat, den får värdet från det första argumentet; $required. Dock måste egenskapen $_inputType hanteras annorlunda. Som du kanske minns från förra artikeln, tar filter_input_array() som första argument en av inmatningskonstanterna:

/*
INPUT_GET
INPUT_POST
INPUT_COOKIE
INPUT_ENV
INPUT_SERVER
INPUT_SESSION (Inte implementerat än)
INPUT_REQUEST (Inte implementerat än)
*/

…vilka har en motsvarande superglobal; $_POST, $_GET, $_COOKIE, $_SESSION o.s.v. Vår klass kommer att koncentrera sig på två av dom; INPUT_POST och INPUT_GET. Och här skulle vi kunnat använda just INPUT_POST som argument, men det betyder att man skulle behöva passera in INPUT_GET till konstruktorn om man istället vill validera en $_GET superglobal. Men en av de viktigaste idéerna bakom My_Validator klassen är ju trots allt att dölja de otympliga konstanterna, därför kommer vi att använda en enkel sträng som argument. Detta innebär att klassen behöver kolla upp rätt konstant att tilldela $_inputType. Den uppgiften ger vi till en protected metod som vi kallar för setInputType(), (lite senare i artikeln).

Klassen förlitar sig på filterfunktioner för att göra allt det hårda arbetet, så man måste se till att dessa är tillgängliga. Det är också en bra idé att kontrollera att $required argumentet innehåller en array.

Ändra koden till att kasta undantag (throw exeption) om något av villkoren inte uppfylls:

public function __construct($required = array(), $inputType = 'post') {
    // se till att filterfunktioner finns tillgängliga
    if (!function_exists('filter_list')) {
        throw new Exception('My_Validator klassen behöver Filter Funktionerna i >= PHP 5.2 eller PECL för att fungera.');
    }
    // Om $required har ett värde måste det vara lika med en array()
    if (!is_null($required) && !is_array($required)) {
        throw new Exception('Namnen på dom nödvändiga fälten måste vara i en array, även om bara ett fält är ovillkorligt.');
    }
    // passera värdena till medlemsvariabel
    $this->_required = $required;
    // sätt vilken typ av superglobal det gäller
    $this->setInputType($inputType);
}

Den första villkorliga satsen kontrollerar om filter_list() funktionen finns (den som listar alla filterfunktionerna), om inte, vet man att ingen av filtren finns tillgängligt och ett undantag kastas. Den andra villkorssats om $required måste det vara lika med en array(), annars kastas ett undantag. Även om bara ett fält krävs, måste man se till det är en array, annars får man problem senare. Om en array med obligatoriska fält har getts som argument, måste man kontrollera att varje fält har ett värde.

Modifiera koden så här:

public function __construct($required = array(), $inputType = 'post') {
    if (!function_exists('filter_list')) {
        throw new Exception('MyValidator klassen behöver Filter Funktionerna i => PHP 5.2 or PECL.');
    }
    if (!is_null($required) && !is_array($required)) {
        throw new Exception('Namnen i de nödvändiga fälten måste vara en array, även om bara ett fält är ovillkorligt.');
    }
    $this->_required = $required;
    $this->setInputType($inputType);

    // här kommer den nya koden
    if ($this->_required) {
        $this->checkRequired();
    }
    $this->_filterArgs = array();
    $this->_errors = array();
    $this->_booleans = array();
}

Om det första argumentet inte finns, så sätts $_this->_required till en tom array, vilket PHP ser som FALSE; annars anropar konstruktorn en protected metod; checkRequired(), (som vi skapar snart). Och till sist sätts $_filterArgs och $_errors egenskaperna till tomma arrayer. Då var vi klara med konstruktorn för tillfället. Vi kommer att lägga till ett par punkter senare, eftersom det är enklare att förklara dem i sitt sammanhang. Konstruktören gör anrop till två protected metoder; checkRequired() och setInputType() vilka kommer härnäst.

 

Sätt inmatningstyp & kontrollera obligatoriska fält

setInputType() och checkRequired() metoderna kallas båda inifrån konstruktorn, vilket låter oss dölja deras existens från alla användare av klassen. Och när det kommer till setInputType() är detta särskilt viktigt, eftersom man inte vill att någon ska kunna ändra inmatningskällan godtyckligt, när det väl har ställts in. Därför kommer båda metoderna att definieras som protected, och därigenom begränsa tillgången till klassen My_Validator, (men dom kan användas av alla barnklasser om man skulle bestämma sig för att förlänga (extends) klassen senare).

 

setInputType()

Syftet med setInputType() är dubbelt: såväl som inställning av inmatningskälla till ”post” eller ”get”, tilldelar den variablerna från inmatningskällan till $_submitted. Därigenom får klassen tillgång till de variabler man vill validera. Koden är rätt så enkelt, här är hela koden för metoden:

// setInputType
protected function setInputType($type) {
    switch (strtolower($type)) {
      case 'post':
        $this->_inputType = INPUT_POST;
        $this->_submitted = $_POST;
        break;
      case 'get':
        $this->_inputType = INPUT_GET;
        $this->_submitted = $_GET;
        break;
default:
throw new Exception('Ogiltig inmatnings typ. Giltiga typer är "post" och "get".');
    }
}

Funktionen innehåller en enkel switch sats, vilket tar det argument det som passerats till setInputType() och skickar den till strtolower(). Det innebär att det andra argumentet i klassens konstruktor är skiftlägeskänsligt . Därför spelar det ingen roll om användaren skriver ”get” eller ”GET”, då det omvandlas till små bokstäver. Beroende på värdet som skickas till setInputType(), är egenskapen $_inputType inställd för rätt inmatnings konstant. Detta kommer att behövas senare, när du passerar variablerna till filter_input_array() för bearbetning. Samtidigt, är innehållet i den relevanta superglobal arrayen delad till $_submitted egenskapen.

Om ett annat värde än post eller få skickas, då metoden ger ett undantag med ett lämpligt meddelande.

 

checkRequired()

Nu när vi har fyllt i $_submitted, kan den jämföras med arrayn av obligatoriska fält.

Så här ser checkRequired() metoden ut:

protected function checkRequired() {
    $OK = array();
    foreach ($this->_submitted as $name => $value) {
       $value = is_array($value) ? $value : trim($value);
       if (!empty($value)) {
          $OK[] = $name;
       }
    }
    $this->_missing = array_diff($this->_required, $OK);
}

Metoden börjar med att initiera en lokal variabel $OK som en tom array. En foreach loop går sedan igenom varje del av $_submitted arrayn, med andra ord en; $_POST eller $_GET array, beroende på vilken inmatningstyp som har valts. Vi vill inte att folk att kringgår ett obligatoriskt fält genom att bara trycka på mellanslagstangenten några gånger, så följande rad avlägsnar mellanslag från värdet, om det inte är en array:

$value = is_array($value) ? $value : trim($value);

Eftersom man inte kan passera en array till trim(), så detta använder villkorliga operatören (? :) för att kontrollera om värdet är en array. Om det är en array, tilldelar den värdet till $value oförändrad; Annars anropas trim() som tar bort alla blanksteg innan $value tilldelas tillbaka till sig själv. Om $value inte är tom, skall namnet på den variabel läggas till $OK array. När loopen är klar,innehåller $OK namnen på alla fält som innehåller ett värde.

Det finns en potentiell brist i denna strategi. Om en array innehåller bara tomma strängar, kommer det ändå att passera testet. Dock är syftet med klassen att bearbeta inmatning från online-formulär. Värden skickas som arrayer från grupper avkryssrutor och flervalslistor. Om formuläret är korrekt inställd, så är det enda sättet man kan få en array med tomma strängar genom $_POST eller $_GET, är om någon använder spoofing på formuläret. Om det händer, finns det andra säkerhetsåtgärder, såsom en CAPTCHA (helt automatiserad Turing test för att skilja datorer och människor åt, se www.captcha.net), vilket kommer sannolikt att vara mer effektivt än att stärka just denna test.

Allt som återstår är att ta reda på om det finns någon skillnad mellan de namnen i $OK och de i $_required. Detta görs genom att leda $_required egenskap och $OK till array_diff() funktion, som returnerar en array som innehåller alla värden från den första array som inte finns i den andra. Så, är något värde i $_required skiljer sig från $OK array, lagras det i $_missing.

Om alla värden i $_required finns dom också i $OK arrayen, medan $_missing innehåller en tom array vilket betyder att alla obligatoriska fält har fyllts i. Det är ganska troligt att de $OK arrayen kan innehålla namnen på valfri fält som har fyllts i, men det spelar ingen roll eftersom array_diff() lämnas utan gards några extra element i den andra array.

Det kan vara svårt att förstå hur detta fungerar, så här är ett praktiskt exempel. $_required och $OK arrayerna är så kallade indexerade arrayer som innehåller bara namnen på variablerna, inte deras värden, de kan se ut ungefär så här:

0 => 'name', 
1 => 'email', 
2 => 'comments'  // $_required
0 => 'name', 
1 => 'comments'  // $OK

När array_diff() returnerar en array med saknade värden, bevarar den de ursprungliga nyckel/värde paren. I detta fall är värdena bara namnen på variablerna.

Föregående exempel skulle returnera en array som innehåller följande enskilt element:

1 => 'email'

Den enda array som innehåller både namnen på de inlämnade fälten och deras värden är $_submitted.

 

 

Testa checkRequired

Nu börjar det bli dags att kontrollera koden som vi skrivit så här långt, genom att testa checkRequired(). Att testa koden med jämna mellanrum gör det mycket lättare att spåra problem.

Här kommer kod till testet:

<!-- test_validator.php -->
<!DOCTYPE html>
<html lang="sv-SE">
<head>
   <meta charset="UTF-8" />
   <title>Test validator class</title>
<style>
body {
	font-family: Arial, Helvetica, sans-serif;
	color: #000;
	background-color: #FFF;
        width:940px;
        margin:50px auto;
}
label {
	font-weight: bold;
	display: block;
}
form {
	margin-left: 50px;
}
.comments {
	height: 100px;
	width: 400px;
}
.textfield {
	width: 250px;
}
.warning {
	color: #f00;
	font-weight: bold;
}
</style>
</head>
<body>
  <form id="form1" name="form1" method="post" action="">
    <p>
        <label for="name">Name:</label> 
        <input name="name" type="text" class="textfield" id="name" />
    </p>
    <p>
        <label for="email">Email:</label> 
        <input name="email" type="text" class="textfield" id="email" />
    </p>
    <p>
        <label for="comments">Comments:</label> 
        <textarea name="comments" class="comments" cols="45" rows="5"></textarea>
    </p>
    <p>
        <input type="submit" name="send" id="send" value="Skicka kommentarer" />
    </p>
  </form><!-- formen tar slut -->
</body>
</html>

Denna formulär innehåller tre fält med name attributen; name, email och comments, och knappen ”Skicka kommentarer” med attributet name=”send”. Metod attributet är satt att post, och action har lämnats tom, så formen blir automatiskt riktad till sig själv.
Lägg in följande kod efter formen:

     </form><!-- formen tar slut -->
<?php
if (filter_has_var(INPUT_POST, 'send')) {
        require_once 'my_validator.php';
        $required = array('name', 'email', 'comments');
        $val = new My_Validator($required);
}
?>
</body>
</html>

Detta använder filter_has_var() för att kontrollera om $_POST arrayen innehåller en variabel som heter send, vilket gör att koden inuti klammerparenteser endast körs om knappen ”Skicka kommentar” har klickats. Vi inkluderar klassen My_Validator med require_once, och därefter skapas en array med namnet $required som innehåller namnen på dom tre formulärfälten, för att sedan skicka den som ett argument till en ny instans av My_Validator klassen.

 

Till sist ska du öppna my_validator.php igen och lägg till en sista rad i metoden checkRequired():

protected function checkRequired() {
        $OK = array();
        foreach ($this->_submitted as $name => $value) {
            $value = is_array($value) ? $value : trim($value);
            if (!empty($value)) {
                $OK[] = $name;
            }
        }
        $this->_missing = array_diff($this->_required, $OK);
        // denna rad
        print_r($this->_missing);
}

print_r() visar då innehållet i $_missing. Spara filerna och ladda test_validator.php i en webbläsare och klicka på ”Skicka kommentar” knappen utan att fylla i något av fälten. Om allt är som det ska bör du se namnen på de tre utelämnade områdena precis efter formuläret, som bilden nedanför visar:

Screenshot - Testa My_validator klass
Testa My_validator klass

Den visar vilka obligatoriska fält som blev utelämnade. Förtsätt med testet genom att fylla i ett av fälten, och sätt ett par blanksteg i en annan, och klicka på ”Skicka kommentarer” igen. Array() ska inte längre innehålla namnen på dom fälten som du fyllde i med något, men den med bara blanksteg bör visas.

Fyll nu i varje fält och klicka på”Skicka kommentarer” igen. Resultatet bör bli Array(), vilket tyder på att $_missing innehåller en tom array.

 

Nu är vi klara med testet så du kan ta bort följande rad från checkRequired() eftersom den endast behövdes för teständamål:

print_r($this ->_missing);

Denna övning bekräftar inte bara att checkRequired() fungerar, utan också att konstruktorn fyller i $_required och setInputType() sätter värden för $_submitted från $_POST arrayen.

 

Inga Dubletter Tack!

Innan vi går vidare till definitionen av valideringsmetoderna behöver vi ytterligare en skyddad metod. Att tillämpa flera filter på en variabel kan ha oförutsägbara resultat, så det är en bra idé att testa det. Klassen behöver för att bygga en flerdimensionell array som innehåller namnet på varje inmatningsfält eller variabel, tillsammans med filtret, alternativen och flaggorna man vill applicera på den. Detta kommer att lagras i $_filterArgs. Om fältnamnet redan har registrerats i $_filterArgs array, vet du att ett duplikat filtret tillämpas, så du måste kasta ett undantag.
Istället för att skriva ut ett liknande meddelande i varje valideringsmetod, är det bättre delegera ansvaret till en skyddad metod som vi kallar för checkDuplicateFilter():

/**
 * @param string $fieldName
 * @throws Exception -> om ett filter redan satts för fältet
 */
protected function checkDuplicateFilter($fieldName) {
	if (isset($this->_filterArgs[$fieldName])) {
          
	throw new Exception("Ett filter har redan satts för fältet: $fieldName.");
	}
}

Denna metod kommer att kallas av varje valideringsmetod, som kommer att passera det namnet på det fält som ska valideras. Om $ _filterArgs array redan innehåller ett element för fältet, klassen kastar ett undantag, visar fältnamnet i felmeddelandet.

 

Validerings-Metoder

Filterfunktionerna erbjuder ett mycket användbart utbud av alternativ och flaggor. Ett sätt att använda dem skulle vara att skapa separata metoder med namn som anger exakt vad de gör. Det har fördelen av att vara detaljerad, men det skulle resultera i en hel del kodning, för att inte nämna faran för att skapa ett gränssnitt precis lika komplicerad som det vi försöker dölja med klassen. Lösningen som vi kommer att använda oss av är att kontrollera alternativen genom valfria argument till varje validerings-metod. Det första argumentet är inte villkorligt, och innehåller namnet på inmatningsfält eller variabel som man vill validera. Där det är möjligt kommer det andra argument att ha ett standardvärde och därigenom bli villkorligt.

Även om detta kan bli komplicerat, så löser vi det med hjälp av phpdoc kommentarer och en IDE som har förmågan att visa kodtips (NetBeans är min favorit gratis applikation, och en annan är Aptana Studio som också är mycket bra):

Screenshot - Codehint - i NetBeans
Kodtips – i NetBeans

Strukturen för varje valideringsmetoden är väldigt lika. Dom kommer alla att deklareras som public och börjar genom att anropa checkDuplicateFilter() för att kontrollera om ett filter redan har tillämpats. Om checkDuplicateFilter() inte kastar ett undantag (throw exeption), tillägger valideringsmetoden namnet på fältet eller variabeln till den översta nivån av $_filterArgs arrayn, och därigenom ställer in filtret och eventuella flaggor eller alternativen. Koden är relativt enkel och bygger helt enkelt på en array av konstanter, alternativ och flaggorna. Arrayn liknar den i avsnittet ”Flera Variabler åt Gången” i  förra artikeln PHP filter_var och filter_input. Så, vi kommer att gå igenom varje metod relativt fort.

 

Validera Heltal

Filterkonstanten för validering av heltal accepterar två alternativ för att ange minimi- och maximum acceptabla värden; minimum och maximum . Eftersom du inte alltid kommer att vilja ställa dessa värden, ska argumenten för båda alternativen måste vara frivillig. Koden för isint() metoden ser ut så här:

/**
 * Kollar om värdet är en Integer
 * @param string $fieldName
 * @param int $min
 * @param int $max
 */
public function isInt($fieldName, $min = null, $max = null) {
        // kolla om filtret är satt
        $this->checkDuplicateFilter($fieldName);
        
        // sätt filter argument till $_filterArgs
        $this->_filterArgs[$fieldName] = array('filter' => FILTER_VALIDATE_INT);

        // kolla om värdena stämmer med minimum och maximum värden
        if (is_int($min)) {
            $this->_filterArgs[$fieldName]['options']['min_range'] = $min;
        }
        if (is_int($max)) {
            $this->_filterArgs[$fieldName]['options']['max_range'] = $max;
        }
}

Standardvärdet på $ min och $ max är satt till null. min_range och max_range alternativ är båda valfritt, så att vi kan sätta antingen båda eller ingen. Att fastställa en lägsta godtagbar värde på egen hand, vi utelämnar det tredje argumentet. Men att ställa in ett maximalt värde utan ställa ett minimum, måste du passera null (utan citationstecken) som det andra argument.

 

Validera Flyttal

Filterkonstanten som validerar flyttal accepterar ett alternativ för att ställa in vilket tecken som används som decimalpunkt och en flagga för att tillåta tusentals separator. Båda alternativen ges standardvärden. Koden för isFloat() ser ut så här:

/**
 * Kollar om ett nummer är ett flyttal
 * @param string $fieldName
 * @param string $decimalPoint
 * @param boolean $allowThousandSeparator
 * @throws Exception
 */
public function isFloat($fieldName, $decimalPoint = '.', $allowThousandSeparator = true) {
        $this->checkDuplicateFilter($fieldName);
        if ($decimalPoint != '.' && $decimalPoint != ',') {
            throw new Exception('Decimal punkt måste vara en komma- eller punkt i isFloat().');
        }
        $this->_filterArgs[$fieldName] = array(
            'filter' => FILTER_VALIDATE_FLOAT,
            'options' => array('decimal' => $decimalPoint)
        );
        if ($allowThousandSeparator) {
            $this->_filterArgs[$fieldName]['flags'] = FILTER_FLAG_ALLOW_THOUSAND;
        }
}

Standardvärdet för $decimalPoint har satts till en punkt, och
$allowThousandSeparator standard true. Detta innebär att båda argumenten kan utelämnas.

 

Valider Numerisk Array

Följande valideringsmetod finns med främst att demonstrera användningen av en av flaggan FILTER_REQUIRE_ARRAY. isNumericArray() funktionen tar tre valfria argument: $allowDecimalFractions, $decimalPoint och $allowThousandSeparator, vilka fungerar på samma sätt som för förra funktionen; isFloat():

/**
 * Testar om en array är numerisk
 * @param string $fieldName
 * @param boolean $allowDecimalFractions
 * @param string $decimalPoint
 * @param boolean $allowThousandSeparator
 * @throws Exception
 */
public function isNumericArray($fieldName, $allowDecimalFractions = true, $decimalPoint = '.', $allowThousandSeparator = true) {
        $this->checkDuplicateFilter($fieldName);
        if ($decimalPoint != '.' && $decimalPoint != ',') {
            throw new Exception('Decimal point must be a comma or period in isNumericArray().');
        }
        $this->_filterArgs[$fieldName] = array(
            'filter' => FILTER_VALIDATE_FLOAT,
            'flags' => FILTER_REQUIRE_ARRAY,
            'options' => array('decimal' => $decimalPoint)
        );
        if ($allowDecimalFractions) {
            $this->_filterArgs[$fieldName]['flags'] |= FILTER_FLAG_ALLOW_FRACTION;
        }
        if ($allowThousandSeparator) {
            $this->_filterArgs[$fieldName]['flags'] |= FILTER_FLAG_ALLOW_THOUSAND;
        }
}

Det valfria argument är alla inställda på de vanligaste värdena, och kan därför utelämnas. Men, om du vill att array endast innehåller heltal, ställa in det andra argumentet ($ allowDecimalFractions) till false.

En viktig sak att notera om denna metod är det sätt flaggorna för att möjliggöra decimal fraktioner och tusentalsavgränsare läggs till befintliga flagg element med den kombinerade tilldelnings operatören | =. Det vertikala strecket är en så kallad bitwise operatör och kan kombineras med ett likhetstecken på samma sätt som aritmetiska operatorer, t.ex. += eller *=.

 

Validera Email

Denna metod har av förklarliga skäl inga alternativ eller flaggor, utan kollar bara om det är en email adress:

/**
 * Kollar om strängen uppfyller kraven för hur en email adress är uppbyggd
 * @param string $fieldName
 */
public function isEmail($fieldName) {
        $this->checkDuplicateFilter($fieldName);
        $this->_filterArgs[$fieldName] = FILTER_VALIDATE_EMAIL;
}

 

Validera Fullständig URL

Denna metod validerar en fullständig URL, och kontrollerar då bara om det är rätt format, d.v.s. att det börjar med; http:// , https://, eller ftp:// etc. Funktionen tar ett valfritt argument: $queryStringRequired, vilket är satt till false som standard:

/**
 * @param string $fieldName
 * @param boolean $queryStringRequired
 */
public function isFullURL($fieldName, $queryStringRequired = false) {
        $this->checkDuplicateFilter($fieldName);
        $this->_filterArgs[$fieldName] = array(
            'filter' => FILTER_VALIDATE_URL,
            'flags' => FILTER_FLAG_SCHEME_REQUIRED | FILTER_FLAG_HOST_REQUIRED | FILTER_FLAG_PATH_REQUIRED);
        if ($queryStringRequired) {
            $this->_filterArgs[$fieldName]['flags'] |= FILTER_FLAG_QUERY_REQUIRED;
        }
}

 

Validera URL

Denna metod är identisk med isFullURL(), förutom att det inte behöver börjar med; http:// , https://, eller ftp:// etc.:

/** 
 * @param string $fieldName
 * @param boolean $queryStringRequired
 */
public function isURL($fieldName, $queryStringRequired = false) {
        $this->checkDuplicateFilter($fieldName);
        $this->_filterArgs[$fieldName]['filter'] = FILTER_VALIDATE_URL;
        if ($queryStringRequired) {
            $this->_filterArgs[$fieldName]['flags'] = FILTER_FLAG_QUERY_REQUIRED;
        }
}

 

Validera Booleskt Värde

Filterfunktioner returnerar variabelns värde vid framgång, och false om inte valideringstestet lyckas. Detta innebär dock ett problem vid validering av ett booleskt värde eftersom, även om valideringstestet lyckas – kan värdet av variabeln som testats vara false. För att undvika den här typen av falska negativa, måste du lägga till en protected egenskap som vi kallar för $_booleans. Du måste också initiera den som en tom array i konstruktorn. Lägg till den högst upp i klassdefinitionen, och lägg till en sista rad i konstruktorn:

// efter raden $this->_errors = array();
$this->_booleans = array();

…och isBool() metoden ser ut så här:

/**
* Kollar om ett värde är booleskt
* @param string $fieldName
* @param boolean $nullOnFailure
*/
public function isBool($fieldName, $nullOnFailure = false) {
        $this->checkDuplicateFilter($fieldName);
        $this->_booleans[] = $fieldName;
        $this->_filterArgs[$fieldName]['filter'] = FILTER_VALIDATE_BOOLEAN;
        if ($nullOnFailure) {
            $this->_filterArgs[$fieldName]['flags'] = FILTER_NULL_ON_FAILURE;
        }
}

Förutom att ställa lämpliga filter argumenten, lägger denna metod namnet på den Boolean fältet till $ _booleans egenskapen. Detta används senare av validateInput() för att förhindra booleska fält från generera felmeddelanden.

 

Validera Reguljära Uttryck

Följande metod matchar ett värde mot en Perl-kompatibel reguljär uttryck (PCRE). Det tar två argument, som båda måste anges: namnet på fältet eller en variabel som testas och en PCRE (reguljärt uttryck). Om matchningen lyckas, ska hela värdet returneras, inte bara den matchande delen.

/**
 * Matchar ett värde mot en Perl-kompatibel reguljär uttryck (PCRE)
 * @param string $fieldName
 * @param string $pattern
 */
public function matches($fieldName, $pattern) {
        $this->checkDuplicateFilter($fieldName);
        $this->_filterArgs[$fieldName] = array(
            'filter' => FILTER_VALIDATE_REGEXP,
            'options' => array('regexp' => $pattern)
        );
}

 

Sanerings-Metoder

 

Sanera Strängar

Den första saneringsmetoden vi ska skapa sanerar strängar. Det tar bort alla taggar, inklusive HTML, PHP och XML, från en input array på ett liknande sätt som PHP:s strip_tags(). Men det finns en stor skillnad mot strip_tags() metoden som är att filterkonstanten; FILTER_SANITIZE_STRING, inte accepterar en lista över godtagbara taggar. Istället erbjuder den en mycket strängare tillvägagångssätt med alternativ för att ta bort eller omkoda tecken som har ett ASCII-värde på mindre än 32 eller större än 127. Det kodar även valfritt et-tecken (&) och bevarar citationstecken.

Med så många alternativ blev det enklare sätta dom alla till FALSE som standard. Så, om removeTags() används med endast namnet på den variabel eller fält som ska saneras, avlägsnas HTML-, PHP- och XML-taggar, enkla och dubbla citationstecken omvandlas, medan et-tecken (&) lämnas orörda.

Här kommer removeTags():

/**
 * @param string $fieldName
 * @param boolean $encodeAmp
 * @param boolean $preserveQuotes
 * @param boolean $encodeLow
 * @param boolean $encodeHigh
 * @param boolean $stripLow
 * @param boolean $stripHigh
 */
public function removeTags($fieldName, $encodeAmp = false, $preserveQuotes = false, $encodeLow = false, $encodeHigh = false, $stripLow = false, $stripHigh = false) {
        $this->checkDuplicateFilter($fieldName);
        $this->_filterArgs[$fieldName]['filter'] = FILTER_SANITIZE_STRING;
        $this->_filterArgs[$fieldName]['flags'] = 0;
        if ($encodeAmp) {
            $this->_filterArgs[$fieldName]['flags'] |= FILTER_FLAG_ENCODE_AMP;
        }
        if ($preserveQuotes) {
            $this->_filterArgs[$fieldName]['flags'] |= FILTER_FLAG_NO_ENCODE_QUOTES;
        }
        if ($encodeLow) {
            $this->_filterArgs[$fieldName]['flags'] |= FILTER_FLAG_ENCODE_LOW;
        }
        if ($encodeHigh) {
            $this->_filterArgs[$fieldName]['flags'] |= FILTER_FLAG_ENCODE_HIGH;
        }
        if ($stripLow) {
            $this->_filterArgs[$fieldName]['flags'] |= FILTER_FLAG_STRIP_LOW;
        }
        if ($stripHigh) {
            $this->_filterArgs[$fieldName]['flags'] |= FILTER_FLAG_STRIP_HIGH;
        }
}

Notera hur flaggorna hanteras. Varje flagga har bakom kulisserna en konstant som representeras av ett heltal. Så, när inga flaggor är inställda behöver $_flags subarray bli satt till 0;

$this->_filterArgs[$fieldName]['flags'] => 0

 

Om argumentet för en flagga är satt till true, kommer dess värde att läggas till med hjälp bitvis kombinerade tilldelningsoperatorn |=.

Notera – Det stora antalet alternativ i föregående metod och följande är opraktiskt om man behöver aktivera dem regelbundet. Vi kunde ha skapat olika metoder för varje kombination av alternativen, men det skulle ha lagt till en ny nivå av komplexitet, att tvinga användarna att komma ihåg vad varje metod gör. Vid utformningen av en klass, måste man bestämma hur ofta en funktion är sannolikt kommer att användas. Där finns det tyvärr ingen formel för att få rätt balans, utan man får ta det från fall till fall.

 

 

Sanera Array genom att avlägsna taggar

Följande metod är identisk med den förra, förutom att den bearbetar innehållet i en array.

Koden ser ut så här:

/**
 * @param string $fieldName
 * @param boolean $encodeAmp
 * @param boolean $preserveQuotes
 * @param boolean $encodeLow
 * @param boolean $encodeHigh
 * @param boolean $stripLow
 * @param boolean $stripHigh
 */
public function removeTagsFromArray($fieldName, $encodeAmp = false, ➥ $preserveQuotes = false, $encodeLow = false, $encodeHigh = false, $stripLow = false, $stripHigh = false) {
        $this->checkDuplicateFilter($fieldName);
        $this->_filterArgs[$fieldName]['filter'] = FILTER_SANITIZE_STRING;
        $this->_filterArgs[$fieldName]['flags'] = FILTER_REQUIRE_ARRAY;
        if ($encodeAmp) {
            $this->_filterArgs[$fieldName]['flags'] |= FILTER_FLAG_ENCODE_AMP;
        }
        if ($preserveQuotes) {
            $this->_filterArgs[$fieldName]['flags'] |= FILTER_FLAG_NO_ENCODE_QUOTES;
        }
        if ($encodeLow) {
            $this->_filterArgs[$fieldName]['flags'] |= FILTER_FLAG_ENCODE_LOW;
        }
        if ($encodeHigh) {
            $this->_filterArgs[$fieldName]['flags'] |= FILTER_FLAG_ENCODE_HIGH;
        }
        if ($stripLow) {
            $this->_filterArgs[$fieldName]['flags'] |= FILTER_FLAG_STRIP_LOW;
        }
        if ($stripHigh) {
            $this->_filterArgs[$fieldName]['flags'] |= FILTER_FLAG_STRIP_HIGH;
        }
}

Standardvärdet för $_filterArgs subarray är satt till:

$this->_filterArgs[$fieldName]['flags'] = FILTER_REQUIRE_ARRAY;

Detta applicerar filterfunktionen till varje element i arrayen, inklusive nästlade arrayer.

 

 

Sanera sträng » omvandla specialtecken

Följande metod omvandlar enkla och dubbla citationstecken, <>, &, och tecken med en ASCII-värde på mindre än 32 till HTML enheter. Dom valfria argumenten kollar om det gäller en array, om man ska koda tecken med ASCII värde större än 127, eller ta bort låga och höga specialtecken. Flaggorna ställs in precis som i removeTags().

Koden för useEntities() ser ut så här:

/**
 * @param string $fieldName
 * @param boolean $isArray
 * @param boolean $encodeHigh
 * @param boolean $stripLow
 * @param boolean $stripHigh
 */
public function useEntities($fieldName, $isArray = false, $encodeHigh = false, $stripLow = false, $stripHigh = false) {
        $this->checkDuplicateFilter($fieldName);
        $this->_filterArgs[$fieldName]['filter'] = FILTER_SANITIZE_SPECIAL_CHARS;
        $this->_filterArgs[$fieldName]['flags'] = 0;
        if ($isArray) {
            $this->_filterArgs[$fieldName]['flags'] |= FILTER_REQUIRE_ARRAY;
        }
        if ($encodeHigh) {
            $this->_filterArgs[$fieldName]['flags'] |= FILTER_FLAG_ENCODE_HIGH;
        }
        if ($stripLow) {
            $this->_filterArgs[$fieldName]['flags'] |= FILTER_FLAG_STRIP_LOW;
        }
        if ($stripHigh) {
            $this->_filterArgs[$fieldName]['flags'] |= FILTER_FLAG_STRIP_HIGH;
        }
}

 

 

Kontrollera Textlängden

Detta är den enda valideringsmetod som inte använder någon av filterfunktionerna eller konstanterna, så det kan användas i kombination med en av våra andra metoder. Den använder PHP strlen() för att fastställa antalet tecken i den angivna strängen, och förbereder lämpliga felmeddelanden som läggs till i $_errors. Liksom alla andra verifieringsmetoder, är det första argumentet namnet på fältet eller variabeln som man vill kontrollera.

Eftersom vi vill kontrollera innehållet i fältet eller variabeln, är det nödvändigt att hämta det från $_submitted, som innehåller en array med alla inlämnade data. Det andra argumentet $min representerar det lägsta antalet acceptabla tecken och är ett obligatoriskt argument. Det tredje argumentet är frivilligt och sätter det högsta antalet tecken. Eftersom $ min behövs, vi sätta den till 0 som standard, om vi bara vill begränsa det maximala antalet tecken tillåtna.

/**
 * @param string $fieldName
 * @param int $min
 * @param int $max
 * @throws Exception
 */
public function checkTextLength($fieldName, $min, $max = null) {
        // Hämta angivet värde
        $text = trim($this->_submitted[$fieldName]);
        // Kolla så att det är en sträng
        if (!is_string($text)) {
            throw new Exception("checkTextLength() metoden kan bara appliceras på strängar; $fieldName är fel datatyp.");
        }
        // Kolla att det andra argumentet är ett nummer
        if (!is_numeric($min)) {
            throw new Exception("checkTextLength() metoden förväntar sig ett nummer som andra argument (fält namn: $fieldName)");
        }
        // Om strängen är kortare är det angivna minimum, skapa error-meddelande
        if (strlen($text) < $min) {
            // Kolla så att ett giltigt max värde har satts
            if (is_numeric($max)) {
                $this->_errors[$fieldName] = ucfirst($fieldName) . " måste vara mellan $min och $max tecken.";
            } else {
                $this->_errors[$fieldName] = ucfirst($fieldName) . " måste vara minst $min antal tecken.";
            }
        }
        // Om ett maximum har satts, och strängen är för lång, generera felmeddelande
        if (is_numeric($max) && strlen($text) > $max) {
            if ($min == 0) {
                $this->_errors[$fieldName] = ucfirst($fieldName) . " måste vara under $max tecken.";
            } else {
                $this->_errors[$fieldName] = ucfirst($fieldName) . " måste vara mellan $min och $max tecken.";
            }
        }
}

 

 

Specialhantering av Data

Följande metod använder filterkonstanten; FILTER_UNSAFE_RAW för att hantera data som man vill behandla på ett sätt som inte täcks av de andra metoderna. Den har två alternativ: antingen hantera en array eller avkoda et-tecken (&). Skälet till att skapa denna till synes värdelösa metod är att lägga data till en arrayn av filtrerade objekt. Man kan sedan loopa igenom den filtrerade arrayen, övertygad om att den endast innehåller variabler som man redan har specifierat.

Koden ser ut så här:

/** 
 * @param string $fieldName
 * @param boolean $isArray
 * @param boolean $encodeAmp
 */
public function noFilter($fieldName, $isArray = false, $encodeAmp = false) {
        // Kolla så att inga andra valideringstester har blivit appliserade på samma inmatning
        $this->checkDuplicateFilter($fieldName);
        // Sätt filter alternativ 
        $this->_filterArgs[$fieldName]['filter'] = FILTER_UNSAFE_RAW;
        // Multipla flaggor sätts med "binary eller bitvis" operator
        $this->_filterArgs[$fieldName]['flags'] = 0;
        if ($isArray) {
            $this->_filterArgs[$fieldName]['flags'] |= FILTER_REQUIRE_ARRAY;
        }
        if ($encodeAmp) {
            $this->_filterArgs[$fieldName]['flags'] |= FILTER_FLAG_ENCODE_AMP;
        }
}

 

Testa Medlemsvariabeln; $_filterArgs

Valideringsmetoderna vi har skapat är ansvariga för att fylla $_filterArgs, vilket är en array som specificerar alla filter, alternativ och flaggor som man vill använda på alla inmatningsvariabler. Det är viktigt att se till att arrayen byggs på rätt sätt, så följande övning tillämpar vissa valideringstest till ett formulär för att se vad $_filterArgs innehåller.

<!-- test_validator2.php -->
<?php
if (filter_has_var(INPUT_POST, 'send')) {
    require_once 'my_validator.php';
    $required = array('name', 'email', 'comments');
    // skapa en ny instans av MyValidator med argumentet $reqguired
    // eftersom konstruktorn använder som standard $_POST, är det därifrån datan hämtas 
    $val = new My_Validator($required);
    // kolla att texten är minst 3 tecken lång
    $val->checkTextLength('name', 3);
    // ta bort taggar från namn-fält
    $val->removeTags('name');
    // kolla om email fältet innehåller en email adress
    $val->isEmail('email');
    // testa om comments är mellan 10 och 500 tecken
    $val->checkTextLength('comments', 10, 500);
    // 
    $val->useEntities('comments');
    echo '<pre>';
    print_r($val->_filterArgs);
    print_r($val->_errors);
    echo '</pre>';
}
?>
<!DOCTYPE html>
<html lang="sv-SE">
    <head>
        <meta charset="utf-8" />
        <title>Testa Obligatoriska Fält</title>
        <style type="text/css">
            body {
                font-family: Arial, Helvetica, sans-serif;
                color: #000;
                background-color: #FFF;
                width: 700px;
                margin: 20px auto;
            }

            label {
                font-weight: bold;
                display: block;
            }

            form {
                margin-left: 50px;
            }

            #comments {
                height: 100px;
                width: 400px;
            }

            .textfield {
                width: 250px;
            }

            .warning {
                color: #f00;
                font-weight: bold;
            }
        </style>
    </head>

    <body>
        <form id="form1" name="form1" method="post" action="">
            <label for="name">Namn:</label> 
            <input name="name" type="text" class="textfield" id="name" />
            <label for="email">Email:</label> 
            <input name="email" type="text" class="textfield" id="email" />
            <label for="comments">Kommentarer:</label> 
            <textarea name="comments" id="comments" cols="45" rows="5"></textarea>
            <input type="submit" name="send" id="send" value="Send comments" />
        </form>
    </body>
</html>

Denna validering tillämpar kontroller på de tre fälten i formuläret och sedan använder print_r() mellan <pre> taggar för att visa innehållet i $ _filterArgs och $_errors.

$_filterArgs och $_errors är deklarerade som protected egenskaper, så man måste ändra det tillfälligt till public:

public $_errors;
public $_filterArgs;

Spara båda sidor, ladda formuläret i en webbläsare och klicka på skicka-knappen. Du bör se liknande ut som den nedan:

Testa My_Validator class
Testa My_Validator class

Nu ska vi testa om checkDuplicateFilter() fungerar som den ska genom att använda ett till filter på comments. Skriv in följande rad någonstans i kodblocket:

$val->removeTags('comments');

Du bör nu få ett felmeddelande eftersom checkDuplicateFilter() kastar ett undantag:

Exeption dubbla filter
Exeption dubbla filter

 

Bearbeta tester och returnera resultaten

Nu när vi har byggt en array med filter, alternativ och flaggor, är allt som återstår att skicka det till filter_input_array(). Den tar två argument: vilken typ inmatnings (som vi har i $ _inputType) och arrayn av filter (lagrad i $_filterArgs). Denna funktionen returnerar en array som innehåller det filtrerade och validerade inmatningen, och lagrar det i $_filtered medlemsvariabel. Och, allt detta hårda arbete utförts av ett enda kommando:

$this->_filtered = filter_input_array($this->_inputType, $this->_filterArgs);

Men för att få validerarklass ska producera användbara resultat, behöver vi några fler steg. Först av allt, är hela poängen med att använda en validator till se till att resten av skriptet får endast hanterar data som du vet har filtrerats. Så, efter att ha satt $_POST eller $_GET array som indata, bör man inte längre ha direkt tillgång till datan den innehåller, i stället ska man alltid ta det från $_filtered. Detta innebär att det inte finns någon mening med att ange ett fält som $_required om man inte ska tillämpa någon av valideringsmetoder på den.

Den andra saken som vi behöver göra, är att bygga en lista över objekt som misslyckats valideringen. Egentligen borde det vara alla element som returnerar FALSE från $_filtered arrayn, men riktigt så enkelt är det inte. Du måste utesluta allt som har passerat till isBool() valideringen, eftersom FALSE helt enkelt kan vara booleskt värde i den variabeln.

Vi måste också utesluta poster som har lagts till $_missing för att undvika rapportering av samma fel två gånger.

Vi utesluter även fält som inte markerats som $_required , med antagandet att, om det inte är ett nödvändigt fält, behöver man inte vara orolig för datan i den misslyckas valideringen. Sådana poster kommer att dyka upp i $_filtered som FALSE.

För att summera, behöver metoden validateInput() följande för att utföra dessa tre uppgifter:

1. Kontrollera att alla obligatoriska fält har filtrerats.
2. Applicera filtren på ingångsdata, och lagra resultatet i $_filtered.
3. Skapa en lista över objekt som misslyckats valideringen och lagras dess namn i $_errors.

Den kommenterade koden för validateInput() pkommer här:

/**
 * Bearbeta tester och returnera resultaten
 * @return array => $this->_filtered
 * @throws Exception
 */
public function validateInput() {
        // Initialisera en array för required fält som inte har validerats
        $notFiltered = array();
        // Hämta namnen på fälten som har validerats
        $tested = array_keys($this->_filterArgs);
        // Loopa igenom obligatoriska fält
        // Lägg till saknade i $notFiltered array
        foreach ($this->_required as $field) {
            if (!in_array($field, $tested)) {
                $notFiltered[] = $field;
            }
        }
        // Om några objekt har lagts till $ notFiltered array, 
        // betyder det att ett föremål som krävs inte har validerats, så kasta ett undantag
        if ($notFiltered) {
            throw new Exception('Följande fält fattades:<br />' . implode(',<br />', $notFiltered));
        }
        // Tillämpa validerings testet med filter_input_array()
        $this->_filtered = filter_input_array($this->_inputType, $this->_filterArgs);
        foreach ($this->_filtered as $key => $value) {
            // Hoppa poster som använde isBool() metod eller som antingen saknas eller inte krävs
            if (in_array($key, $this->_booleans) || in_array($key, $this->_missing) || !in_array($key, $this->_required)) {
                continue;
            } elseif ($value === false) {
                // Om det filterade värdet blir false, misslyckades valideringen,
                // och läggs då till $_errors array
                $this->_errors[$key] = ucfirst($key) . ': invalid data supplied';
            }
        }
        // Returnera validerade inmatningen från medlemsvariabeln $_filtered
        return $this->_filtered;
}

Allt som återstår är att tillhandahålla public metoder för att ger tillträde till den skyddade $_missing, $_filtered och $_errors (eftersom alla medlemsvariabler är protected). Var och en returnerar helt enkelt egenskapen som du kan se av följande kod:

/**
 * Returnerar en array av obligatoriska fält som inte fyllts i
 * @return array Indexed array of names of missing fields or variables.
 */
public function getMissing() {
    return $this->_missing;
}

/**
 * Returnerar en array med den filtrerade datan efter validering.
 * @return array -> En Multidimensionell associativ array av fält (variable) namn & filtrerade värden
 */
public function getFiltered() {
    return $this->_filtered;
}

/**
 * Returnerar en array innehållande namnen på fält eller variabler som inte passerade validering
 * @return array -> En Indexerad array av fält (variabler) som inte passerade validering
 */
public function getErrors() {
    return $this->_errors;
}

Okej, det var all kod för My_Validator klassen. Lämna gärna en kommentar om du undrar över något eller har synpunkter.

 

Jag hoppas att du kan dra nytta av klassen i framtiden, och till nästa gång – Koda Smart 🙂