Clientes SOAP en Python y PHP

En el post anterior vimos como crear servicios Web personalizados con el protocolo SOAP en Drupal. Por supuesto, un servicio Web en SOAP puede hacerse en multitud de lenguajes. Al igual que los clientes que lo consumen. En este caso vamos a ver ejemplos para consumir el servicio Web creado en el post anterior con clientes SOAP escritos en los lenguajes Python y PHP.

Cliente en Python
En primer lugar, instalamos easy_install:

  1. neonigma@neonigma-desktop:~$ sudo apt-get install python-setuptools python-dev build-essential

A continuación, instalamos suds:

  1. neonigma@neonigma-desktop:/opt/lampp/htdocs$ sudo easy_install suds
  2. install_dir /usr/local/lib/python2.6/dist-packages/
  3. Searching for suds
  4. Reading http://pypi.python.org/simple/suds/
  5. Reading https://fedorahosted.org/suds
  6. Best match: suds 0.4
  7. Downloading http://pypi.python.org/packages/2.6/s/suds/suds-0.4-py2.6.egg#md5=94a9414e90e01243262548ad9eaf2784
  8. Processing suds-0.4-py2.6.egg
  9. creating /usr/local/lib/python2.6/dist-packages/suds-0.4-py2.6.egg
  10. Extracting suds-0.4-py2.6.egg to /usr/local/lib/python2.6/dist-packages
  11. Adding suds 0.4 to easy-install.pth file
  12.  
  13. Installed /usr/local/lib/python2.6/dist-packages/suds-0.4-py2.6.egg
  14. Processing dependencies for suds
  15. Finished processing dependencies for suds

A continuación, con sólo este pequeño programa en Python usando la librería suds podemos utilizar la operación que definimos en el servicio Web del post anterior:

  1. from suds import WebFault
  2. from suds.client import Client
  3. import traceback as tb
  4. import logging
  5.  
  6. logging.basicConfig(level=logging.INFO)
  7. logging.getLogger('suds.client').setLevel(logging.DEBUG)
  8.  
  9. try:
  10.     client = Client('http://debian-virtual/drupal/?q=services/soap/?wsdl')
  11.     print client.service.add_numbers(10,3)
  12. except WebFault, f:
  13.     print f
  14.     print f.fault
  15. except Exception, e:
  16.     print e
  17.     tb.print_exc()

El resultado de la ejecución es el siguiente:

  1. root@debian:/var/www# python cliente.py
  2. DEBUG:suds.client:sending to (http://debian-virtual/drupal/services/soap/?wsdl/)
  3. message:
  4. <?xml version="1.0" encoding="UTF-8"?>
  5. <SOAP-ENV:Envelope xmlns:ns3="http://debian-virtual/drupal/services/soap/?wsdl/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns0="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns2="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  6.    <SOAP-ENV:Header/>
  7.    <ns1:Body>
  8.       <ns3:add_numbers>
  9.          <number_one xsi:type="ns2:int">10</number_one>
  10.          <number_two xsi:type="ns2:int">3</number_two>
  11.       </ns3:add_numbers>
  12.    </ns1:Body>
  13. </SOAP-ENV:Envelope>
  14. DEBUG:suds.client:headers = {'SOAPAction': u'"http://debian-virtual/drupal/services/soap/?wsdl/add_numbers"', 'Content-Type': 'text/xml; charset=utf-8'}
  15. DEBUG:suds.client:http succeeded:
  16. <?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><ns1:soap_call_wrapperResponse xmlns:ns1="http://debian-virtual/drupal/services/soap/?wsdl/"><return xsi:type="xsd:int">13</return></ns1:soap_call_wrapperResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>
  17. 13

Cliente en PHP
Para el cliente en PHP, necesitamos la librería nuSOAP. En este caso, la tenemos ya instalada del post anterior, por lo que apuntaremos a esa ruta. Escribimos este pequeño cliente en PHP:

  1. <?php
  2. ini_set('soap.wsdl_cache_enabled', '0');
  3. require_once('drupal/modules/soap_server/nusoap/lib/nusoap.php');
  4.  
  5. $wsdl = "http://localhost/drupal-testing/?q=services/soap/?wsdl";
  6. $soap = new soapclient($wsdl);
  7.  
  8. $result = $soap->add_numbers(10,3);
  9. print "El resultado es: " . $result;
  10. ?>

Apuntando a la URL de este ejemplo (http://localhost/cliente.php en este caso), veremos que nos imprime el resultado de la suma correctamente.

Sé el primero en valorar positivamente

Crea tu propio servicio Web con NuSOAP en Drupal

Una de las cosas que más me gustan del software libre es la liberación del conocimiento. Incluso (o sobre todo), cuando lo que has investigado, usado o desarrollado al final no te sirve. Me parece realmente mal que se deseche todo ese conocimiento, ya que se ha invertido el tiempo en ello, por qué no invertir 20 minutos más en estructurarlo y escribirlo. Otro podría necesitar ese conocimiento tan cercano. Aunque no esté 100% depurado y sea directamente utilizable, podría ser un gran punto de partida para otras personas, o incluso para uno mismo en momentos posteriores.

El presente artículo es uno de los que sí me han servido, pero ya empezaba a olvidar. Así que lo escribo. Y tengo en mente el siguiente, totalmente relacionado, que cumple una de las premisas del párrafo anterior: al principio no me sirvió para mucho y meses más tarde ha sido la llave para desbloquear el cierre de un proyecto.

Sin más preámbulos, veamos como crear tu propio servicio Web utilizando SOAP en Drupal. Esta forma da una idea de lo extendible que es un servicio Web dentro de este CMS y me sirve para recordar en cualquier momento cómo llevar a cabo este proceso de extensión.

En primer lugar, como siempre, instalamos drush:

  1. neonigma@neonigma-laptop:~$ sudo apt-get install drush

Descargamos el módulo services:

  1. neonigma@neonigma-laptop:/var/www/drupal-testing/modules$ drush dl services -r modules
  2. Project services (6.x-2.3) downloaded to                             [success]
  3. /var/www/drupal-testing/modules/.

Lo habilitamos:

  1. neonigma@neonigma-laptop:/var/www/drupal-testing/modules$ drush en services
  2. The following modules will be enabled: services
  3. Do you really want to continue? (y/n): y
  4. Services was enabled successfully.                                   [ok]

Descargamos el módulo soap_server:

  1. neonigma@neonigma-laptop:/var/www/drupal-testing/modules$ drush dl soap_server -r modules/services
  2. Project soap_server (6.x-1.2-beta1) downloaded to                    [success]
  3. /var/www/drupal-testing/modules/.

Lo habilitamos:

  1. neonigma@neonigma-laptop:/var/www/drupal-testing/modules$ drush en soap_server
  2. The following modules will be enabled: soap_server
  3. Do you really want to continue? (y/n): y
  4. SOAP Server was enabled successfully.                                [ok]

Para completar la instalación de SOAP Server, no basta con haber instalado el módulo. Debemos instalar la librería NuSOAP que es la que proporcionará realmente el servicio. La descargamos de este enlace por ejemplo a /tmp y la descomprimimos de la siguiente forma:

  1. neonigma@neonigma-laptop:/tmp$ mkdir nusoap
  2. neonigma@neonigma-laptop:/tmp$ mv nusoap-0.9.5.zip nusoap
  3. neonigma@neonigma-laptop:/tmp$ cd nusoap/
  4. neonigma@neonigma-laptop:/tmp/nusoap$ unzip nusoap-0.9.5.zip
  5. neonigma@neonigma-laptop:/tmp/nusoap$ rm nusoap-0.9.5.zip
  6. neonigma@neonigma-laptop:/tmp/nusoap$ cd ..
  7. neonigma@neonigma-laptop:/tmp$ mv nusoap/ /var/www/drupal-testing/modules/soap_server/

En este punto, tenemos un servidor SOAP escuchando en http://localhost/drupal-testing/?q=services/soap. Pero existe un bug en esta versión de SOAP server, por el cual al acceder a esa URL por primera vez no nos muestra las operaciones disponibles, sino el mensaje de error You must specify a name when you register an operation.

Afortunadamente tiene fácil solución. Nos bajamos este parche visto en este enlace en la ruta del módulo soap_server y lo parcheamos de esta forma:

  1. neonigma@neonigma-laptop:/var/www/drupal-testing/modules/soap_server$ wget http://drupal.org/files/issues/751326.patch
  2. neonigma@neonigma-laptop:/var/www/drupal-testing/modules/soap_server$ patch -p0 < 751326.patch

Si volvemos a acceder de nuevo a la URL de escucha, ahora deberíamos de ver las operaciones disponibles y un enlace al WSDL. Esta URL al WSDL para mi no encaja con la realidad, por lo que yo siempre uso http://localhost/drupal-testing/?q=services/soap/?wsdl a la hora de proporcionar este parámetro a los clientes que deseen conectarse al servicio Web personalizado.

Otro de los hándicaps de utilizar SOAP en Drupal es que se requiere URLs limpias, tema bastante espinoso en Drupal 6, al menos para mi gusto. Para habilitarlas debemos seguir los siguientes pasos:

  • Comprobamos si tenemos instalado el módulo rewrite de Apache:
    1. root@neonigma-laptop:/var/www/drupal-testing# apache2ctl -M
  • Si no está instalado, lo instalamos:
    1. root@neonigma-laptop:/var/www/drupal-testing# a2enmod rewrite
    2. Enabling module rewrite.
    3. Run '/etc/init.d/apache2 restart' to activate new configuration!
    4. root@neonigma-laptop:/var/www/drupal-testing# /etc/init.d/apache2 restart
  • Visitar la URL http://localhost/drupal/?q=admin/settings/clean-urls y, si está disponible el botón de radio con la opción Activado, lo marcamos y guardamos la configuración. Si el botón no está disponible para marcado, debemos revisar cómo habilitar las URLs limpias en este post.

Con todo instalado, toca el turno de lo interesante, crearnos nuestro propio servicio Web. Los servicios Web preinstalados y listos para usar se encuentran en modules/services/services, por lo que un buen punto de partida es copiarnos uno de ellos y modificarlo a nuestro gusto.

  1. neonigma@neonigma-laptop:/var/www/drupal-testing/modules/services/services$ cp -R comment_service/ nuestro_service
  2. neonigma@neonigma-laptop:/var/www/drupal-testing/modules/services/services/nuestro_service$ mv comment_service.info nuestro_service.info
  3. neonigma@neonigma-laptop:/var/www/drupal-testing/modules/services/services/nuestro_service$ mv comment_service.inc nuestro_service.inc
  4. neonigma@neonigma-laptop:/var/www/drupal-testing/modules/services/services/nuestro_service$ mv comment_service.module nuestro_service.module

La utilidad de cada fichero es la siguiente:

  • nuestro_service.info: este fichero contiene la información de visualización del módulo. Es decir, la identificación del módulo dentro de http://localhost/drupal-testing/?q=admin/build/modules, en la zona Services.
  • nuestro_service.module: este fichero contiene la descripción estática de las funciones del servicio Web que se van a compartir.
  • nuestro_service.inc: este fichero contiene el código de las funciones del servicio Web definidas en el fichero anterior.

Lo primero que vamos a hacer es cambiar la información de identificación de nuestro servicio Web en el fichero nuestro_service.info. Para ello, modificamos el primer bloque del código original:

  1. ; $Id: comment_service.info,v 1.1.2.1 2009/06/06 22:57:40 marcingy Exp $
  2. name = Comment Service
  3. description = Provides a comment service.
  4. package = Services - services
  5. dependencies[] = services
  6. dependencies[] = comment
  7. core = 6.x

y escribimos en su lugar este otro:

  1. ; $Id: nuestro_service.info,v 1.1.2.1 2010/12/04 11:28:00 marcingy Exp $
  2. name = Nuestro propio servicio Web
  3. description = Proporciona nuestra propia funcionalidad
  4. package = Services - services
  5. dependencies[] = services
  6. core = 6.x

Nótese que hemos eliminado la dependencia al módulo comment.

A continuación, editamos el fichero nuestro_service.module:, eliminando todo el código existente y colocando este en su lugar:

[PHP]
<?php
// $Id: nuestro_service.module,v 1.1.2.1.2.9 2010/07/16 02:59:56 skyredwang Exp $

/**
* @file
* Link functionality to services module.
*/

/**
* Implementation of hook_perm().
*/
function nuestro_service_perm() {
return array(‘access add two numbers’);
}
/**
* Implementation of hook_service().
*/
function nuestro_service_service() {
return array(

// nuestro.add
array(
‘#method’ => ‘add_numbers’,
‘#callback’ => ‘nuestro_service_add’,
‘#access arguments’ => array(‘access add two numbers’),
‘#file’ => array(‘file’ => ‘inc’, ‘module’ => ‘nuestro_service’),
‘#args’ => array(
array(
‘#name’ => ‘number_one’,
‘#type’ => ‘int’,
‘#description’ => t(‘The first number.’),
),
array(
‘#name’ => ‘number_two’,
‘#type’ => ‘int’,
‘#description’ => t(‘The second number.’),
),
),
‘#return’ => ‘int’,
‘#help’ => t(‘This method adds two numbers and return the result’),
),
);
}[/PHP]

Por último, editamos el fichero nuestro_service.inc:, eliminamos todo el código existente y definimos lo que hará la función que acabamos de exponer:

  1. &lt;?php
  2. // $Id: nuestro_service.inc,v 1.1.2.1.2.5 2010/05/08 19:26:00 heyrocker Exp $
  3.  
  4. /**
  5.  * @file
  6.  *  Link functionality to services module.
  7.  */
  8.  
  9. /**
  10.  * Returns the addition of two parameters received.
  11.  *
  12.  * @param $number_one
  13.  *   First number to add.
  14.  * @param $number_two
  15.  *   Second number to add.
  16.  * @param $since
  17.  *   Timestamp to indicate what nodes are new. Defaults to time of last user acces to node.
  18.  * @return
  19.  *   Number of nuestros that node has.
  20.  */
  21. function nuestro_service_add($number_one, $number_two) {
  22.   return (int)($number_one + $number_two);
  23. }

Es el momento de verificar que todo está en su sitio. Ahora veamos la configuración de módulos en http://localhost/drupal-testing/?q=admin/build/modules. Debemos activar nuestro nuevo módulo que representa el servicio Web que acabamos de crear.

Nos vamos a http://localhost/drupal-testing/?q=admin/user/permissions y verificamos que los permisos que hemos creado en el fichero services.modules, concretamente access add two numbers, están disponibles para asignar a los roles que tenemos creados. Inicialmente se encuentran desmarcados, deberemos marcarlos para acceso a usuario anónimo si es nuestro deseo.

Daremos permisos a todo el mundo para utilizar nuestro servicio Web. Para hacer que sólo puedan utilizar el servicio Web los usuarios registrados, me remito a la entrada anterior en este blog, donde se explicaba este hecho.

En http://localhost/drupal-testing/?q=admin/build/services podemos ver el servidor SOAP ejecutándose y las operaciones expuestas de nuestro servicio Web.

Para acceder a un testeador de nuestro servicio Web pulsamos en el enlace a nuestro.add. En la pantalla que aparece podemos escribir los dos argumentos y pulsar en Call method para realizar la llamada al servicio Web y obtener el resultado.

A 1 persona le gusta esta entrada

Login y registro de usuarios en Drupal con Python vía XMLRPC

Para este propósito necesitamos tener un rol administrador con todos los permisos asignados. El usuario que tenga asignado este rol será con el que iniciemos sesión en Python y el que tendrá poder para registrar usuarios. A partir de aquí, voy a suponer una instalación limpia de Drupal. Drupal tiene módulos que proporcionan un servidor XMLRPC y una serie de servicios Web impecables que expone al exterior. Veamos los pasos para preparar Drupal para este cometido.

  1. Instalar la herramienta de descarga y habilitación sencilla de módulos Drupal
    1. neonigma@neonigma-desktop:~/Descargas$ sudo apt-get install drush
  2. Descargar y habilitar el módulo Services
    1. neonigma@neonigma-desktop:/opt/lampp/htdocs/drupal/modules$ drush dl services -r modules
    2. Project services (6.x-2.2) downloaded to /opt/lampp/htdocs/drupal/modules/services.                                                                                                                  [success]
    3.  
    4. neonigma@neonigma-desktop:/opt/lampp/htdocs/drupal/modules$ drush en services
    5. The following projects will be enabled: services
    6. Do you really want to continue? (y/n): y
    7. services was enabled successfully.                                                                                                                                                                   [ok]

    En Drupal vamos a Administrar -> Construcción del sitio -> Módulos. Activamos los siguientes módulos y pulsamos en Guardar configuración:

    MUY IMPORTANTE. En Drupal vamos ahora a Administrar -> Administración de usuarios -> Opciones de usuario y DESACTIVAMOS la casilla Es necesaria la verificación por correo cuando un visitante crea una cuenta. Pulsamos el botón Guardar la configuración del final de la página. La siguiente imagen muestra cómo debe quedar la configuración:

    A continuación, vamos a Administrar -> Construcción del sitio -> Services, pulsamos en la pestaña Opciones y en el desplegable Authentication module escogemos Key authentication. A continuación desmarcamos Use keys y dejamos marcado Use sessid. Este párrafo es lo más importante, el que permite la magia. La siguiente imagen muestra cómo debe quedar la configuración:

    Por último, vamos a asignar todos los permisos correctamente. Vamos a Administrar -> Administración de usuarios -> Permisos. En la columna de administrador debemos haber marcado todos los checkbox, dando permiso al administrador para hacer lo que desee en el portal.

    Con esto, ya tendríamos Drupal preparado para el acceso a los distintos servicios Web. Para comprobarlo, vamos Administrar -> Construcción del sitio -> Services y hacemos clic en el enlace XMLRPC – /services/xmlrpc. La URL que se nos abra en el navegador será nuestra URL de conexión a los servicios Web. En mi caso de ejemplo, la URL es http://localhost/drupal/services/xmlrpc

    Ahora, sólo tenemos que escribir un pequeño programa de testing como este para aprovechar estos servicios:

    1. #! /usr/bin/python
    2. import os.path, sys, xmlrpclib, socket
    3.  
    4. config = {
    5.   'url': 'http://localhost/drupal/services/xmlrpc',
    6.   'username': 'admin',
    7.   'password': 'admin',
    8. }
    9.  
    10. # Make initial connection to service
    11. server = xmlrpclib.ServerProxy(config['url'], allow_none=True);
    12.  
    13. try:
    14.     server.system.listMethods() # si podemos listar las operaciones del servicio web, hemos conectado al servidor
    15. except xmlrpclib.ProtocolError, socket.error:
    16.     print 'No se puede conectar al servidor'
    17. except EOFError:
    18.     exit(1)
    19. else:
    20.     try:
    21.         connection = server.system.connect(); # hacer uso de la funcion connect del servicio web System
    22.     except:
    23.         print "Error en la conexion. Codigo de error: %d" % err.faultCode
    24.         print "%s" % err.faultString.encode('utf-8','ignore')
    25.     else:
    26.         try:
    27.             session = server.user.login(connection['sessid'], config['username'], config['password']); # usar funcion login del servicio web User
    28.  
    29.         except xmlrpclib.Fault, err:
    30.             print "Error en el inicio de sesion. Codigo de error: %d" % err.faultCode
    31.             print "%s" % err.faultString.encode('utf-8','ignore')
    32.         else:
    33.             sessid = session['sessid']; # necesario obtener el sessid, es nuestra key para identificarnos despues
    34.             user = session['user'];
    35.  
    36.             try:
    37.                 # construimos los datos del nuevo usuario y le entregamos la key
    38.                 user_data = {
    39.                     'sessid': session['sessid'],
    40.                     'name': 'enigma',
    41.                     'mail': 'enigma@enigma.es',
    42.                     'pass': 'enigma',
    43.                 }
    44.                 print session # datos del administrador
    45.                 result = server.user.save(sessid, user_data) # intentar registrar nuestro usuario, no olvidar la key
    46.                 print result # resultado del registro de usuario
    47.             except xmlrpclib.Fault, err:
    48.                 print "Error en el registro de usuario. Codigo de error: %d" % err.faultCode
    49.                 print "%s" % err.faultString.encode('utf-8','ignore')        
    50.             else:
    51.                 print "Se ha registrado correctamente al usuario"

    El resultado de la ejecución de este código es el siguiente:

    1. neonigma@neonigma-desktop:/opt/lampp/htdocs/drupal$ python register.py
    2. u003igf16uvf9fnhaspe3v36e0
    3. {'sort': '0', 'status': '1', 'picture': '', 'uid': '3', 'language': 'es', 'created': '1290805507', 'roles': {'3': 'usuario administrador', '2': 'authenticated user'}, 'signature': '', 'init': 'admin@admin.fake', 'access': '1290858423', 'signature_format': '0', 'theme': '', 'form_build_id': 'form-ac8a1d5923bb603b231df3f65fc8d38f', 'mode': '0', 'pass': '21232f297a57a5a743894a0e4a801fc3', 'threshold': '0', 'mail': 'admin@admin.fake', 'login': 1290858449, 'data': 'a:1:{s:13:"form_build_id";s:37:"form-ac8a1d5923bb603b231df3f65fc8d38f";}', 'timezone': '3600', 'name': 'admin'}
    4. 9
    5. Se ha registrado correctamente al usuario

    Si vamos a Administrar -> Administración de usuarios -> Usuarios veremos nuestro usuario perfectamente creado. Además, podemos iniciar sesión con él.

    A 3 personas les gusta esta entrada

Redimensionar iFrame en IE y Firefox con Javascript

Ha sido especialmente tedioso conseguir que para un iframe, se me redimensionara la altura dependiendo del contenido que se cargara dentro de éste. Firefox lo realizaba a la perfección, pero no así Internet Explorer. Tomando un par de referencias me he construido la solución que quiero compartir.

En el archivo que declara el iframe:

javascript

  1. &lt;script language=&quot;javascript&quot;&gt;
  2. function grand(h)
  3. {
  4.   iframe=document.getElementById(&quot;mi_iframe&quot;)
  5.   iframe.height=h;
  6. }
  7. function reSize(h)
  8. {  
  9.     try
  10.   {
  11.     var oBody   =   mi_iframe.document.body;
  12.     var oFrame  =   document.all(&quot;mi_iframe&quot;);
  13.        
  14.         oFrame.style.height = oBody.scrollHeight + (oBody.offsetHeight - oBody.clientHeight);
  15.         oFrame.style.width = oBody.scrollWidth + (oBody.offsetWidth - oBody.clientWidth);
  16.     }
  17.     catch(e) //An error is raised if the IFrame domain != its container's domain
  18.     {
  19.      window.status =    'Error: ' + e.number + '; ' + e.description;
  20.     }
  21. }
  22. &lt;/script&gt;

En el mismo fichero, declaramos el iframe y colocamos esto en el body para IE:

  1. &lt;body onLoad=&quot;reSize(0)&quot;&gt;&lt;iframe id=&quot;mi_iframe&quot; src=&quot;iframe.php&quot; width=&quot;100%&quot; frameborder=&quot;0&quot; height=&quot;100%&quot;&gt;&lt;/iframe&gt;&lt;/body&gt;

En el contenido del iframe (iframe.php en el ejemplo):

javascript

  1. &lt;script language=&quot;javascript&quot;&gt;
  2.      function redimensiona()
  3.      {
  4.       var navegador = navigator.appName
  5.       if (navegador == &quot;Microsoft Internet Explorer&quot;)
  6.       {
  7.         top.reSize(0);
  8.       }
  9.       else
  10.       {
  11.         principal=document.getElementById(&quot;div_principal&quot;);
  12.         top.grand(principal.scrollHeight+40);
  13.       }      
  14.      }
  15. &lt;/script&gt;

El código HTML del contenido de este iframe sería algo así como:

  1. &lt;html&gt;&lt;body onLoad=&quot;redimensiona()&quot;&gt;&lt;table id=&quot;div_principal&quot;&gt;&lt;tr&gt;&lt;td&gt;Incluir contenido de la pagina&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/body&gt;&lt;/html&gt;

Referencias:

A 2 personas les gusta esta entrada

Enlazar MySQL Query Browser en Ubuntu con Lampp (Xampp para Linux)

Para los que usamos Lampp y reconocemos como un fastidio usar PHPMyAdmin, existe una solución para que cada vez que se arranca Lampp, se inicie también un socket al demonio de mysql que permita la ejecución de MySQL Query Browser.

Para crear el socket sería necesario hacer esto cada vez que se quiere iniciar Lampp:

$ sudo mkdir /var/run/mysqld
$ cd /var/run/mysqld
$ sudo ln -s /opt/lampp/var/mysql/mysql.sock mysqld.sock

Podemos automatizar este proceso de forma que sólo sería necesario realizarlo una sola vez. Abrimos el archivo /opt/lampp/lampp como root, buscamos el case startmysql y añadimos las tres líneas anteriores al último else, tal y como sigue a continuación:

“startmysql”)
if testrun /opt/lampp/var/mysql/`/bin/hostname`.pid mysqld
then
$de && echo “XAMPP: XAMPP-MySQL laeuft bereits.”
$de || echo “XAMPP: XAMPP-MySQL is already running.”
else
if testport 3306
then
$de && echo “XAMPP: Ein anderer MySQL daemon laeuft bereits.”
$de || echo “XAMPP: Another MySQL daemon is already running.”
else
/opt/lampp/bin/mysql.server start > /dev/null &
$de && echo “XAMPP: Starte MySQL…”
$de || echo “XAMPP: Starting MySQL…”
sudo mkdir /var/run/mysqld
cd /var/run/mysqld
sudo ln -s /opt/lampp/var/mysql/mysql.sock mysqld.sock
fi
fi

Fuente: Ubuntu Forums

Sé el primero en valorar positivamente

Selección condicional (IF) de campos en MySQL con múltiples tablas (JOIN)

En un proyecto en el que estoy trabajando necesitaba seleccionar ciertos datos dependiendo de si el usuario escogía un artículo o bien un pack de artículos.

En la siguiente tabla puede verse que cada fila o bien apunta a la id de un artículo o bien a la ide de un pack.
bd-listaboda

Para conseguir mi propósito y obtener o los datos del artículo o los datos del pack directamente con una sola consulta, desarrollé la siguiente:

  1. select distinct
  2. if (lb.id_articulo  '', f.id_categoria, '') as id_categoria,
  3. if (lb.id_articulo  '', f.parent_id_categoria, '') as parent_id_categoria,
  4. if (lb.id_articulo  '', concat('arti',a.id_articulo), concat('pack', p.id_pack)) as id_articulo,
  5. if (lb.id_articulo  '', a.nombre, p.nombre) as nombre,
  6. if (lb.id_articulo  '', a.descripcion, p.descripcion) as descripcion,
  7. if (lb.id_articulo  '', a.unidades, '') as unidades,
  8. if (lb.id_articulo  '', a.PVP, p.PVP_pack) as PVP, lb.cantidad,
  9. e.id_enlaces_novios as enlaces_novios
  10. from
  11. articulo a,
  12. categoria f,
  13. packs p,
  14. enlaces_novios e
  15. inner join listaboda lb on (lb.id_enlaces_novios = e.id_enlaces_novios and e.id_enlaces_novios = 10)
  16. where
  17. f.id_categoria = a.id_categoria
  18. and (lb.id_articulo = a.id_articulo and lb.id_articulo  '') or (lb.id_pack = p.id_pack and lb.id_pack  '')
  19. and a.visible = 1

Podemos ver la sintaxis en su esplendor en la línea 4:

  1. IF (lb.id_articulo  '', concat('arti',a.id_articulo), concat('pack', p.id_pack)) AS id_articulo

Lo que viene a decir algo así como “si en la tabla listaboda (la que se ha mostrado en la imagen) el id del artículo NO es nulo, concatenar la frase ‘arti’ con el id del artículo (por ejemplo: arti128), en otro caso concatenar ‘pack’ con el id del pack. Asignar el resultado al campo ‘id_articulo'”.

Por tanto, al recuperar el campo ‘id_articulo’ tendremos o bien ‘arti128’ o ‘pack3’, con lo cual sabemos el tipo de artículo que hemos recuperado, su ID y el resto de los datos asociados.

A 3 personas les gusta esta entrada

Select multiple con DIV pasando arrays a Javascript

Vamos a aprovechar el código Javascript creado en el post anterior para crear un campo <select> dinámico que contendrá una serie de artículos recuperados de la base de datos. Muy útil para la selección de varios articulos en varias listas desplegables.

Como siempre el código habla por sí solo:

  1. &lt;!-- Importamos del port de php a javascript&gt;
  2. &lt;script language="javascript" src="php.js"&gt;&lt;/script&gt;
  3. &lt;!-- Importamos el js creado en el post anterior&gt;
  4. &lt;script language="javascript" src="generar_fila.js"&gt;&lt;/script&gt;
  5. &lt;?php
  6.     // Si se ha pulsado el submit, procesamos datos que nos llegan
  7.     if ($_POST)
  8.     {
  9.       echo var_dump($_POST);
  10.       echo "&lt;br/&gt;";
  11.       echo "&lt;br/&gt;";
  12.       echo "&lt;b&gt;Articulos recibidos:&lt;/b&gt;&lt;br/&gt;";
  13.       for ($i=0;$i&lt;count($_POST['articulos']);$i++)
  14.         echo "id del articulo: " . $_POST['articulos'][$i] . "&lt;br/&gt;";
  15.      
  16.       echo "&lt;br/&gt;";
  17.     }
  18. ?&gt;
  19.  
  20. &lt;!-- Formulario principal de la pagina --&gt;
  21. &lt;form name="formulario" id="formulario" action="listas.php" method="post" enctype="multipart/form-data"&gt;
  22. &lt;?php
  23.  
  24. // imaginemos que esto lo sacamos de la base de datos,
  25. // pero ahora vamos a hacer un array de prueba
  26. $articulos_bd[] = array('id_articulo' =&gt; '1', 'nombre' =&gt; 'Powered');  
  27. $articulos_bd[] = array('id_articulo' =&gt; '2', 'nombre' =&gt; 'by');  
  28. $articulos_bd[] = array('id_articulo' =&gt; '3', 'nombre' =&gt; 'Linux');  
  29.  
  30. // creamos dos listas, una con los ids de los articulos recogidos presuntamente de la BD ($ids),
  31. // y otra lista con los nombres de dichos articulos ($array)
  32. $lista_articulos = '&lt;select id="articulos_0" name="articulos[]"&gt;
  33.  &lt;option selected value=""&gt;-Seleccione un art&iacute;culo-&lt;/option&gt;';
  34.   $ids[] = "";
  35.   $ids[] = "-Seleccione un art&iacute;culo-";
  36.   $array[] = "";
  37.   $array[] = "-Seleccione un art&iacute;culo-";
  38.  
  39.   // recorremos la lista de articulos del array supuestamente extraido de la BD
  40.   for ($i=0;$i&lt;count($articulos_bd);$i++)
  41.   {
  42.     // montamos un elemento &lt;select&gt;&lt;/select&gt; normal de HTML con los datos
  43.     // de los articulos recogidos de la BD
  44.     $lista_articulos.='&lt;option id="'.$articulos_bd[$i]['id_articulo'].'" name="'.$articulos_bd[$i]['id_articulo'].'"  value="'.$articulos_bd[$i]['id_articulo'].'"&gt;'.$articulos_bd[$i]['nombre'].'&lt;/option&gt;';
  45.     $ids[] = $articulos_bd[$i]['id_articulo'];
  46.     $array[] = $articulos_bd[$i]['nombre'];
  47.   }
  48.   $lista_articulos.='&lt;/select&gt;';  
  49.  
  50. // creamos un div que contendra los diferentes campos &lt;select&gt;&lt;/select&gt;
  51. // con todos los productos y sus datos asociados  
  52. echo '
  53.   &lt;div id="tabla"&gt;
  54.   &lt;b&gt;Art&iacute;culo relacionado:&lt;/b&gt;
  55.   '.
  56.    $lista_articulos;
  57.    ?&gt;
  58.    &lt;!-- A la funcion addCampo le voy a pasar el evento originado,
  59.         una cadena con los nombres de los articulos separados por comas,
  60.         y otra cadena con los ids de los articulos tambien separados por comas --&gt;
  61.    &lt;input type="button" class="boton" value="Añadir" onClick="addCampo(event,'&lt;?php echo implode(",", $array); ?&gt;', '&lt;?php echo implode(",", $ids); ?&gt;')" alt="Insertar"&gt;&nbsp;
  62.  
  63.   &lt;!-- continuamos la generacion del formulario --&gt;
  64.    &lt;?php echo '        
  65.   &lt;/div&gt;
  66.   &lt;br/&gt;
  67.   &lt;input type="submit" value="Submit"/&gt;
  68. &lt;/form&gt;';

Y como siempre, para estas cosas es necesaria una demostración

La lista de referencias utilizadas ha sido la siguiente:
http://www.trans4mind.com/personal_development/JavaScript2/createSelectDynamically.htm
http://www.cristalab.com/tips/32381/subir-multiples-archivos-con-php.html

A 1 persona le gusta esta entrada

Port de funciones PHP ejecutando en Javascript

Os pongo en situación. Quería pasar desde PHP un array a una función Javascript. En esa función Javascript necesitaba hacer un bucle que me recorriera desde el primer elemento hasta el último, por lo que necesitaba conocer el número total de elementos.

Sin percatarme de los sabios consejos de Moisés acerca de la existencia de la propiedad length existente también para arrays, busco funciones como sizeof o count (existentes en PHP) para desarrollar en Javascript de forma más cómoda.

Por curiosidad busqué referencia sobre el asunto y me topé con el sitio Web de Kevin Vanzonneveld, en el que ofrecen un archivo php.js que contiene una serie de funciones PHP portadas a Javascript de manera impecable. En el sitio de Kevin se relatan las 212 funciones portadas hasta ahora.

En mi caso, sólo tuve que descargar el mencionado fichero php.js, enlazarlo con una etiqueta script y utilizar la función count como si lo hiciera con PHP de forma normal para contar el número de elementos de un array o descomponer cadenas en array seccionando según un carácter. Os dejo con un ejemplo que completaré en una próxima entrada. Lógicamente se podrían haber utilizado las propiedades nativas de Javascript length y split para desarrollar el ejemplo, pero así vemos una prueba para otras funciones de esta librería que no estén desarrolladas de forma nativa en Javascript.

[Javascript]var numero = 0;

// esta funcion añade un nuevo 'dd' al div principal con el contenido especificado
// recibe el evento disparado y dos arrays: el primero con las IDs de los campos
// select y el segundo con las IDs de las opciones que irán dentro de cada select

function addCampo(evento, array, ids) {
newID = 'articulos_' + (++numero) // genero una nueva ID
nDD = document.createElement('dd')
nDD.id = 'dd_' + numero
bold = document.createElement('b') // creo una etiqueta en negrita
bold.innerHTML = "Artículo relacionado: "

myselect = document.createElement("select") // creo un elemento <select>
myselect.name = "articulos[]" // le pongo de nombre el de un array previamente inicializado en PHP
myselect.id = newID

// aquí puedo utilizar la función explode al haber importado php.js, obteniendo los mismos
// resultados que en PHP, es decir, me separará en un array el resultado de descomponer
// la cadena separada por comas
var newArray = explode(',', array)
var newIDs = explode(',', ids)

// aquí puedo utilizar la función count de forma normal porque he incluido en el archivo .php
// correspondiente la importación de php.js. Como puede verse, puedo recorrer de forma normal
// el array incluyendo la funcion count dentro de mi for de Javascript
for (i=0;i<count(newArray);i++)
{
if (newArray[i] != ',' && newArray[i] != '')
{
// voy creando dinamicamente las opciones (<option>) para el <select>
// en base a los datos que he recibido como parámetros de la función
theOption = document.createElement("OPTION")
theText = document.createTextNode(newArray[i])
theOption.appendChild(theText)
theOption.id = newIDs[i]
theOption.name = newIDs[i]
theOption.value = newIDs[i]
myselect.appendChild(theOption)
}
}

// creo un enlace que me servirá para eliminar elementos <select>
// incluidos dentro de un DD
a = document.createElement('a')
a.name = nDD.id
a.href = '#'
a.onclick = elimCamp
a.innerHTML = ' Eliminar'

// adjunto todos los elementos al DD
nDD.appendChild(bold)
nDD.appendChild(myselect)
nDD.appendChild(a)

// al contenedor que tengo en la página PHP le adjunto el DD creado
container = document.getElementById('tabla')
container.appendChild(nDD)
}

//con esta función eliminamos el campo cuyo link de eliminación sea presionado
function elimCamp(evt){
evt = evento(evt)
nCampo = rObj(evt)
div = document.getElementById(nCampo.name)
div.parentNode.removeChild(div)
}

//con esta función recuperamos una instancia del objeto que disparo el evento
rObj = function (evt) {
return evt.srcElement ? evt.srcElement : evt.target;
}

//esta funcion nos devuelve el tipo de evento disparado
evento = function (evt) {
return (!evt) ? event : evt;
}
[/Javascript]

Sé el primero en valorar positivamente

‘Cannot redeclare pclziputilpathreduction’ en WordPress 2.7

Algunos habréis notado que al actualizar de forma automática con la nueva herramienta que nos ofrece WordPress 2.7 nos aparece un error Cannot redeclare pclziputilpathreduction, justo al intentar desempaquetar la nueva versión de WordPress.

La solucion es bien sencilla. Hay que desactivar el plugin WordPress Automatic Upgrade, con el que ya disfrutábamos de esta características que ahora WordPress integra de forma interna.

Sé el primero en valorar positivamente

Solucionar error “La página no está redirigiendo adecuadamente” en OsCommerce

Al intentar meter una nueva opción del box Clientes,

me he encontrado con un problema que me resultaba familiar y para el que no recordaba la solución:

se soluciona incluyendo el fichero que integra la nueva opción (en mi caso requests.php) en el array $aADMPages del fichero /admin/includes/functions/administrators.php, diciéndole cuál es su fichero superior (en mi caso customers.php, porque estoy dentro del box de clientes).

A 1 persona le gusta esta entrada