Niezalogowany [ logowanie ]
Subskrybuj kanał ATOM Kanał ATOM    Subskrybuj kanał ATOM dla tagu php Kanał ATOM (tag: php)

Autor wpisu: Diabl0, dodany: 05.07.2012 01:07, tagi: zend_framework, php

Tym razem poruszę jednocześnie dwie kwestie – tworzenie i obsługę webservices oraz zarządzanie uprawnieniami.

Zanim zaczniemy z autoryzacją i prawami dostępu musimy mieć usługi które udostępniamy. Nie wiem czy wszyscy zdają sobie sprawę że z pomocą ZF w miarę prosto i szybko można za jednym zamachem stworzyć usługi obsługiwane za pomocą trzech najbardziej obecnie popularnych protokołów: XML-RPC, Json-RPC i SOAP.

Stworzymy sobie kontroler do obsługi usług (w moim przypadku main_ServicesController) a w nim 3 metody – każda dla osobnego protokołu.

class main_ServicesController extends Mao_Controller_Action {
	/**
	 *
	 * Server JSON-RPC
	 */
	public function jsonAction()
	{
		$this->disableLayoutAndViews();

		$server = new Zend_Json_Server();

		$this->_setClasses($server);

		if ('GET' == $_SERVER['REQUEST_METHOD']) {
			$server
			->setTarget( 'http://' . $_SERVER['HTTP_HOST'] . '' . $this->view->url(array('module' => 'main', 'controller' => 'services', 'action' => 'json' )) )
			->setEnvelope(Zend_Json_Server_Smd::ENV_JSONRPC_2);
			$smd = $server->getServiceMap();

			header('Content-Type: application/json');
			echo $smd;
			return;
		}

		echo $server->handle();
	}

	/**
	 *
	 * Server XML-RPC
	 */
	public function xmlAction()
	{
		$this->disableLayoutAndViews();

		Zend_XmlRpc_Value::setGenerator(new Zend_XmlRpc_Generator_XmlWriter());

	    // Specify a cache file
	    $cacheFile = APPLICATION_PATH . '/temp/xmlrpc.cache';

		$server = new Zend_XmlRpc_Server();

	    // Attempt to retrieve server definition from cache
	    if (!Zend_XmlRpc_Server_Cache::get($cacheFile, $server)) {
	        $this->_setClasses($server);

	        // Save cache
	        // @todo: uncomment when going live
	        //Zend_XmlRpc_Server_Cache::save($cacheFile, $server);
	    }

		echo $server->handle();

	}

	/**
	 *
	 * Server SOAP
	 */
	public function soapAction() {
		$this->disableLayoutAndViews();

		$serviceURL = $url = 'http://' . $_SERVER['HTTP_HOST'] . '' . $this->view->url(array('module' => 'main', 'controller' => 'services', 'action' => 'soap' ));

		// Generate WSDL relevant to code
		if (isset($_GET['wsdl'])){
		    $autodiscover = new Zend_Soap_AutoDiscover('Zend_Soap_Wsdl_Strategy_ArrayOfTypeComplex');
		    $this->_setClasses($autodiscover);
		    $autodiscover->handle();
		} else {
		    $server = new Zend_Soap_Server($serviceURL . "?wsdl");
		    $this->_setClasses($server);
		    $server->handle();
		}
	}

    /**
     * Sets classes for servers
     *
     * @param object $server
     */
	protected function _setClasses( $server ) {

		if ( method_exists( $server, 'setClass' ) ) {
			$server->setClass( 'main_services_Auth', 'auth' );
			$server->setClass( 'shop_services_Products', 'products' );
			$server->setClass( 'shop_services_Orders', 'orders' );
		}
	}

}

Jeden kontroller, 3 akcje, 3 protokoły.

Skoro mamy już zdefiniowane usługi to czas zająć się autoryzacją i uprawnieniami.

Niestety żaden z protokołów nie ma odgórnie ustalonych zasad realizacji tego problemu i w sieci można się spotkać z wieloma sposobami. Ja zamiast każdorazowe przekazywanie pełnych danych logowania zdecydowałem się na tzw. tokeny. Jedna metoda służy do uwierzytelnienia i wystawienia tokena który natomiast jest przekazywany przy wywoływaniu kolejnych metod.

Za logowanie odpowiada klasa:


class main_services_Auth extends main_services_Abstract {

	/**
	 *
	 * Login and generate login token.
	 *
	 * @param string $username username
	 * @param string $password password
	 * @param array $additional	optional additional informations (currently unused)
	 *
	 * @return array dod
	 */
	public function login( $username, $password, $additional = array() ) {

		// 1 - sprawdzamy usera i hasło
		$db = Zend_Registry::get ( 'db' );

		$authAdapter = new Zend_Auth_Adapter_DbTable ( $db );
		$authAdapter->setTableName ( 'users' );
		$authAdapter->setIdentityColumn ( 'username' );
		$authAdapter->setCredentialColumn ( 'password' );
		$authAdapter->setCredentialTreatment('MD5(?) AND active = 1');

		// Set the input credential values to authenticate against
		$authAdapter->setIdentity ( $username );
		$authAdapter->setCredential ( $password );

		$auth = Zend_Auth::getInstance ();
		$result = $auth->authenticate ( $authAdapter );

		if ($result->isValid ()) {
			//2 - sprawdzamy/generujemy token

			$tokensModel = new main_models_Services_LoginTokens();
			$tokenRow = $tokensModel->fetchTokenFor( $username, true );

			return array('status' => true, 'token' => $tokenRow->token);
		}

		return array('status' => false, 'error' => 'Unable to login');
	}
}

Jak widać dość typowe zendowska autoryzacja, jedyna różnica to to że po zalogowaniu nie zapisujemy danych użytkownika do Zend_Auth_Storate a jedynie zwracamy token logowania.

Samo generowanie tokena to:

Czytaj dalej tutaj (rozwija treść wpisu)
Czytaj dalej na blogu autora...

Autor wpisu: Łukasz Socha, dodany: 03.07.2012 19:33, tagi: php

pobierz w .pdf(przeznaczone do wydruku)

Trzecia część z serii wpisów o wzorcach projektowych. Tym razem omówię wzorzec projektowy Prototyp (Prototype).

 

Prototyp jest wzorcem, opisującym mechanizm tworzenie nowych obiektów poprzez klonowanie jednego obiektu macierzystego. Mechanizm klonowania wykorzystywany jest wówczas, gdy należy wykreować dużą liczbę obiektów tego samego typu lub istnieje potrzeba tworzenia zbioru obiektów o bardzo podobnych właściwościach.

Diagram klas wzorca Prototype

Implementując ten wzorzec deklaruje się klasę Prototype z abstrakcyjną operacją klonującą clone(). Operacja ta jest implementowana w klasach dziedziczonych po Prototype. Klient chcąc stworzyć nowy obiekt wywołuje metodę clone() pośrednio, za pomocą zdefiniowanej przez siebie operacji z parametrem określającym wymaganą docelową klasę realizującą abstrakcję Prototype.

Przykładowa implementacja

<?php
abstract class Prototype{
    protected $name;

    public function __construct($name) {
        $this->name=$name;
    }
     abstract function __clone();
    public function getName() {
        return $this->name;
    }
}

class ConcretePrototype extends Prototype{
    
    public function __construct($name) {
        parent::__construct($name);
    }
    public function __clone() {}
}

// testy
$prototype = new ConcretePrototype("nazwa");
echo  $prototype->getName(); // wyswietli "nazwa"
$prototype2 = clone $prototype;
echo  $prototype2->getName(); // wyswietli "nazwa"
?>

Przykład z życia wzięty

Przypuśćmy, że tworzymy księgarnię internetową. Istnieje potrzeba stworzenia wielu obiektów książek o podobnych właściwościach (wspólna kategoria, autor itp.). Zamiast ustawiać pola dla każdego obiektu oddzielnie możemy wykonać klony i zmieniać tylko elementy unikalne.

<?php
abstract class Book {
    protected $title;
    protected $topic;
    abstract function __clone();
    public function getTitle() {
        return $this->title;
    }
    public function setTitle($title) {
        $this->title = $title;
    }
    public function getTopic() {
        return $this->topic;
    }
}

class PHPBook extends Book {
    public function __construct() {
        $this->topic = 'PHP';
    }
    function __clone() {
    }
}

class JAVABook extends Book {
    public function __construct() {
        $this->topic = 'JAVA';
    }
    function __clone() {
    }
}
 
//testy
$phpbook1 = new PHPBook();
$phpbook1->setTitle("Ksiazka1");
$phpbook2 = clone $phpbook1;
$phpbook2->setTitle("Ksiazka2");

$javabook1 = new JAVABook();
$javabook1->setTitle("Ksiazka1");
$javabook2 = clone $javabook1;
$javabook2->setTitle("Ksiazka2");

echo "Kategoria: ".$phpbook1->getTopic()." Tytul: ".$phpbook1->getTitle()."<br />";
echo "Kategoria: ".$phpbook2->getTopic()." Tytul: ".$phpbook2->getTitle()."<br />";
echo "Kategoria: ".$javabook1->getTopic()." Tytul: ".$javabook1->getTitle()."<br />";
echo "Kategoria: ".$javabook2->getTopic()." Tytul: ".$javabook2->getTitle()."<br />";
?>

Zastosowanie

Wzorzec Prototype można stosować w sytuacjach, gdy tworzona jest duża liczba obiektów tego samego typu. Stosuje się go głównie w celach optymalizacji, gdyż klonowanie obiektu jest szybsze niż jego stworzenie.

PS: Może ktoś napisze miarodajne testy? ;)

Powiązane tematy

Autor wpisu: Marek, dodany: 03.07.2012 17:26, tagi: php, javascript

Literalna próba zapisu znaków specjalnych przy użyciu js powoduje dosłowne ich wyświetlenie:

<script type="text/javascript">
  alert('&raquo;')
  alert('&laquo;')
</script>

Możemy to zapisać również używając innej notacji:

<script type="text/javascript">
  alert('&#187;')
  alert('&#170;')
</script>

Ale i to zostaje przepisane. Aby uzyskać żądany efekt należy użyć funkcji fromCharCode oraz kodu danego znaku – dla &raquo; (czyli &#187;) będzie to 187:

<script type="text/javascript">
  alert(String.fromCharCode(187))
  alert(String.fromCharCode(171))
</script>

Autor wpisu: Łukasz Socha, dodany: 01.07.2012 16:20, tagi: php

pobierz w .pdf(przeznaczone do wydruku)

Druga część z serii wpisów o wzorcach projektowych. Dziś omówię wzorzec Strategii (Strategy).

 

Strategia jest wzorcem projektowym, który definiuje rodzinę wymiennych algorytmów i kapsułkuje je w postaci klas. Dzięki temu umożliwia wymienne stosowanie każdego z nich w trakcie działania programu.

Diagram klas wzorca Strategy

Przykładowa implementacja

<?php
interface AbstractStrategy{
    function task();
}
class ConcreteStrategy1 implements AbstractStrategy{
    public function task() {
        echo "Strategy 1";
    }
}
class ConcreteStrategy2 implements AbstractStrategy{
    public function task() {
        echo "Strategy 2";
    }
}
class Context{
    private $strategy;
    
    public function setStrategy(AbstractStrategy $obj) {
        $this->strategy=$obj;
    }
    public function getStrategy() {
        return $this->strategy;
    }
}
// testy
$obj = new Context();
$obj->setStrategy(new ConcreteStrategy1);
$obj->getStrategy()->task(); // wyswietla „Strategy 1”
$obj->setStrategy(new ConcreteStrategy2); 
$obj->getStrategy()->task(); // wyswietla „Strategy 2”
?>

We wzorcu tym definiujemy wspólny interfejs dla wszystkich strategii. Następnie, w poszczególnych klasach implementujemy metody z konkretnymi już algorytmami. Za pomocą klasy Context możemy łatwo zmieniać używaną strategię w trakcie działania aplikacji.

Przykład z życia wzięty

Przypuśćmy, że tworzymy sklep internetowy oferujący swoje usługi w kilku państwach. Jak wiadomo prawo podatkowe znacząco różni się w poszczególnych krajach. Powstaje problem naliczenia odpowiedniego podatku dla klientów pochodzących z odmiennych państw. Jak to rozwiązać? Wybrać odpowiednią stawkę za pomocą licznych instrukcji warunkowych? Nie, do tego świetnie nadaje się wzorzec strategii.

<?php

interface Tax{
    public function count($net);
}

class TaxPL implements Tax{
    public function count($net) {
        return 0.23*$net;
    }
}

class TaxEN implements Tax{
    public function count($net) {
        return 0.15*$net;
    }
}

class TaxDE implements Tax{
    public function count($net) {
        return 0.3*$net;
    }
}

class Context{
    private $strategy;
    
    public function setCountry($country) {
        switch ($country) {
            case "PL":
                $this->strategy = new TaxPL();
                break;
            case "DE":
                $this->strategy = new TaxDE();
                break;
            case "EN":
                $this->strategy = new TaxEN();
                break;
        }
    }
    public function getTax() {
        return $this->strategy;
    }
}

// testy
$tax = new Context();
$tax->setCountry("PL");
echo $tax->getTax()->count(100); // wyswietla "23"
$tax->setCountry("EN");
echo $tax->getTax()->count(100); // wyswietla "15"
$tax->setCountry("DE");
echo $tax->getTax()->count(100); // wyswietla "30"

?>

Za pomocą metody setCountry() możemy w bardzo prosty sposób wybierać odpowiednią strategię obliczania podatku dostosowaną do państwa, z którego pochodzi nasz klient. Jeżeli sklep zdecyduje się na poszerzenie działalności o kolejny kraj, wystarczy tylko dopisać odpowiednią klasę implementującą interfejs Tax oraz dodać do switch’a odpowiedni warunek.

Zalety i wady

Zalety:

  • Eliminacja instrukcji warunkowych – kod jest bardziej przejrzysty.
  • Umożliwia wybór implementacji – algorytmy mogą rozwiązywać ten sam problem, lecz różnić się uzyskiwanymi korzyściami.
  • Łatwość dołączania kolejnych strategii.
  • Łatwiejsze testowanie programu – można debugować każdą strategię z osobna.

Wady:

Czytaj dalej tutaj (rozwija treść wpisu)
Czytaj dalej na blogu autora...

Autor wpisu: Łukasz Socha, dodany: 29.06.2012 18:25, tagi: php

pobierz w .pdf(przeznaczone do wydruku)

Tym postem rozpoczynam kolejny cykl postów – tym razem o wzorcach projektowych przydatnych w projektowaniu i programowaniu aplikacji webowych. Na początek opiszę jeden z najprostszych, a zarazem dość popularny wzorzec – Singleton.

Singleton jest jednym z najprostszych wzorców projektowych. Jego celem jest ograniczenie możliwości tworzenia obiektów danej klasy do jednej instancji oraz zapewnienie globalnego dostępu do stworzonego obiektu – jest to obiektowa alternatywa dla zmiennych globalnych.

Diagram klasy wzorca Singleton

Singleton implementuje się poprzez stworzenie klasy, która posiada statyczną metodę getInstance(). Metoda ta sprawdza, czy istnieje już instancja tej klasy, jeżeli nie – tworzy ją i przechowuje jej referencję w prywatnym polu. Aby uniemożliwić tworzenie dodatkowych instancji, konstruktor klasy deklaruje się jako prywatny lub chroniony.

Przykładowa implementacja

<?php
class Singleton {
    private static $instance;
    private function __construct() {} konstruktor publiczny
    private function __clone() {} 
    public static function getInstance() {
        if(self::$instance === null) {
            self::$instance = new Singleton();
        }
        return self::$instance;
    }
}
$singleton = Singleton::getInstance();
?>

Zalety i wady

Zalety:

  • Pobieranie instancji klasy jest niewidoczne dla użytkownika. Nie musi on wiedzieć, czy w chwili wywołania metody instancja istnieje czy dopiero jest tworzona.
  • Tworzenie nowej instancji zachodzi dopiero przy pierwszej próbie użycia.
  • Klasa zaimplementowana z użyciem wzorca singleton może samodzielnie kontrolować liczbę swoich instancji istniejących w aplikacji.

Wady:

  • Brak elastyczności, ponieważ już na poziomie kodu, na „sztywno” określana jest liczba instancji klasy.
  • Utrudnia testowanie i usuwanie błędów w aplikacji.

Zastosowanie

Programując w PHP używa się wzorca Singleton do przechowywania konfiguracji aplikacji oraz utrzymania połączenia z bazą danych. Jednak, warto pamiętać o wadach tego wzorca i korzystać z niego rozważnie. Zbyt częste stosowanie wzorca Singleton pogarsza przejrzystość kodu.

Autor wpisu: Marek, dodany: 21.06.2012 17:17, tagi: php, apache

Podczas próby uruchomienia aplikacji opartej o framework Kohana3.2 na lokalnym Apache’u przywitał mnie Internal Server Error z informacją w logu:

.htaccess: order not allowed here

W pliku .htaccess był wpis:

# Protect hidden files from being viewed
<Files .*>
	Order Deny,Allow
	Deny From All
</Files>

Aby umożliwić korzystanie z dyrektywy Files w pliku .htaccess trzeba w konfiguracji Apache’a pozwolić mu na to przez:

AllowOverride Limit

Po restarcie serwera WWW znów powitał mnie błąd 500 z informacją w logu:

.htaccess: SetEnv not allowed here

W pliku .htaccess była próba ustawienia środowiska:

SetEnv development

I tutaj również nadrzędne AllowOverride None nie pozwalało użyć tej dyrektywy w pliku .htaccess.

Rozwiązaniem jest dopisanie do konfiguracji:

AllowOverride FileInfo

Ostatecznie sekcja Directory może wyglądać tak:

<Directory "/sciezka/do/katalogu/www/">
Options -Indexes FollowSymLinks
AllowOverride Limit FileInfo
Order allow,deny
Allow from all
</Directory>

Autor wpisu: batman, dodany: 18.06.2012 15:30, tagi: php

Kilka miesięcy temu ekipa odpowiedzialna za największe polskie forum dla programistów PHP, we współpracy z Microsoftem, zorganizowała konkurs Rockstar Programmer. W skrócie polegał on na stworzeniu aplikacji w języku PHP działającej w chmurze Windows Azure. Miałem ten zaszczyt i zasiadłem w jury, którego zadaniem miała być ocena nadesłanych prac.

Dzisiaj w końcu poznaliśmy laureatów, a dokładniej laureata. Oto oficjalny komunikat zamieszczony na forum.php.pl.

Na wstępie dziękuję w imieniu całego zespołu za zainteresowanie konkursem. W konkursie wzięło udział 120 uczestników.

Decyzja komisji w Kategorii Zaawansowanej: Ze wszystkich przesłanych prac wybraliśmy tylko jedną która wg naszej opinii była możliwa do oceny. I właśnie tę prace zdecydowaliśmy się wyróżnić nagrodą II stopnia czyli 5000 PLN. Jest to praca Michała Czerskiego, której projekt znajduje się pod adresem: http://piclastic.com/ Składam wyrazu szacunku oraz gratulacje dla Michała za jego dzieło!

Komisja jednocześnie podjęła decyzję o nie przyznaniu nagrody za I miejsce.

Decyzja komisji w Kategorii Podstawowej: Tutaj sami się zaskoczycie. Choć zasady były proste to jednak dostarczono jedną pracę, która była niepełna, autor nie odpowiedział na naszą prośbę oraz przysłana po czasie. Z tych powodów nie podlegała ocenie. NIe dostarczono ani jednej pracy i tym samym nikt nie wygrał konsol.

Pieniądze przeznaczone na nagrody zostały przekazane na dalsze konkursy.

Ja ze swojej strony pragnę podziękować uczestnikom za udział zaś Michałowi ponownie złożyć gratulacje.

Do zobaczenia na kolejnym może mniej wymagającym konkursie !

Dołączam się do gratulacji i życzę powodzenia w kolejnych konkursach!

Czytaj dalej tutaj (rozwija treść wpisu)
Czytaj dalej na blogu autora...

Wszystkie wpisy należą do ich twórców. PHP.pl nie ponosi odpowiedzialności za treść wpisów.