Estilos sólo para Ipad

Si se desea aplicar unos estilos sólo para el , se puede hacer (al menos en este momento) de la siguiente forma:

Ejemplo:
  1. <style  type="text/css" media="only screen and (min-device-width: 768px) and (max-device-width: 1024px)">
  2.  body {
  3.   text-align: center;
  4.   background: #434242  url(img/_bg_iphone.png) no-repeat 50% 10px ;
  5.  }
  6.  #wrapper {
  7.   position: relative;
  8.   margin: 170px auto 50px auto;
  9.   width: 320px;
  10.   height: 460px;
  11.  }
  12. </style>

Aplicaciones Facebook sobre SSL

mensaje https facebook

Hace unos días Facebook ha empezado a mostrar mensajes de error cuando se accedía a aplicaciones desde https, estando disponible para los desarrolladores, en la configuración de la aplicación, dos nuevos campos, para indicar las urls seguras (sobre https).

Para evitar esto debemos, claramente, añadir soporte https a nuestra aplicación, algo que si bien es sencillo, nos dará más que un quebradero de cabeza. Esto se debe a que nos encontraremos con los nuevos y vitales “bugs” con los que Facebook nos premia a todos los desarrolladores. [Read more...]

Implementar Haanga como sistema de plantillas para OpenCart

haanga

OpenCart es una plataforma de comercio electrónica hecha en , con un impecable, 100% MVC. Como prueba de concepto he reescrito el sistema de plantillas de OpenCart a Haanga (plantillas “Django” para PHP, über eficiente) de César Rodas.

¿ Por que Haanga ?, simplemente porque me gusta.
¿ Por qué OpenCart ?, simplemente porque me gusta como está desarrollado.

Implementación, he creado una clase TemplateEngine con el siguiente código:

  1.  class TemplateEngine {
  2.    public $template = null ;
  3.    public $default = array();
  4.    public $config = array();
  5.  
  6.    function __construct( $templateDir = null  ) {
  7.     $this->loadDefaults( $templateDir);
  8.    }
  9.    
  10.  
  11.    protected function loadDefaults( $templateDir) {
  12.     $this->default = array();
  13.      $this->config = array(
  14.     'template_dir' => (( is_null( $templateDir )) ? Settings::getInstance()->getValue('Web.root') .'' : $templateDir),
  15.     'cache_dir' =>  Settings::getInstance()->getValue('Web.root'). 'cache.templates',
  16.     'compiler' => array(  
  17.      'if_empty' => FALSE,
  18.      'autoescape' => FALSE,
  19.      'strip_whitespace' => TRUE,
  20.       'allow_exec'  => TRUE,
  21.      'global' => array( ),
  22.      'use_hash_filename' => FALSE  
  23.     )
  24.    );
  25.    }
  26.  
  27.   function loadEngine() {
  28.    // incluimos  
  29.     require_once Settings::getInstance()->getValue('Web.root') . 'lib/vendors/Haanga.php';
  30.      Haanga::configure($this->config);
  31.  
  32.  
  33.  
  34.   }
  35.     function loadTemplate( $name ) {
  36.     $this->template =   $name  ;
  37.    }
  38.     function display( $vars = array()) {
  39.     $this->loadEngine();
  40.      $vars = array_merge( $this->default, $vars);
  41.      Haanga::Load( $this->template , $vars);
  42.    
  43.    }
  44.  
  45.  }

Ahora sólo queda indicarle al que haga uso de esta clase:
en /system/engine/controller.php

Modificando los métodos render y fetch, renombrando el antiguo fetch a __fetch

  1. []
  2. protected function render($return = FALSE) {
  3.   foreach ($this->children as $child) {
  4.    $action = new Action($child);
  5.    $file   = $action->getFile();
  6.    $class  = $action->getClass();
  7.    $method = $action->getMethod();
  8.    $args   = $action->getArgs();
  9.  
  10.    if (file_exists($file)) {
  11.     require_once($file);
  12.  
  13.     $controller = new $class($this->registry);
  14.    
  15.     $controller->index();
  16.     $this->data[$controller->id] =  $controller->output;
  17.    
  18.     $this->addToModule( $controller->id, $controller->output );
  19.     } else {
  20.     exit('Error: Could not load controller ' . $child . '!');
  21.    }
  22.   }
  23.  
  24.   if ($return) {
  25.    return $this->fetch($this->template);
  26.   } else {
  27.    $this->output = $this->fetch($this->template);
  28.   }
  29.  }
  30.  
  31.   protected function addToModule( $module , $output ) {
  32.    $i = 0 ;
  33.    if ( !isset( $this->data['modules'] )) { return ;}
  34.    foreach( $this->data['modules'] as $item ) {
  35.     if ( $item['code'] == $module ) {
  36.      $this->data['modules'][$i]['output'] = $output;
  37.      return ;
  38.    
  39.     }
  40.     $i++;
  41.    }
  42.  
  43.   }
  44.  
  45.   protected function fetch($filename) {
  46.    if ( substr( $_SERVER['REQUEST_URI'], 0, 7) == '/admin/') {
  47.     return $this->__fetch( $filename);
  48.    
  49.    } else {
  50.           ob_start();
  51.        $this->templateEngine->loadTemplate( $filename );
  52.        $this->templateEngine->display( $this->data);
  53.      $content = ob_get_contents();
  54.         ob_end_clean();
  55.         return $content;
  56.         }
  57.     }
  58. protected function __fetch($filename) {
  59.   $file = DIR_TEMPLATE . $filename;
  60.       if (file_exists($file)) {
  61.    extract($this->data);
  62.     ob_start();
  63.      
  64.      require($file);
  65.      
  66.      $content = ob_get_contents();
  67.  
  68.         ob_end_clean();
  69.  
  70.         return $content;
  71.      } else {
  72.         exit('Error: Could not load template ' . $file . '!');
  73.      }
  74.  }
  75.  
  76. []

Para evitar utilizar Haanga en la administración se comprueba que la url no sea de la administración, de ser así se utiliza el motor de plantillas original.

  1. []
  2.    if ( substr( $_SERVER['REQUEST_URI'], 0, 7) == '/admin/') {
  3.     return $this->__fetch( $filename);
  4. []

Una de las particularidades de las plantillas es que hacen uso de $$variable a la hora de mostrar la salida de los módulos, y es por esto (imposible, por lo que parece, en Haanga) que he añadido un método y comprobación para que cada módulo devuelva a la plantilla su salida en un elemento “output” de la matriz y es el que mostraremos.

Así, al final, una plantilla como la de la visualización de las categorías queda en algo como los siguientes ejemplos:
/catalog/view/theme/default/common/column_right.tpl

  1. <div id="column_right">
  2.  
  3.  {% for module in modules %}
  4.  
  5.     {{ module.output }}
  6.  
  7.   {% endfor %}
  8.  
  9. </div>

/catalog/view/theme/default/product/category.tpl

  1. {% extends "layout/default.html" %}
  2. {% block content %}
  3. <div id="content">
  4.   <div class="top">
  5.     <div class="left"></div>  
  6.     <div class="right"></div>
  7.     <div class="center">
  8.       <h1>{{ heading_title }}</h1>
  9.     </div>
  10.   </div>
  11.   <div class="middle">
  12.     <table style="padding-bottom:10px;">
  13.    <tr>
  14.         {% if thumb %}
  15.         <td><img src="{{ thumb }}" alt="{{ heading_title }}" /></td>  
  16.  {% endif %}
  17.         {% if description %}
  18.       <td>{{ description }}</td>
  19.  {% endif %}
  20.    </tr>    
  21.  </table>
  22.  
  23.  {% if  !categories  &&   !products %}<div class="content">{{ text_error|default:"" }}</div>{% endif %}
  24.      
  25.     {% if categories %}
  26.  
  27.    <table>
  28.     {% for category in categories %}
  29.      
  30.    
  31.           <a href="{{ category['href'] }}"><img src="{{ category['thumb'] }}" title="{{ category['name'] }}" alt="{{ category['name'] }}" style="margin-bottom: 3px;" /></a><br />
  32.           <a href="{{ category['href'] }}">{{ category['name'] }}</a>
  33.  
  34.     </table>
  35.     {% endfor %}
  36.  
  37.  {% endif %}
  38.  
  39.  
  40.  
  41.     {% if products %}
  42.     <div class="sort">
  43.       <div class="div1">
  44.         <select name="sort" onchange="location = this.value">
  45.          {% buffer sort_order %}{{sort}}-{{order}}{% endbuffer %}
  46.  
  47.          {% for sort  in sorts %}
  48.            <option value="{{ sort['href'] }}" {% if sort_order == sort['value'] %} selected="selected"{% endif %}>{{ sort['text'] }}</option>
  49.           {% endfor %}
  50.         </select>
  51.       </div>
  52.       <div class="div2">{{ text_sort }}</div>
  53.     </div>
  54.    
  55.    
  56.    {% inline "elements/lista_productos.html" %}
  57.    
  58.      
  59.      
  60.     <div class="pagination">{{ pagination }}</div>
  61.  
  62.  {% endif %}
  63.  
  64.   </div>
  65.   <div class="bottom">
  66.     <div class="left"></div>
  67.     <div class="right"></div>
  68.     <div class="center"></div>
  69.   </div>
  70. </div>
  71. {% endblock %}

Actualización claves GPG repositorios Ubuntu

Ubuntu Server

Algunas veces es posible que debamos actualizar las claves públicas de algunos repositorios de . Un síntoma es el siguiente error:

W: error: http://ppa.launchpad.net intrepid Release: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 4FEC45DD06899068

La solución es bien sencilla.

  1. sudo apt-key adv –recv-keys \
  2.     –keyserver keyserver.ubuntu.com \
  3.     06899068

Ver las 10 IPs con más acceso

DSC_1242

Una “receta” para tener a mano:

cat fichero.log  |
  1.        \ '{print $1}'  |
  2.        \ sort |
  3.        \ uniq -c |
  4.        \ sort -n |
  5.        \ -10