If you are developing a module for Drupal you might need to use tabs to simplify a bit a screen which has too much functionality. Typically a settings page that might need too many options to comfortably fit on a single screen. Since I had to search and experiment a bit to find out how to do it I decided to write a short post with my findings. In this article I assume you have a basic understanding on writing Drupal modules.
Drupal Tip - How to determine what module handles a given path
Posted by: miquel in DrupalDrupal has a sophisticated module system that allows developers to extend the CMSs functionality very easily. Each module “hooks” into Drupal by implementing hook functions. On way to use this feature is to hook different URLs to module functions. Essentially the developer in his module declares an array of url paths and what function should be called when that path is requested. This small post will show you how you can determine which module handles a specific URL. This can be quite useful for debugging and/or browsing other peoples source code to learn how to do something.
Every module in Drupal that hooks to a URL path needs to implement the hook_menu function. This hook basically tells Drupal what paths will be handled by this module. This information is read when the module is enabled and stored in a database table. In Drupal 6 this information is cached so if you modify the array returned by the hook_menu function you need to clear the cache. To determine what module is handling what path you simply need to query the menu_router table. A simple query to do this is:
path
, file
, page_callback
, type
, title
FROM
menu_router m
ORDER BY
path
This table has more information that might be useful: access_callback and access_arguments store information related to what access function is called to determine who has access to that path, page_arguments stores information related to what arguments to pass to the callback function. This is specially relevant when the page_callback function is drupal_get_form in which case Drupal will render a form and this field stores the name of the form to render.
An example usage might be:
$ drush sql cli Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 1859 Server version: 5.0.77 Source distribution Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql> SELECT path, file, page_callback FROM menu_router ORDER BY path; +-----------------------------------+---------------------------------+------------------------------+ | path | file | page_callback | +-----------------------------------+---------------------------------+------------------------------+ | admin | modules/system/system.admin.inc | system_main_admin_page | | admin/build | modules/system/system.admin.inc | system_admin_menu_block_page | | admin/build/block | modules/block/block.admin.inc | block_admin_display | | admin/build/block/add | modules/block/block.admin.inc | drupal_get_form | | admin/build/block/configure | modules/block/block.admin.inc | drupal_get_form | | admin/build/block/delete | modules/block/block.admin.inc | drupal_get_form | | admin/build/block/list | modules/block/block.admin.inc | block_admin_display | | admin/build/block/list/bluemarine | modules/block/block.admin.inc | block_admin_display | | admin/build/block/list/chameleon | modules/block/block.admin.inc | block_admin_display | | admin/build/block/list/donline | modules/block/block.admin.inc | block_admin_display | ..... mysql>
Today I needed to generate source code documentation for a webservice APIs we are in coding. One of the guys in the office suggested I take a look at Zend_Reflection. It turns out its quite simple to write PHP code to parse source files and extract the documentation from them. I took a little time to write this sample program.
This program is quite simple: it has a single class called TestClass with one method: addIntegers(). Below this class I wrote a little code which parses the file and then outputs the information. You can use this and a templating system to generate doc. I used it to write the documentation so that we can easily add it to our Wiki.
The script I wrote parses the documentation style used in Zend Framework. Here’s a sample class:
/**
* This is a sample test class.
*
* This class has only one method: addIntegers() which adds
* two integers. Its a sample class for our test.
*
*/
class TestClass
{
/**
* This method adds two integers.
*
* This method adds the two given integers and returns
* its sum. If only one integer is given it sums zero.
*
* @param int $number1 The first integer
* @param int $number2 The second integer
* @return int The sum of $number1 and $number2.
*
*/
public function addIntegers( $number1, $number2 = 0 ) {
return $number1 + $number2;
}
}
Read the rest of the post to see how to easily parse this code…
Read the rest of this entry »
Initializing only one module per request in Zend_Framework.
Posted by: adji in Zend FrameworkZend Framework recently introduced the concept of modules so that your applications become more manegable. The application on startup will load the resources defined in the main application.ini file. To configure each module there is a resource called modules that calls the bootstraping code for each module on every request. If you want to load resources on a per module basis you need to write a bootstrap for each module. This can also generate clashes if two modules try to load the same resource. Additionally this process can have a negative impact on your applications performance.
In this blog I propose a different strategy: I created a controller action plugin that will load resources dynamically using the main bootstraping code. The idea is that after the routes are parsed and before the action is executed this code will load the module’s config file and call the bootstrap again so that it will load the resources defined in this config.
This method has several advantages: only the resources for the module that is being called are loaded. Becuase only one config file is read there is no possiblity of clashes.
Here’s the code:
/**
* Bootstraps the module used in the current request
* It merges the options from main application.ini with the options from a
* module specific application.ini.
* I’m using the fact that a resources are loaded only once, so a resource
* declared in main application.ini is initialized there. If you wish to use some resource
* in every module use the key default (see bellow).
*
* The keys default and disable in the main application.ini have a special meaning.
* default: It is merged initally so a key default.resources.xxx is added as resource.xxx
* so it load the resource xxx as a default for all modules
* disable: It is used to disable keys after merging so a key disable.resources.xxx disables
* this resource in all modules.
*/
class Easytech_Controller_Plugin_ModuleBootstrap extends Zend_Controller_Plugin_Abstract
{
const MODULE_APPLICATION_INI = "configs/application.ini";
protected $_bootstrap;
protected $_autoloader;
public function dispatchLoopStartup( Zend_Controller_Request_Abstract $request )
{
$moduleName = $request->getModuleName();
if ( empty( $moduleName ) ) {
$moduleName = ‘default’;
}
$front = Zend_Controller_Front::getInstance();
$moduleDir = $front->getModuleDirectory( $moduleName );
if ( empty( $moduleDir ) ) {
$moduleDir = APPLICATION_PATH;
}
// Para ser usado en los ini.
define(‘MODULE_PATH’, $moduleDir );
define(‘MODULE_NAME’, $moduleName );
// Create a autoloader for this module
$autoloader = new Zend_Application_Module_Autoloader(array(
‘namespace’ => $moduleName,
‘basePath’ => $moduleDir,
));
$this->_bootstrap = $front->getParam(‘bootstrap’);
$globalOptions = $this->_bootstrap->getOptions();
// Default options from main application.ini
$options = array();
if ( isset( $globalOptions[‘default’] ) ) {
$options = $globalOptions[‘default’];
}
if ( isset( $globalOptions[ $moduleName ] ) ) {
$options = $this->_bootstrap->mergeOptions($options, $globalOptions[ $moduleName ]);
}
$applicationFile = $moduleDir . DIRECTORY_SEPARATOR . self::MODULE_APPLICATION_INI;
if ( isset( $globalOptions[ ‘application_file’ ] ) ) {
$applicationFile = $moduleDir . DIRECTORY_SEPARATOR . $globalOptions[ ‘application_file’ ];
}
$options = $this->_bootstrap->mergeOptions( $options, $this->_loadConfig( $applicationFile ) );
if ( isset( $globalOptions[‘disable’] ) ) {
$options = $this->unsetOptions($options, $globalOptions[‘disable’] );
}
$this->_bootstrap->setOptions( $options );
$this->_bootstrap->bootstrap();
}
/**
* Unset options recursively.
*
* @param array $array1
* @param mixed $array2
* @return array
*/
public function unsetOptions(array $array1, $array2 = null)
{
if (is_array($array2)) {
foreach ($array2 as $key => $val) {
if ( ! isset( $array1[ $key ] ) ) {
continue;
}
if ( is_array( $array2[ $key ] ) ) {
$array1[ $key ] = $this->unsetOptions( $array1[ $key ], $array2[ $key ]);
} else {
unset( $array1[ $key ] );
}
}
}
return $array1;
}
/**
* Based heavily on Zend_Application->_loadConfig
* Load configuration file of options
*
* @param string $file
* @throws Zend_Application_Exception When invalid configuration file is provided
* @return array
*/
protected function _loadConfig($file)
{
if (! Zend_Loader::isReadable($file) ) {
return;
}
$environment = $this->_bootstrap->getApplication()->getEnvironment();
$suffix = strtolower(pathinfo($file, PATHINFO_EXTENSION));
switch ($suffix) {
case ‘ini’:
$config = new Zend_Config_Ini($file, $environment);
break;
case ‘xml’:
$config = new Zend_Config_Xml($file, $environment);
break;
case ‘php’:
case ‘inc’:
$config = include $file;
if (!is_array($config)) {
throw new Zend_Application_Exception(‘Invalid configuration file provided; PHP file does not return array value’);
}
return $config;
break;
default:
throw new Zend_Application_Exception(‘Invalid configuration file provided; unknown config type’);
break;
}
return $config->toArray();
}
}
When developing multi-organization web applications it is of utmost importance that data from one organization is not visible to the other. There are several software aproaches for this. Usually this can be solved by having an organization ID and whenever a query is made a ‘where’ clause is added to filter by organization. Although this approach works fine it is up to developers to always filter by org_id but its certainly error prone.
To solve this problem there are other approaches. One is that each organization gets a copy of the database and a single database user to log to this database. When the user logs in the application uses the URL to determine the organization (say: http://organization.domain.com/login). With the organization name extracted from the URL, the aplication determines which database instance, database user and password to use for the application to use. This obviously solves the problem since, by definition, there is no way data from the two organizations can mix: they live in different databases alltogether.

Sometimes I need to use data from a csv (comma separated values) in an oracle procedure. The best way to do that is inserting the data into a db table using sqlloader and then reading it from the PL/SQL.
In this post I will show you how to use sql loader to load a csv file exported from excel into an oracle table.
Suppose that you got a XLS spreadsheet with contact data: first name, last name, security number, phone number.
First, create a table where the file will be loaded:
(first_name varchar2(200)
,last_name varchar2(200)
,security_number number
,phone_number varchar2(50)
);
In my xls (people.xls) I have the following info:
| First Name | Last Name | Secutiry Number | Phone Number |
| John | Doe | 00000001 | 11111123456 |
| John 01 | Doe | 00000002 | 11111123457 |
| John 02 | Doe | 00000003 | 11111123458 |
| John 03 | Doe | 00000004 | 11111123459 |
| John 04 | Doe | 00000005 | 11111123460 |
| John 05 | Doe | 00000006 | 11111123461 |
| John 06 | Doe | 00000007 | 11111123462 |
Save the data as a comma delimited file.
File -> Save As
Change File name to people_csv
Select ‘Text CSV ’ in the File type drop down box.
If you open the people_csv.csv file in a text editor (vi in my case), you will see it in a comma separated format. Two commas will denote fields without a value, these will be loaded as nulls into the Oracle table.
CSV file:
John ,Doe,00000001,11111123456
John 01,Doe,00000002,11111123457
John 02,Doe,00000003,11111123458
John 03,Doe,00000004,11111123459
John 04,Doe,00000005,11111123460
John 05,Doe,00000006,11111123461
John 06,Doe,00000007,11111123462
Create the following sql loader control file (people_ctrl.txt)
INFILE ‘people_csv.csv’
INTO TABLE people_from_csv
FIELDS TERMINATED BY ‘,’
( first_name, last_name , security_number, phone_number)
at last run the sql loader to put the info into the db table.
SQL*Loader: Release 9.2.0.8.0 - Production on Tue Jan 13 17:26:53 2009
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
Commit point reached - logical record count 7
Now I can use the data from sql with a simple query:
PHONE_NUMBER
————————————————–
11111123456
11111123457
11111123458
11111123459
11111123460
11111123461
11111123462
7 rows selected.
curl es un programa que nos permite transferir datos (o archivos) desde o hasta un servidor, a través de distintos protocolos (entre ellos HTTP, FTP, SCP, etc).

hackers usando curl para testear un SQL injection
Lo interesante (y lo más usado entre los code-monkeys de Easytech) es su uso para emular POSTs a ciertas URLs, sin tener que pasar por la página en el browser.
si no lo tienen, pueden bajarlo del link anterior, aunque tiene fama de estar en todos los repos de las distros conocidas.
En mi caso particular, curl me fue muy útil para hacer un POST a una de las webapps que desarrollamos, y poder chequear el XML que devolvía, sin complicaciones ni pasar por un web-browser.

un PM de Easytech le enseña a un junior a probar sus Forms con curl.
empecemos por lo más básico, emular un formulario. esto lo hacemos con curl -F, o curl -d (dependiendo del content-type que querramos usar). La sintáxis sería algo como:
Otro uso interesante es el de hacer upload de files, emulando un de un form html. La sintáxis:
o…
… si queremos un nombre específico para el file.
Nótese que la arroba delante del path del file es obligatoria.
Claro que, lo que yo quería, era ver qué me devolvía la aplicación (en este caso es un upload de un file a un servidor que devolvía un XML con datos). Para hacer esto tenemos varias formas, u opciones, para pasarle al comando curl, como ser –verbose, –trace, o –trace-ascii. Cada una muestra distintas cosas, dependiendo lo que necesitemos. En mi caso, el servidor devolvía el XML con un simple fpassthru, para lo que trace-ascii venía perfecto.
La sintáxis, entonces, sería así:
la aplicación recibió el file a uploadear como si de un form se tratase, y al devolver el XML, curl lo mostró por stdout. Ideal para debuggear desde la terminal en un servidor remoto o sin tener que pasar por la aplicación web.
Dicen por ahí que también es muy útil para testear vulnerabilidades en algunos sitios con poca validación de formularios, pero eso es demasiado oscuro para mí.

hacker sexy tipea un script con 2 joysticks.
Para ver más ejemplos, consulten acá o en el man de curl, por supuesto.
Como es costumbre, todos los veranos Easytech organiza un “día de campo” bien merecido por los developers que tanto sufrimos durante el año (no podemos vivir manejando helicópteros de juguete todo el día).
Para distendernos, fuimos obligados a hacer deporte (terrestre Y ACUÁTICO). Además, no consultamos nuestros mails en todo el día (Bueno, en realidad sí, había Wi-Fi).
En agradecimiento por ese exquisito matambrito a la pizza (y por organizar el evento un día laboral), compartimos las fotos que documentan el hecho:
Mantener la sesion entre dominios diferentes
Posted by: Pablo Morales in Programming and ScriptingUn problema recurrente con los sistemas grandes y/o multidominio es mantener la sesion de usuarios entre diferentes dominios.
Es imposible hacerlo con las cookies ya que por cuestiones de seguridad los browser no dejan leer o escribir cookies con diferente dominio al actual.
Lo mismo pasa con las sesiones, si uno accede a una pagina y genera un sesion cuando pasa a otro dominio pierde esa sesion.
La solucion no es nada simple. En el ultimo web and beer se hablo de una solucion, pero esa solucion no me dejo nada convencido, y me quede pensando en la idea.
Actualmente en Easytech estamos trabajando en un proyecto, que inicialmente iba a tener el mismo problema, pero lo solucionamos usando un unico dominio, ya que no era necesario otro. Solo tuvimos que unir varios sistemas, bajo el mismo dominio, pero esto es mucho mas facil, ya que podemos pasar un hash que nos permita buscar la info del usuario en una base de datos o en el file system a traves de las cookies.
Pero este problema de los multidominios tiene solucion, de hecho tenemos un google account, que administra las claves de diferentes dominios, ya sea www.gmail.com, www.google.com, www.youtube.com, www.orkut.com, www.picasaweb.com, etc.. Si google lo resolvio porque no nosotros?
Una manera de resolver este probelma, es guardar los datos de sesion en una base de datos, y los enlaces a los diferentes dominios agregarle el hash que hace de indice en esta base para que pueda regenerar los datos de session. El problema es que si yo accedo directamente a un dominio eso no me va a funcionar muy bien.
Una alternativa a este problema es que todo siempre se redireccione a un dominio, cheque si hay una sesion, y despues redirigirlo, como hace google.
Por ejemplo, cada vez que nosotros accedemos a www.orkut.com, este nos redirecciona a https://www.google.com/accounts/ServiceLogin y envia todos los parametros que necesita para identificar al usuario.
Desde este dominio de autenticacion, generamos la cookie correspondiente con el hash necesario. Y lo volvemos a redireccionar al sitio que quiere acceder con un parametro hash, con el indice para que obtenga los datos.
La solucion parece bastante simple, y creo que lo es pero queria compartirla ya que se me quedo colgada en el ultimo web and beer.
Vamos a ver ahora un ejemplo practico
Yo tengo el dominio www.mail.com, el dominio www.calendar.com, y el dominio de mi empresa que se llama www.cloacas.com.
Un usuario ingresa en www.mail.com, ingresa los datos de su cuenta, este formulario envia un post a http://account.cloacas.com/, valido los datos, genero la autenticacion, y lo redirecciono a http://www.mail.com/?id=1231534232, el dominio mail.com, sabe que tiene que generar la sesion con los datos que va a obtener de la base de datos, con el indice que le paso en id.
Con esto tengo que haber logrado autenticarme en www.mail.com. Ahora el usuario, en otro tab de su browser escribe, www.calendar.com.
Calendar.com, hace lo mismo que www.mail.com, y lo redirecciona a account.cloacas.com, este se fija sino tiene ninguna cookie seteada, y si la tiene busca el hash que guardo en la cookie y la compara con el de la base de datos, si todo esta ok, redirecciona al usuario a www.calendar.com/?id=1231534232, sin la necesidad que el usuario ingrese sus datos, porque ya lo habia hecho en www.mail.com
Sometimes easytech developers need flying lessons.
After that we got a better kung-fu.
free video player & free video platformvideo player, online video, video tools
flv player - video editor - video pluginvideo blog + wordpress plugin + video remix











Entries (RSS)