Niezalogowany [ logowanie ]
Subskrybuj kanał ATOM Kanał ATOM

Autor wpisu: sokzzuka, dodany: 03.10.2010 23:59, tagi: php

Zyx ma ciekawe przemyślenia, ja również je mam (tak mi się zdaje) więc tym razem moje RE, będzie dotyczyć jego artykułu pt. poeksperymentujmy z kontrolą uprawnień. Przedstawił on w swoim artykule sposób na weryfikacje czy dany kod ma dostęp do innego kodu na podstawie domen. Domena była obszarem gdzie obowiązywała dana polityka bezpieczeństwa, jeżeli zewnętrzny kod chciał na niej wykonać jakąś operacje, musiał wywołać metodę safeOperation z argumentami charakterystycznymi dla danej operacji i podać domenę z której pochodzi. Metoda safeOperation weryfikowała za pomocą policyManagera czy kod z innej domeny ma prawo wywołać daną operację i jeżeli ich nie posiadał to wyrzucany był wyjątek.

Rozwiązanie, które tu przedstawię jest w pewnym sensie generalizacją koncepcji Zyx-a. Na czym ono polega ?

Pierwsze założenie jest takie, że wszystkimi obiektami (a przynajmniej tymi które chcemy zabezpieczyć) zarządzą kontener IoC (inversion of control). Jest to maszynka, która tworzy nam i konfiguruje obiekty. Mój kontener IoC ma tą ciekawą właściwość, że pozwala zwracać zamiast żądanego obiektu jego proxy. Proxy jest obiektem przez którego przelatują wszystkie żądania do docelowego obiektu i posłuży on do kontroli uprawnień.

Cała idea leży w tym, że proxy przy próbie wywołania metody na obiekcie docelowym, sprawdzi w Acl, czy aktualny użytkownik (może być cokolwiek innego np wywołujący obiekt) ma uprawnienia do wywołania owej metody i jeżeli nie to rzuci wyjątkiem.

Żeby nie być gołosłownym, przedstawię fragmenty kodu jak to działa, na końcu artykułu będzie też link do kompletnego przykładu razem z moim kontenerem IoC.

Po pierwsze konfiguracja IoC (pełną informacje o konfiguracji znajdziesz w artykule o kontenerze IoC):

<object-config>
    <application>
        <!-- For now empty, objects declared here will be cached by APC or something similiar -->
    </application>
    <session>

    </session>
    <request>   

        <object class="Foo1">
            <property name="param2">other_baz</property>
            <property name="param1">baz</property>
            <proxy class="AccessProxy" />
        </object>
        <object class="AccessProxy">
            <property name="acl" type="class">Acl</property>
        </object>
        <object class="Acl">
            <property name="user" type="class">User</property>
        </object>

    </request>
</object-config>

I klasy biorące udział w eksperymencie: klasa docelowa:

class Foo1 {

    private $param1;
    private $param2;

    function __construct($param1, $param2){
        $this->param1 = $param1;
        $this->param2 = $param2;
    }

    function doHello(){
        echo 'hello <br/>';
    }

    function doFoo(){
        echo 'foo <br/>';
    }

}

Klasa Acl:

class Acl {

    protected $_user;
    public function __construct(User $user){
        $this->_user = $user;
    }

    public function isCallable($class, $method){

        if($this->_user->id == 10 and $method == 'doHello'){
            return true;
        }
        if($this->_user->id == 15 and $method == 'doFoo'){
            return true;
        }
        return false;
    }
}

Minimalistyczna klasa użytkownika ;)

class User {
    public $id = 10;
}

oraz najważniejsze – klasa proxy:

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

Autor wpisu: batman, dodany: 02.10.2010 21:00, tagi: zend_framework

Podczas pracy z Zend_Db_Table bardzo doskwierał mi brak metod, które automatycznie pobierałyby dane na podstawie nazwy metody. A co robi programista, któremu brakuje jakiejś funkcjonalności? Sam ją dopisuje. Po połączeniu tej funkcjonalności z automatycznym tworzeniem obiektu DbTable, powstał “magiczny model”.

Jeśli nie wiecie o czym piszę, za chwilę wszystko stanie się jasne. Załóżmy, że mamy w bazie danych tabelę users, o następującej strukturze (baza MySQL):

CREATE  TABLE IF NOT EXISTS `batman`.`users` (
  `iduser` INT NOT NULL AUTO_INCREMENT ,
  `login` VARCHAR(50) NULL ,
  `password` VARCHAR(32) NULL ,
  `firstname` VARCHAR(150) NULL ,
  `lastname` VARCHAR(250) NULL ,
  `email` VARCHAR(250) NULL ,
  PRIMARY KEY (`iduser`) )
ENGINE = InnoDB

Jeśli chcielibyśmy stworzyć metody zwracające kolekcje przefiltrowane według którejś z kolumn, musielibyśmy napisać szereg metod, np getUsersByLogin, czy getUsersByFirstname. Im więcej kolumn, po których chcielibyśmy zwracać dane, tym więcej czeka na pracy.

Z pomocą przychodzi magiczna metoda __call (stąd robocza nazwa “magiczny model”). Wystarczy, że w metodzie tej sprawdzimy dla jakiej kolumny chcemy pobierać dane. Resztą zajmie się “magia”.

public function __call($method, array $args)
{
    if(!isset($args[0])) {
        throw new Exception('You have to pass at least one argument in this magic');
    }

    $name = $this->getDbTable()->info(Zend_Db_Table_Abstract::NAME);
    $conditionCol = strtolower(
        str_ireplace('get' . $name . 'by', '', $method)
    );

    $cols = $this->getDbTable()->info(Zend_Db_Table_Abstract::COLS);
    if(!in_array($conditionCol, $cols)) {
        throw new Exception('What are you looking for? "' . $method . '" is invalid in this model');
    }

    $select = $this->getDbTable()->select();
    $select->where($conditionCol . ' = ?', $args[0]);

    return $this->getDbTable()->fetchAll($select);
}

Metoda najpierw sprawdza, czy przekazany został parametr, według którego będziemy pobierać dane. Następnie z nazwy metody usuwamy wszystkie zbędne elementy tak, by pozostała nam rzeczywista nazwa kolumny. Oczywiście musimy sprawdzić, czy wskazana kolumna znajduje się w odpytywanej tabeli. Na koniec wykorzystywana jest metoda fetchAll, do pobrania przefiltrowanych danych.

Wracając do naszej przykładowej tabeli. Jeśli powyższa metoda znajdzie się w modelu, wówczas zapis getUsersByFirstname(‘Anna’), spowoduje, że z tabeli pobrani zostaną wszyscy użytkownicy (a raczej użytkowniczki), których imię to Anna.

Pełny kod klasy wygląda następująco

abstract class Batman_Model
{
    /**
     * @var Zend_Db_Table_Abstract
     */
    protected $_dbTable = null;

    public function __construct()
    {
        $classParts = explode('_', get_class($this));
        $className = array_pop($classParts);
        array_push($classParts, 'DbTable', $className);
        $dbTableClassName = implode('_', $classParts);
        $this->_dbTable = new $dbTableClassName();
    }

    /**
     * @return Zend_Db_Table_Abstract
     */
    public function getDbTable()
    {
        if($this->_dbTable === null) {
            throw new Exception('There id no db table object');
        }
        return $this->_dbTable;
    }

    /**
     * @return Zend_Db_Table_Rowset_Abstract
     */
    public function __call($method, array $args)
    {
        if(!isset($args[0])) {
            throw new Exception('You have to pass at least one argument in this magic');
        }

        $name = $this->getDbTable()->info(Zend_Db_Table_Abstract::NAME);
        $conditionCol = strtolower(
            str_ireplace('get' . $name . 'by', '', $method)
        );

        $cols = $this->getDbTable()->info(Zend_Db_Table_Abstract::COLS);
        if(!in_array($conditionCol, $cols)) {
            throw new Exception('What are you looking for? "' . $method . '" is invalid in this model');
        }

        $select = $this->getDbTable()->select();
        $select->where($conditionCol . ' = ?', $args[0]);

        return $this->getDbTable()->fetchAll($select);
    }
}

Przykład użycia:

model i db table

class Application_Model_User extends Batman_Model
{
}

class Application_Model_DbTable_User extends Zend_Db_Table_Abstract
{
	protected $_name = 'users';
}

Kod w kontrolerze:

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

Autor wpisu: Blame, dodany: 01.10.2010 18:52, tagi: css

Tym razem pokażę wam, w jaki sposób wykorzystując sam CSS, wyclearować float’owane elementy bez dodawania zbędnych div’ów czy co tam jeszcze ktoś sobie wymyśli. Jedziemy :)

Przypuśćmy, że posiadamy następujący kod html:

<div style="float:left">Blok float'owany</div>
<div>Tego już nie chcemy opływać.</div>

Normalnie w takim przypadku większość programistów wstawiłaby po pierwszym bloku następny, ze stylem clear:both. Istnieje jednak łatwiejsza metoda.

W tym rozwiązaniu skorzystamy skorzystamy z pseudoklasy :after, żeby automatycznie wstawić za element z atrybutem float niewidoczną treść która nam wszystko ładnie wyclearuje.

Kod wygląda następująco:

<style type="text/css">

  .clear:after {
    content: ".";
    display: block;
    height: 0;
    clear: both;
    visibility: hidden;
    }

.clearfix {display: inline-block;}  /* hack dla IE pod Mac'iem */

</style>
<!--[if IE]>  /* Hack dla IE */
<style type="text/css">
  .clear {
    zoom: 1;
    display: block;
  }</style>
<![endif]-->

Teraz wystarczy do naszego div'a z ustawionym float dodać klasę .clear a powyższy kod doda za nim niewidzialną kropkę, która całkowicie rozwiąże problem zbędnych znaczników.
Jedynym minusem jest wątpliwa obsługa tego kodu pod starszymi przeglądarkami, nawet pomimo zastosowanych przeze mnie hacków. No ale jeśli cały czas będziemy się oglądać do tyłu to nie pójdziemy na przód, takie życie ;) 
Tagged: clear, clear:both, CSS, float

Autor wpisu: sokzzuka, dodany: 30.09.2010 16:15, tagi: php

Z ostatniej chwili – Adam Harvey w swoim wpisie na grupie php.internals, zaproponował aby dodać do języka możliwość przeciążania operatorów porównania: >,

Autor wpisu: batman, dodany: 30.09.2010 08:00, tagi: css

Hacki CSS dla przeglądarki kojarzą się głównie z IE6. Obok komentarzy warunkowych, najpopularniejszym sposobem na zastosowanie innych wartości atrybutów CSS w IE6, jest sztuczka polegająca na dodaniu przed selektorem * html, np

/* wszystkie przeglądarki */
#menu {
	margin-top: 10px;
}

/* tylko IE6 */
* html #menu {
	margin-top: 5px;
	font-size: 10px;
}

Niestety na rynek trafiła przeglądarka IE7, w której nie działa hack * html. Na szczęście mamy do dyspozycji inną kombinację selektorów, która działa tylko w IE7 – *:first-child+html. Ostatecznie CSS dla IE6 oraz IE7 będzie wyglądał następująco:

/* wszystkie przeglądarki */
#menu {
	margin-top: 10px;
}

/* tylko IE6 */
* html #menu {
	margin-top: 5px;
	font-size: 10px;
}

/* tylko IE7 */
*:first-child+html #sub-menu {
	margin-top: 8px;
}

Autor wpisu: Kamil, dodany: 30.09.2010 02:41, tagi: zend_framework, javascript, apache

Nie ma wątpliwości, że praca programisty polega na ciągłym rozwoju i doskonaleniu swoich umiejętności, szlifowaniu wiedzy, poznawaniu nowych technik i automatyzacji przestarzałych. Także i ja dbam o odwiedzających mój blog, a więc zamieszczam kolejny zbiór ciekawych i pouczających linków :-) Poniżej prezentuję kolejne darmowe artykuły i książki dla programistów, ciekawe odnośniki, mówiąc pokrótce – zasoby, [...]

Autor wpisu: batman, dodany: 28.09.2010 20:34, tagi: javascript

Dwa tygodnie temu (15 września) Microsoft zaprezentował światu najnowszą wersję przeglądarki Internet Explorer, oznaczoną numerem 9. Obok długo wyczekiwanej obsługi aktualnych standardów oraz znacznej poprawie wydajności, zaprezentowano szereg usprawnień wprowadzonych do przeglądarki. Najciekawszym z nich jest funkcjonalność nazwana Pinned Sites.

Co to jest?

Pinned Sites jest mechanizmem pozwalającym przypinać konkretne strony internetowe do paska zadań i korzystać z nich tak, jakby to były zainstalowane na komputerze aplikacje. Pinned Sites najlepiej będzie działać w Windows 7 i na tym właśnie systemie operacyjnym się skupię.

Oczywiście kolejne miejsce, w którym trzymamy odnośniki do ulubionych stron nie byłoby niczym ciekawym, gdyby nie kilka drobiazgów, dzięki którym przypięta strona jest bardziej funkcjonalna od jej standardowej odpowiedniczki. Po pierwsze, favicon staje się ikoną widoczną na pasku zadań. Po drugie, mamy możliwość zdefiniowania najpopularniejszych zadań dostępnych z poziomu Jump List. Na koniec mamy możliwość nałożenia na ikonę w pasku zadań grafiki sygnalizującej jakieś zdarzenie, które może nas zainteresować.

Po co to wszystko?

Najlepszym przykładem zastosowania Pinned Sites będzie webmail. Po przypięciu takiej strony do paska zadań, Jump List będzie zawierał linki do skrzynki odbiorczej, nowej wiadomości oraz ustawień, a ikona będzie zmieniała się w momencie odebrania wiadomości.

Jak tworzyć Pinned Sites?

Pinned Sites nie wymagają od nas znajomości ani języka C#, ani wiedzy na temat środowiska .NET. Wszystko sprowadza się do kilku tagów meta umieszczonych w nagłówku dokumentu HTML oraz kilku prostych funkcji Javascript.

Zacznijmy od zdefiniowania ustawień aplikacji.

<html>
	<head>
		<title>pinned site</title>
		<meta name="application-name" content="pinned site example" />
		<meta name="msapplication-tooltip" content="run pinned site example" />
		<meta name="msapplication-starturl" content="pinned-apps.html" />
		<meta name="msapplication-window" content="width=800;height=600" />
		<meta name="msapplication-navbutton-color" content="red" />
	</head>
	<body>
		<div>
			hello world!
		</div>
	</body>
</html>

Dzięki pięciu widocznym powyżej znacznikom meta nasza przypięta strona zyskała kilka interesujących właściwości. Są to:

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.