Categories
Artí­culos drupal Open Source PHP Ubercart

Ubercart para productos de tipo “servicio”

Este es un post de varios que empezaremos sobre Drupal.

Ubercart es un poderoso módulo de Drupal para vender productos o servicios.

Por defecto este módulo nos permite crear el tipo de nodo "Producto" con atributos de envío como peso, altura, etc.

Sin embargo unos proyectos que estoy haciendo necesité quitar este tipo de atributos para ofrecer sólo servicios. Un ejemplo sería por ejemplo ofrecer Tours.

Para esto he creado un pequeño módulo que básicamente oculta estos campos usando el hook_form_alter de la API de Drupal sin alterar el core de Ubercart. El código es el siguiente:

PHP:

function uc_service_form_alter(&$form, &$form_state, $form_id) {
  if ($form_id == "product_node_form") {
          
          // Precios
          $form['base']['prices']['list_price']["#type"]        = 'hidden';
          $form['base']['prices']['cost']["#type"]                = 'hidden';
          
          // Producto Físico
          $form['base']['shippable']['#type']         = 'hidden';
          $form['base']['shippable']['#default_value']   = FALSE;
          
          // Peso
          unset($form['base']['weight']);
          
          // Dimensiones
          unset($form['base']['dimensions']);
          
          // Cantidades
          $form['base']['default_qty']["#type"]                         = 'hidden';
          $form['base']['default_qty']["#default_value"]        = 0;
          
          unset($form['base']['pkg_qty']);
  }
}
 

Instalación

  1. Descomprimir el archivo
  2. Copiar la carpeta uc_service en /sites/all/modules/ o /modules/ depende donde hayas instalado Ubercart.
  3. Activar el módulo en /admin/build/modules/.
  4. Crear tus productos tipo servicio.

He probado este módulo en algunos sitios y todo va bien, sin embargo cualquier observación háganmelo saber.

Descargar el módulo uc_service.

Categories
Miniposts PHP Seguridad XSS

¿Estás cometiendo estos 10 errores en PHP?

¿Estás cometiendo estos 10 errores en PHP?

Categories
PHP WordPress

Tip: Optimización de consultas SQL en plugins de WordPress

Durante el tiempo que no hubo actividad alguna en este blog y por algunos trabajos que me encomendaron relacionados al desarrollo de plugins y modificación del código de WordPress, he visto algo que se repite casi en todos los plugins que he visto hasta el momento: usan varias consultas pequeñas cuando sólo una puede hacer el trabajo (no tengo idea de porqué hacen las cosas de ese modo).

php:

$a = query("select ID from tabla1 ...");
$b = array();
foreach($a as $v) {
        $b[] = query("select ... from tabla2 where ID = $v");
}

El problema del código mostrado es que se hacen consultas innecesarias a la base de datos cuando en este caso un simple JOIN serviría para el mismo propósito.

Como ejemplo voy a poner dos plugins que acompañaron a este blog desde hace más de un año y por los que el número de consultas SQL aunmentaba en 55 para generar la página principa. Éstos son:

  • Real Fast Latest Comments: En este caso el plugin realiza una consulta para obtener las entradas que recibieron comentarios recientemente y luego itera para mostrar los datos devueltos:

    php:

    function rflc_show_comments($comment_limit = 5, $show_trackbacks = false) {
            global $wpdb;

            if(!$show_trackbacks) {
                    $activity = $wpdb->get_results("SELECT $wpdb->comments.comment_date, $wpdb->comments.comment_author,
                                                    $wpdb->comments.comment_ID, $wpdb->posts.post_title,
                                                    $wpdb->posts.ID FROM $wpdb->comments INNER JOIN
                                                    $wpdb->posts ON $wpdb->posts.ID = $wpdb->comments.comment_post_ID WHERE
                                                    $wpdb->comments.comment_approved = '1' AND $wpdb->comments.comment_type
                                                    NOT LIKE '%back%' ORDER BY $wpdb->comments.comment_date DESC
                                                    LIMIT $comment_limit");
            } else {
                    $activity = $wpdb->get_results("SELECT $wpdb->comments.comment_date, $wpdb->comments.comment_author,
                                                    $wpdb->comments.comment_ID, $wpdb->posts.post_title,
                                                    $wpdb->posts.ID FROM $wpdb->comments INNER JOIN
                                                    $wpdb->posts ON $wpdb->posts.ID = $wpdb->comments.comment_post_ID WHERE
                                                    $wpdb->comments.comment_approved = '1'
                                                    ORDER BY $wpdb->comments.comment_date DESC
                                                    LIMIT $comment_limit");
            }
           
            if($activity) {
                    echo '<ul>';
                    foreach($activity as $comment) {

                            echo '<li>'.wp_specialchars($comment->comment_author).' en: <a href="'. get_permalink($comment->ID) .'#comment-'. $comment->comment_ID .'">'. wp_specialchars($comment->post_title) .'</a></li>' . "\n";

                    }
                    echo '</ul>';
            }
    }

    El problema en este caso es que para mostrar el enlace (permalink) de una entrada, el plugin invoca en cada iteración a la función get_permalink, la misma que hace una nueva consulta (o varias dependiendo de la estructura de permalinks) para recuperar la entrada y formatear el enlace, esto pasa siempre y cuando el argumento pasado no sea un objeto o la entrada ya se encuentre en la caché de objetos.

  • Related Posts: El problema es el mismo que se comenta en el anterior, a continuación muestro la parte relevante:

    php:

    $sql = "SELECT ID, post_title, post_content,"
             . "MATCH (post_name, post_content) "
             . "AGAINST ('$terms') AS score "
             . "FROM $wpdb->posts WHERE "
             . "MATCH (post_name, post_content) "
             . "AGAINST ('$terms') "
             . "AND post_date <= '$now' "
             . "AND (post_status IN ( 'publish',  'static' ) && ID != '$post->ID') ";
    if ($show_pass_post=='false') { $sql .= "AND post_password ='' "; }
    $sql .= "ORDER BY score DESC LIMIT $limit";
    $results = $wpdb->get_results($sql);
    $output = '';
    if ($results) {
            foreach ($results as $result) {
                    $title = stripslashes(apply_filters('the_title', $result->post_title));

                    $permalink = get_permalink($result->ID);

                    $post_content = strip_tags($result->post_content);
                    $post_content = stripslashes($post_content);
                    $output .= $before_title .'<a href="'. $permalink .'" rel="bookmark" title="Permanent Link: ' . $title . '">' . $title . '</a>' . $after_title;

                    if ($show_excerpt=='true') {
                            $words=split(" ",$post_content);
                            $post_strip = join(" ", array_slice($words,0,$len));
                            $output .= $before_post . $post_strip . $after_post;
                    }
            }
            echo $output;
    }

Para evitar este comportamiento pero con algunas posibles consecuencias no deseadas**, se debe recuperar también el campo post_name en la primera consulta de ambos casos y a continuación invocar a la función get_permalink con un objeto como parámetro -- get_permalink($comment); y get_permalink($result); respectivamente.

**: Al usar la función get_permalink con un objeto como parámetro, éste se almacena en el caché de objetos y cualquier función que haga uso de get_post puede mostrar entradas "incompletas". Una forma de evitar esto es recuperar todos los campos de la tabla posts o quitar la entrada almacenada en cache luego de invocar a la función get_permalink.

Categories
.NET Microsoft Miniposts PHP

Misión Géminis 48 hs.

Para los que puedan estar interesados, Misión Géminis 48 hs. es un concurso de Microsoft para...

... demostrar en 2 etapas qué tanto sabes acerca de .Net y PHP. Durante la primera etapa deberás responder una serie de preguntas de selección múltiple sobre estos lenguajes de programación. Los participantes que contesten correctamente todo el cuestionario, con la posibilidad de múltiples intentos, podrán pasar a la segunda etapa – La Misión. Allí deberás estar preparado para el reto de desarrollar una aplicación web funcional, un sistema de Control Epidemiológico basado en PHP, y migrarla a ASP.NET. Tendrás sólo 48 horas para hacerlo, y los primeros 48 que lo hagan estarán participando por increíbles premios. Los 3 ganadores designados por especialistas calificados recibirán U$D 1.000, U$D 800 y U$D 400, respectivamente.

Para mayor información revisen la página del concurso.

Categories
PHP WordPress

WordPress: Llamadas múltiples en XML-RPC

Según WikiPedia, XML-RPC es un protocolo de llamada a procedimiento remoto que usa XML para codificar los datos y HTTP como protocolo de transmisión de mensajes, creado por Dave Winer (Userland Software) y Microsoft en 1998.

A pesar de que este protocolo tiene mucho más tiempo de lo que yo con el uso de computadoras, recién hace 3 meses que conozco de la existencia de éste y algo que me llama la atención es el soporte para invocar múltiples métodos en una sola petición HTTP -- aunque en realidad depende si el servidor XML-RPC implementa/soporta este tipo de llamadas.

Por ejemplo, el servidor XML-RPC de WordPress soporta este tipo de llamadas gracias a Incutio XML-RPC Library:

php:

<?php
require_once( './class-IXR.php' );

$client = new IXR_ClientMulticall( 'http://www.buayacorp.com/xmlrpc.php' );

$client->debug = true;

$client->addCall('demo.sayHello');
$client->addCall('demo.addTwoNumbers', 10, 1);

$client->query();

print_r($client->getResponse());
?>

Lo que se envía y recibe del servidor:

code:

POST /xmlrpc.php HTTP/1.0
Host: www.buayacorp.com
Content-Type: text/xml
User-Agent: The Incutio XML-RPC PHP Library (multicall client)
Content-length: 652

<?xml version="1.0"?>
<methodCall>
<methodName>system.multicall</methodName>
<params>
<param><value><array><data>
  <value><struct>
  <member><name>methodName</name><value><string>demo.sayHello</string></value></member>
  <member><name>params</name><value><array><data>
</data></array></value></member>
</struct></value>
  <value><struct>
  <member><name>methodName</name><value><string>demo.addTwoNumbers</string></value></member>
  <member><name>params</name><value><array><data>
  <value><int>10</int></value>
  <value><int>1</int></value>
</data></array></value></member>
</struct></value>
</data></array></value></param>
</params></methodCall>

<?xml version="1.0"?>
<methodResponse>
<params>
<param>
<value>
<array><data>
<value><array><data>
<value><string>Hello!</string></value>
</data></array></value>
<value><array><data>
<value><int>11</int></value>
</data></array></value>
</data></array>
</value>
</param>
</params>
</methodResponse>

Array
(
    [0] => Array
        (
            [0] => Hello!
        )

    [1] => Array
        (
            [0] => 11
        )

)

Haciendo uso de este tipo de llamadas y gracias a ciertas características de WordPress, fue posible hacer funcionar el tan publicitado exploit para una vulnerabilidad que afecta a casi todas las versiones de este CMS.