Oggi finalmente si poteva scaricare il software di qtrax per poter scaricare legalmente musica. POter scaricare musica gratis da un catalogo di 50000 canzoni, il tutto pagato da qualche banner pubblicitario, sembrava troppo bello... Sembrava in quanto pare che le case discografiche si siano tirate fuori dal business lasciando il sito nel caos!
Free music downloads site in chaos as record giants pull out| News | This is London
giovedì 7 febbraio 2008
lunedì 4 febbraio 2008
Una casella di posta da gettare
Nello sviluppo di Naturalads.net, mi sono trovato a cercare informazioni su Zend Framework in molteplici siti e quasi tutti mi chiedevano la registrazione per poter postare. Solitamente la registrazione richiede necessariamente l'inserimento del proprio indirizzo email. Si tratta di un piccolo pegno che si deve pagare per accedere ad una nuova sorgente di informazione. Questo, in genere non è un problema, se non fosse che a volte ci si ritrova sommersi dallo spam.
Una soluzione è quella di utilizzare dei servizi di email usa e getta (disposable email) che forniscono un indirizzo di posta per pochi minuti, giusto il tempo per effettuare la registrazione, recuperare il link di attivazione, e non ricevere lo spam! L'unico problema è che molte volte questi indirizzi sono 'bannati' e non accettati dai principali siti web. Inoltre non è possibile riutilizzare lo stesso indirizzo alcuni giorni dopo.
Allora, visto che il php è pronto e caldo, ho pensato che si può perdere un giorno di tempo per crearne uno nuovo... Beh già che c'ero ne ho fatti un paio. Qui vi segnalo dispose.it un servizio di email usa e getta, appena nato, che non è sicuramente bloccato da nessune sito e che, tra l'altro, permette di indicare il proprio indirizzo preferito.
Il servizio è troppo semplice per meritare una sola riga di spiegazione. Basta accedere a questo indirizzo di posta usa e getta e fare CTRL-V nel modulo di registrazione del sito in cui ci si vuole registrare.
Sul sito di dispose.it apparirà presto l'email ricevuta!
Da domani, o meglio da stanotte, si riprende lo sviluppo di naturalads... a proposito penso che utilizzerò Zend Form per le mie prossime forms di naturalads.net e quindi sto installando ZF 1.5 (preview naturalmente).
Una soluzione è quella di utilizzare dei servizi di email usa e getta (disposable email) che forniscono un indirizzo di posta per pochi minuti, giusto il tempo per effettuare la registrazione, recuperare il link di attivazione, e non ricevere lo spam! L'unico problema è che molte volte questi indirizzi sono 'bannati' e non accettati dai principali siti web. Inoltre non è possibile riutilizzare lo stesso indirizzo alcuni giorni dopo.
Allora, visto che il php è pronto e caldo, ho pensato che si può perdere un giorno di tempo per crearne uno nuovo... Beh già che c'ero ne ho fatti un paio. Qui vi segnalo dispose.it un servizio di email usa e getta, appena nato, che non è sicuramente bloccato da nessune sito e che, tra l'altro, permette di indicare il proprio indirizzo preferito.
Il servizio è troppo semplice per meritare una sola riga di spiegazione. Basta accedere a questo indirizzo di posta usa e getta e fare CTRL-V nel modulo di registrazione del sito in cui ci si vuole registrare.
Sul sito di dispose.it apparirà presto l'email ricevuta!
Da domani, o meglio da stanotte, si riprende lo sviluppo di naturalads... a proposito penso che utilizzerò Zend Form per le mie prossime forms di naturalads.net e quindi sto installando ZF 1.5 (preview naturalmente).
Etichette:
disposable email,
email usa e getta,
indirizzo di posta
martedì 29 gennaio 2008
Due note sulla sicurezza (worst practices) #1
Ci sono molte idee nuove nella sicurezza dei computer. Ogni mese escono nuove soluzioni e nuove release software aggiungono nuove funzionalità a vecchi apparati. Ma perchè, anche spendendo un sacco di soldi, ci sono ancora problemi di sicurezza?
Forse perchè nel settore esiste ancora una mentalità radicata, e si continua sempre a fare gli stessi errori. Esistono infatti alcune tecniche che possono far sì che il vostro nuovo ASIC da 100.000 Euro, che sniffa, riordina, ripulisce milioni di pacchetti al secondo possa essere perfettamente trasparente e inutile per proteggervi dagli attacchi.
IDEA 1 - Aperto di Default
Questa sicuramente è un'idea che prende numerose forme. Molto diffusa in svariate forme e difficile da sdradicare. Esattamente come i cibi senza calorie, che non si come, fanno ingrassare comunque.
Il tutto risale ai primi tempi della rete quando per mettere in sicurezza un sistema non si faceva altro che impedire l'accesso via Telnet, via FTP e via Rlogin e si lasciava tutto il resto aperto di default. Immagino che vi sia noto il procedimento...
Quando si scopriva una nuova vulnerabilità allora la decisione era, prima di essere hackerati naturalmente, chiudiamo anche questa porta oppure no? Il tutto supportato dal convincimento, 'tanto noi non siamo interessanti per gli hacker'.
Nel 1990, anche con l'avvento dei worms che non guardano in faccia a nessuno, questa idea di 'Aperto di Default' è stata portata avanti lo stesso, senza alcun ritegno e sopravvive ancora oggi.
Ma il concetto di 'Aperto di Default' si applica anche ad altri campi, come ad esempio nell'esecuzione del codice. Su qualsiasi computer qualsiasi codice cliccato può essere eseguito di default se non interviene un qualcosa che lo blocca. Questo qualcosa può essere un Antivirus, un Antispyware, una policy del sistema operativo. Sul mio pc ho circa 20 programmi che uso abitualmente, non capisco perchè il sistema operativo si permetta di eseguire pezzi di virus, mai utilizzati senza nemmeno chiedermi il permesso... Anche questo è 'Aperto di Default'.
Il contrario di questa idea è Chiuso di default che è senz'altro una buona idea, in quanto chiude le porte a tutto quello che vi è sconosciuto e permette di dormire sogni tranquilli.
Forse perchè nel settore esiste ancora una mentalità radicata, e si continua sempre a fare gli stessi errori. Esistono infatti alcune tecniche che possono far sì che il vostro nuovo ASIC da 100.000 Euro, che sniffa, riordina, ripulisce milioni di pacchetti al secondo possa essere perfettamente trasparente e inutile per proteggervi dagli attacchi.
IDEA 1 - Aperto di Default
Questa sicuramente è un'idea che prende numerose forme. Molto diffusa in svariate forme e difficile da sdradicare. Esattamente come i cibi senza calorie, che non si come, fanno ingrassare comunque.
Il tutto risale ai primi tempi della rete quando per mettere in sicurezza un sistema non si faceva altro che impedire l'accesso via Telnet, via FTP e via Rlogin e si lasciava tutto il resto aperto di default. Immagino che vi sia noto il procedimento...
Quando si scopriva una nuova vulnerabilità allora la decisione era, prima di essere hackerati naturalmente, chiudiamo anche questa porta oppure no? Il tutto supportato dal convincimento, 'tanto noi non siamo interessanti per gli hacker'.
Nel 1990, anche con l'avvento dei worms che non guardano in faccia a nessuno, questa idea di 'Aperto di Default' è stata portata avanti lo stesso, senza alcun ritegno e sopravvive ancora oggi.
Ma il concetto di 'Aperto di Default' si applica anche ad altri campi, come ad esempio nell'esecuzione del codice. Su qualsiasi computer qualsiasi codice cliccato può essere eseguito di default se non interviene un qualcosa che lo blocca. Questo qualcosa può essere un Antivirus, un Antispyware, una policy del sistema operativo. Sul mio pc ho circa 20 programmi che uso abitualmente, non capisco perchè il sistema operativo si permetta di eseguire pezzi di virus, mai utilizzati senza nemmeno chiedermi il permesso... Anche questo è 'Aperto di Default'.
Il contrario di questa idea è Chiuso di default che è senz'altro una buona idea, in quanto chiude le porte a tutto quello che vi è sconosciuto e permette di dormire sogni tranquilli.
giovedì 24 gennaio 2008
Aspettando Zend Framework 1.5
Una nuova versione di Zend Framework è in arrivo... oggi dovrebbe essere in giro una prerelease e tra 3 settimane dovremmo vedere una prima Release Candidate.
In pratica le principali modifiche riguardano:
* Zend_Auth_Adapter_Ldap
* Zend_Build/Zend_Console
* Zend_Controller ha nuovi action helpers, tra cuiContextSwitch/AjaxContext, Json, e AutoComplete
* Zend_Form
* Zend_InfoCard
* Zend_Layout
* Zend_OpenId
* Zend_Search_Lucene migliorato, comprende ricerca con wildcard, ricerca per intervalli di date, e supporto per il formato indice di Lucene 2.1
* Zend_View migliorato, comprende azioni, partials, e placeholders
* Zend_Pdf con supporto UTF8
* UN sacco di correzioni di bug e migliore documentazione
Staremo a vedere e saremo pronti a convertire il codice scritto. Io sono soprattutto curioso per Zend_form, che leggendo nelle proposte, permette di gestire facilmente le form e il tanto atteso Zend Layout che permette di trattare le form come avviene in Ruby.
In pratica le principali modifiche riguardano:
* Zend_Auth_Adapter_Ldap
* Zend_Build/Zend_Console
* Zend_Controller ha nuovi action helpers, tra cuiContextSwitch/AjaxContext, Json, e AutoComplete
* Zend_Form
* Zend_InfoCard
* Zend_Layout
* Zend_OpenId
* Zend_Search_Lucene migliorato, comprende ricerca con wildcard, ricerca per intervalli di date, e supporto per il formato indice di Lucene 2.1
* Zend_View migliorato, comprende azioni, partials, e placeholders
* Zend_Pdf con supporto UTF8
* UN sacco di correzioni di bug e migliore documentazione
Staremo a vedere e saremo pronti a convertire il codice scritto. Io sono soprattutto curioso per Zend_form, che leggendo nelle proposte, permette di gestire facilmente le form e il tanto atteso Zend Layout che permette di trattare le form come avviene in Ruby.
martedì 22 gennaio 2008
Estendere il model con nuovi metodi
ovvero
visualizzare al meglio le colonne del proprio DB
Il mio problema di oggi è il seguente:
Ho una tabella che contiene una colonna che si chiama isChecked di tipo INT che può contenere 0 oppure 1.
Il risultato che voglio ottenere è quello di chiamare un metodo del tipo
$table->status()
che restituisca "verificato" oppure "da verificare" a seconda del valore contenuto nella colonna.
Naturalmente il tutto deve essere fatto in modo naturale ovvero col minimo sforzo possibile.
Vediamo allora di capire dove andare a mettere il metodo magico che ci trasforma il risultato.
Quando si estraggono i dati da db utilizzando Zend_DB_table, quello che si ottiene indietro è un Rowset, ovvero una collezione di Rows.
Con Zend Framework c'è la possibilità di definire una classe personalizzata di Righe (Rows) che estende quella base in modo da aggiungere i metodi che si desiderano.
Per aggiungere nuovi metodi alla riga si crea, quindi, una classe che estende Zend_Db_Table_Row_Abstract
nel mio caso uso la seguente:
la classe la salvo naturalmente in library/Naturalads/WebsiteRow.php dove l'autoloader la può trovare comodamente
Occorre aggiungere al model la classe di riga creata nel passo 1. Questo è molto più semplice del previsto, basta infatti aggiungere al proprio modello una variabile protetta:
in pratica io uso il seguente modello che basta e avanza per i miei scopi:
devo dire che il modello lo salvo come al solito in models/Website.php
Adesso il modello è pronto per l'uso e contiene la mia estensione di classe e il mio metodo. L'unica cosa che mi manca è solo richiamarlo. Vediamo come è possibile istanziare il tutto nel controller e poi visualizzarlo in una view:
Nel mio controller posso utilizzare qualcosa del genere
quindi nella view uso qualcosa del genere per richiamare il mio metodo personale:
Forse non è velocissimo, ma in questo modo posso 'giocare' con tutte le colonne direttamente nel modello di dati, aggiungere colonne virtuali e richiamare il tutto sempre come metodi dalla view senza dover toccare il controller in alcun modo.
Un ottima cosa per la manutenzione del progetto. Se un domani dovrò gestire il nuovo stato "verificato senza successo", basterà inserire il valore -1 nel campo isChecked e modificare il metodo status(). Tutta l'applicazione continuerà a funzionare e a mostrare il nuovo stato senza problemi.
visualizzare al meglio le colonne del proprio DB
Il mio problema di oggi è il seguente:
Ho una tabella che contiene una colonna che si chiama isChecked di tipo INT che può contenere 0 oppure 1.
Il risultato che voglio ottenere è quello di chiamare un metodo del tipo
$table->status()
che restituisca "verificato" oppure "da verificare" a seconda del valore contenuto nella colonna.
Naturalmente il tutto deve essere fatto in modo naturale ovvero col minimo sforzo possibile.
Vediamo allora di capire dove andare a mettere il metodo magico che ci trasforma il risultato.
Quando si estraggono i dati da db utilizzando Zend_DB_table, quello che si ottiene indietro è un Rowset, ovvero una collezione di Rows.
Con Zend Framework c'è la possibilità di definire una classe personalizzata di Righe (Rows) che estende quella base in modo da aggiungere i metodi che si desiderano.
Passo 1 - estendere la riga
Per aggiungere nuovi metodi alla riga si crea, quindi, una classe che estende Zend_Db_Table_Row_Abstract
nel mio caso uso la seguente:
<?php
class Naturalads_WebsiteRow extends Zend_Db_Table_Row_Abstract
{
/**
* Find the Row in the current Rowset with the
* greatest value in its 'updated_at' column.
*/
public function status()
{
$output = ($this->isChecked == 0)? "da verificare":"verificato";
return $output;
}
}
la classe la salvo naturalmente in library/Naturalads/WebsiteRow.php dove l'autoloader la può trovare comodamente
Passo 2 - aggiungere la classe al modello
Occorre aggiungere al model la classe di riga creata nel passo 1. Questo è molto più semplice del previsto, basta infatti aggiungere al proprio modello una variabile protetta:
protected $_rowClass = 'Naturalads_WebsiteRow';
in pratica io uso il seguente modello che basta e avanza per i miei scopi:
<?php
class Website extends Zend_Db_Table {
protected $_name = 'Websites';
protected $_rowClass = 'Naturalads_WebsiteRow';
}
devo dire che il modello lo salvo come al solito in models/Website.php
Passo 3 - Usare il modello
Adesso il modello è pronto per l'uso e contiene la mia estensione di classe e il mio metodo. L'unica cosa che mi manca è solo richiamarlo. Vediamo come è possibile istanziare il tutto nel controller e poi visualizzarlo in una view:
Nel mio controller posso utilizzare qualcosa del genere
...
$website = new Website();
$this->view->assign('websites', $website->fetchAll()); // fetchAll's signature is unmodified
...
quindi nella view uso qualcosa del genere per richiamare il mio metodo personale:
<?php foreach($this->websites as $website) : ?>
<tr>
<td><?php echo $this->escape($website->url);?></td>
<td><?php echo $this->escape($website->status());?></td>
</tr>
<?php endforeach; ?>
e adesso...
Forse non è velocissimo, ma in questo modo posso 'giocare' con tutte le colonne direttamente nel modello di dati, aggiungere colonne virtuali e richiamare il tutto sempre come metodi dalla view senza dover toccare il controller in alcun modo.
Un ottima cosa per la manutenzione del progetto. Se un domani dovrò gestire il nuovo stato "verificato senza successo", basterà inserire il valore -1 nel campo isChecked e modificare il metodo status(). Tutta l'applicazione continuerà a funzionare e a mostrare il nuovo stato senza problemi.
lunedì 21 gennaio 2008
Accetta le condizioni!
Quando si esegue la verifica dei campi delle form utilizzando Zend Framework a volte ci si scontra con dei piccoli noiosi problemi. Ad esempio nella verifica dei checkbox.
Supponiamo che in una form occorra necessariamente accettare le condizioni cliccando su una checkbox. Se utilizziamo Zend_Filter_Input per la verifica dell'inserimento,
e si utilizzano i seguenti parametri, sembra che la cosa possa funzionare:
ma c'è un problema: se la checkbox non è selezionata, non viene inserita nel POST e quindi non arriva proprio alla fase di validazione.
La soluzione è quindi quella di richiedere che la checkbox sia presente e non vuota.
Adesso se non si accettano le condizioni la form non viene validata, correttamente.
Il fatto poi che il messaggio di errore non sia proprio consono è un altro paio di maniche !
Supponiamo che in una form occorra necessariamente accettare le condizioni cliccando su una checkbox. Se utilizziamo Zend_Filter_Input per la verifica dell'inserimento,
e si utilizzano i seguenti parametri, sembra che la cosa possa funzionare:
$validators = array(
'checkbox' => 'NotEmpty'
);
ma c'è un problema: se la checkbox non è selezionata, non viene inserita nel POST e quindi non arriva proprio alla fase di validazione.
La soluzione è quindi quella di richiedere che la checkbox sia presente e non vuota.
$validators = array(
'checkbox' => array(
'presence' => 'required',
'NotEmpty'
)
);
Adesso se non si accettano le condizioni la form non viene validata, correttamente.
Il fatto poi che il messaggio di errore non sia proprio consono è un altro paio di maniche !
giovedì 17 gennaio 2008
Traduzione & Action Helpers
Il problema che mi ha fatto impazzire ieri notte è trovare un metodo comodo per gestire il sito naturalads.net in più lingue.
Il componente Zend_Translate fa proprio questo: permette di gestire facilmente le traduzioni prendendo le stringe da un adapter che può essere un semplice file csv oppure un file di tipo .mo (vedi gettext).
I problemi a cui sono giunto sono i seguenti:
OK. il posto giusto per non fare troppo lavoro e avere un oggetto facilmente manutenibile.
Perchè ho scartato i Front Controller Plugins invece...
In un primo tempo avevo pensato ai Plugin del Front Controller, però non si sono rivelati così flessibili.
Questo è un plugin, ad esempio, trovato sul blog di naneau.nl, che blocca l'accesso ad ogni pagina se non si è loggati:
basta metterlo nella directory library/Plugins e richiamarlo nel bootstrap con
$frontController->registerPlugin(new Plugins_CheckLogin());
per vederlo funzionare in tutte le pagine del nostro sito.
L'unico problema è che il Plugin agisce 'fuori' dal controller e quindi non ha possibilità di accedere al controller e magari settare le variabili della view... Quindi se si vuole lavorare sulla request e magari modificarla, la soluzione migliore è sicuramente il Front Controller Plugin. Se invece si vuole agire a livello globale sui controller, come nel mio caso, è meglio usare un action helper che può essere richiamato in modo automatico sugli eventi.
... Aggiornamento .... dopo 4 ore (dovute soprattutto a convincere l'helper broker a digerire il nuovo helper) il mio helper 'translator' è funzionante e si adatta a qualsiasi controller (attuale o futuro) senza bisogno di scrivere una riga in più.
Anzi già che c'ero l'ho infarcito di tutte le cose che mi servono bene o male per tutti i controller...
(per i curiosi eccolo...)
Il componente Zend_Translate fa proprio questo: permette di gestire facilmente le traduzioni prendendo le stringe da un adapter che può essere un semplice file csv oppure un file di tipo .mo (vedi gettext).
I problemi a cui sono giunto sono i seguenti:
- come mantenere lo stato della lingua dell'utente
- una volta definita la lingua come e dove inizializzare la classe Zend_Translate
- come permettere all'utente di cambiare lingua senza perdere il contesto
- La lingua dell'utente si tiene dentro la sessione in questo modo non si creano problemi di passaggio parametri negli URL. Inoltre la sessione è comunque già attiva per gestire le autenticazioni e quindi una variabile in più di 2 caratteri non fa troppo male.
- Quando un controller vede nell'url/get/post/cookie/env un parametro lang=xx si attiva per salvare il parametro nella sessione. In questo modo l'utente può cambiare la lingua senza perdere il contesto di quello che sta facendo
- L'inzializzazione della classe Zend_translate, così come la modifica della variabile di sessione, è fatto nel controller attivo.
OK. il posto giusto per non fare troppo lavoro e avere un oggetto facilmente manutenibile.
Perchè ho scartato i Front Controller Plugins invece...
In un primo tempo avevo pensato ai Plugin del Front Controller, però non si sono rivelati così flessibili.
Questo è un plugin, ad esempio, trovato sul blog di naneau.nl, che blocca l'accesso ad ogni pagina se non si è loggati:
class Plugins_CheckLogin extends Zend_Controller_Plugin_Abstract {
public function preDispatch() {
$login = false;
//you will probably want to implement this ;)
if (!$login) {
//no login
$request = $this->getRequest();
//the request
$request->setModuleName('default');
$request->setControllerName('login');
$request->setActionName('index');
//send to default/login/index
}
}
basta metterlo nella directory library/Plugins e richiamarlo nel bootstrap con
$frontController->registerPlugin(new Plugins_CheckLogin());
per vederlo funzionare in tutte le pagine del nostro sito.
L'unico problema è che il Plugin agisce 'fuori' dal controller e quindi non ha possibilità di accedere al controller e magari settare le variabili della view... Quindi se si vuole lavorare sulla request e magari modificarla, la soluzione migliore è sicuramente il Front Controller Plugin. Se invece si vuole agire a livello globale sui controller, come nel mio caso, è meglio usare un action helper che può essere richiamato in modo automatico sugli eventi.
... Aggiornamento .... dopo 4 ore (dovute soprattutto a convincere l'helper broker a digerire il nuovo helper) il mio helper 'translator' è funzionante e si adatta a qualsiasi controller (attuale o futuro) senza bisogno di scrivere una riga in più.
Anzi già che c'ero l'ho infarcito di tutte le cose che mi servono bene o male per tutti i controller...
(per i curiosi eccolo...)
<?php
require_once 'Zend/Controller/Action/Helper/Abstract.php';
class Helpers_Translator extends Zend_Controller_Action_Helper_Abstract {
public function init() {
$controller = $this->getActionController();
// utilità per le view
$controller->view->baseUrl = $controller->getRequest()->getBaseUrl();
//tutti i metodi della view possono usare $this->user per accedere all'utente
$controller->view->user = Zend_Auth::getInstance()->getIdentity();
//get the session
$sex = Zend_Registry::get('sex');
// numero di pagine
$controller->view->numberOfPageRequests =$sex->numberOfPageRequests;
// esiste un parametro di lingua allora lo mettiamo nella sessione
if($lang = $controller->getRequest()->getParam('lang', '')) {
$sex->lang = $lang;
}
//comunichiamo alla view il lang da usare
$controller->view->lang = $sex->lang;
// carichiamo il file di traduzione
$translationFile = '../languages/'. $sex->lang .'-source.csv';
// carichiamo il file di traduzione
if (file_exists($translationFile)) {
$controller->view->trans = new Zend_Translate('csv', $translationFile, $sex->lang, array('separator' => '|'));
} else {
$controller->view->trans = new Zend_Translate('csv', '../languages/nosource.csv');
}
}
}
Etichette:
NaturalAds,
Plugins,
traduzione,
Zend Framework,
Zend_Translate
Iscriviti a:
Post (Atom)