miércoles, 4 de septiembre de 2013

Android: Compartir en redes sociales

En esta ocasión vamos a compartir texto e imágenes en las distintas redes sociales, para esto vamos a añadir a nuestro Activity el siguiente método

public void shareSocialNetwork(String title, String extraTitle,
            String filename) {
        Intent share = new Intent(Intent.ACTION_SEND);
        share.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
        share.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File(filename)));
        share.putExtra(Intent.EXTRA_TITLE, extraTitle);
        share.putExtra(Intent.EXTRA_SUBJECT, extraTitle);
        share.setType("image/png");
        startActivity(Intent.createChooser(share, title));
    }


Este método es el encargado de mostrar el dialogo para la selección de redes sociales y los valores por defecto a compartir.

Para ejecutarlo creamos un botón con id btnShare al cual le asignaremos el evento:

ImageButton btnShare = (ImageButton) findViewById(R.id.btnShare);
        btnShare.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {

               shareSocialNetwork("
PensandoEnBinario",
             "Powered by PensandoEnBinario",inputFilename); //inputFilename es una imagen (uri) para compartir
}
});


Listo, ya tenemos un botón que permite compartir en las redes sociales.

Android FullScreen Activity

Muchas aplicaciones móviles requieren mostrarse en FullScreen, para esto tenemos dos posibilidades

Fullscreen en toda la aplicación:

Es necesario editar el archivo :
AndroidManifest.xml
Y en la sección application se añade el parametro:
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"

Fullscreen en pantallas especificas:

Es necesario en el método: onCreate
añadir las siguientes líneas (después de super.onCreate(savedInstanceState)):

 requestWindowFeature(Window.FEATURE_NO_TITLE);
 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
 WindowManager.LayoutParams.FLAG_FULLSCREEN);


Listo!!

lunes, 26 de agosto de 2013

Linux + Android SDK + Célular Android (USB Drivers)

El presente es un tutorial para conectar Android SDK con los célulares Android de distintos fabricantes.

Lo primero que tenemos que hacer es detectar es el fabricante de nuestro célular. Para eso conectamos por USB el célular a la PC y ejecutamos

#lsusb

Tendremos una lista con los distintos puertos USB y el fabricante del dispositivo conectado.

El fabricante de mi dispositivo (célular) es el siguiente:

Bus 005 Device 006: ID 0fce:6193 Sony Ericsson Mobile Communications AB

Si todavía no encuentran el suyo pueden probar ejecutando "lsusb" con y sin conectar por USB el célular. El que se añadede en la lista será el de su célular.

Uno de los parametros de la línea extraida es el Id del fabricante, a continuación lo marcamos de rojo:

Bus 005 Device 006: ID 0fce:6193 Sony Ericsson Mobile Communications AB 

Luego de que tenemos detectado el Id del fabricante tendremos que editar o crear el archivo (como usuario root):
#/etc/udev/rules.d/51-android.rules

En este archivo añadimos la siguiente línea
SUBSYSTEM=="usb", ATTR{idVendor}=="0fce", MODE="0666", GROUP="plugdev" 

Noten que el Id del fabricante esta marcado de rojo. Este es el valor de nuestro fabricante de dispositivo (Célular)

Nos queda darle permisos al archivo:
#chmod a+r /etc/udev/rules.d/51-android.rules

Desconectamos y conectamos el USB de conexión al célular y probamos con la herramienta del SDK Android (sdk/platform-tools)
#adb devices
List of devices attached
BX903H993B    device


Listo hemos logrado la conexión de nuestro Android SDK con nuestro dispositivo android y podemos comenzar a desarrollar.

lunes, 8 de julio de 2013

Apache 2.4 añadir VirtualHost para Zend Framework 2

La versión de ZF2 trae por defecto una configuración para levantar un VirtualHost en Apache. Pero esta configuración no funciona correctamente en Apache 2.4.

A continuación adjunto la configuración correcta para Apache 2.4, espero les sea útil.


<VirtualHost *:80>
  ServerName "local.mipagina.com"
  DocumentRoot "/home/webmaster/local.mipagina.com/public"
  SetEnv APPLICATION_ENV "development"
  ErrorLog "/var/log/httpd/local.mipagina.com.err"
  <Directory "/home/webmaster/local.mipagina.com/public">
    DirectoryIndex index.php
    Options Indexes FollowSymLinks
    AllowOverride All
    Allow from All
    require all granted
  </Directory>
</VirtualHost> 


Probado en Slackware 14

viernes, 25 de enero de 2013

PHP - capturar el IP del cliente

Adjunto un script muy necesario para poder extraer el IP del cliente, que incluye validaciones de red interna, host local y redirecciones:
function getIp()
    {
        if (isset($_SERVER['HTTP_X_FORWARDED_FOR']) 
     AND $_SERVER['HTTP_X_FORWARDED_FOR'] 
     AND (!isset($_SERVER['REMOTE_ADDR']) 
     OR preg_match('/^127\..*/i', trim($_SERVER['REMOTE_ADDR'])) 
     OR preg_match('/^172\.16.*/i', trim($_SERVER['REMOTE_ADDR'])) 
     OR preg_match('/^192\.168\.*/i', trim($_SERVER['REMOTE_ADDR'])) 
     OR preg_match('/^10\..*/i', trim($_SERVER['REMOTE_ADDR'])))) {
                $ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
                return $ips[0];
        }
        return $_SERVER['REMOTE_ADDR'];
    }

lunes, 12 de marzo de 2012

Mejorando Prestashop: cambio de driver Mysql a Mysqli

La presente es una mejora de Prestashop, se cambia el driver Mysql por Mysqli. Para esto creamos la clase "classes/MySQL2.php" con el siguiente código:

class MySQL2Core extends Db
{
 public function connect()
 {
            
  if (!defined('_PS_DEBUG_SQL_'))
   define('_PS_DEBUG_SQL_', false);
  if ($this->_link = mysqli_connect($this->_server, $this->_user, $this->_password))               
                { 
   if (!$this->set_db($this->_database))
    die(Tools::displayError('The database selection cannot be made.'));
  }
  else
   die(Tools::displayError('Link to database cannot be established.'));
  /* UTF-8 support */
  if (!mysqli_query($this->_link,'SET NAMES \'utf8\''))
   die(Tools::displayError('PrestaShop Fatal error: no utf-8 support. Please check your server configuration.'));
  // removed SET GLOBAL SQL_MODE : we can't do that (see PSCFI-1548)
  return $this->_link;
 }
 
 public function getServerVersion(){
  return mysqli_get_server_info();
 }
 
 /* do not remove, useful for some modules */
 public function set_db($db_name) {
  return mysqli_select_db($this->_link , $db_name );
 }
 
 public function disconnect()
 {
  if ($this->_link)
   @mysqli_close($this->_link);
  $this->_link = false;
 }
 
 public function getRow($query, $use_cache = 1)
 {
  $query .= ' LIMIT 1';
  $this->_result = false;
  $this->_lastQuery = $query;
  if ($use_cache AND _PS_CACHE_ENABLED_){
      $result = Cache::getInstance()->get(md5($query));
      if ( !(gettype($result) === 'boolean' &&  ($result === false) ) )
   {
    $this->_lastCached = true;
    return $result;
   }
  }
  if ($this->_link)
   if ($this->_result = mysqli_query($this->_link, $query))
   {
// echo 'getRow : '. $query ."\n";
    $this->_lastCached = false;
    if (_PS_DEBUG_SQL_)
     $this->displayMySQLError($query);
    $result = mysqli_fetch_assoc($this->_result);
    if ($use_cache = 1 AND _PS_CACHE_ENABLED_){
        Cache::getInstance()->setQuery($query, $result);
    }
    return $result;
   }
  if (_PS_DEBUG_SQL_)
   $this->displayMySQLError($query);
  return false;
 }

 public function getValue($query, $use_cache = 1)
 {
  $query .= ' LIMIT 1';
  $this->_result = false;
  $this->_lastQuery = $query;
  if ($use_cache AND _PS_CACHE_ENABLED_){
      $result = Cache::getInstance()->get(md5($query));
      if ( !(gettype($result) === 'boolean' &&  ($result === false) ))
       {
        $this->_lastCached = true;
        return $result;
       }

  }
  
  if ($this->_link AND $this->_result = mysqli_query($this->_link, $query) AND is_array($tmpArray = mysqli_fetch_assoc($this->_result)))
  {
// echo 'getValue : '. $query ."\n";
      
   $this->_lastCached = false;
   $result =  array_shift($tmpArray);
   if ($use_cache AND _PS_CACHE_ENABLED_){
       Cache::getInstance()->setQuery($query, $result);
   }
   return $result;
  }
  
  return false;
 }
 
 public function Execute($query, $use_cache = 1)
 {
  $this->_result = false;
  if ($this->_link)
  {
   $this->_result = mysqli_query($this->_link, $query);
// echo 'Execute : '. $query ."\n";
   
   if (_PS_DEBUG_SQL_)
    $this->displayMySQLError($query);
   if ($use_cache AND _PS_CACHE_ENABLED_){
       Cache::getInstance()->deleteQuery($query); //VALIDAR POR Q BORRA EL CACHE
   }
   return $this->_result;
  }
  if (_PS_DEBUG_SQL_)
   $this->displayMySQLError($query);
  return false;
 }
 
 /**
  * ExecuteS return the result of $query as array, 
  * or as mysqli_result if $array set to false
  * 
  * @param string $query query to execute
  * @param boolean $array return an array instead of a mysql_result object
  * @param int $use_cache if query has been already executed, use its result
  * @return array or result object 
  */
 public function ExecuteS($query, $array = true, $use_cache = 1)
 {   
  $this->_result = false;
  $this->_lastQuery = $query;
  if ($use_cache AND _PS_CACHE_ENABLED_){
      $result = Cache::getInstance()->get(md5($query));
      if ($array  AND  !(gettype($result) === 'boolean' &&  ($result === false) ) ) 
   {
    $this->_lastCached = true;
    return $result;
    
   } 
  }
                
  if ($this->_link && $this->_result = mysqli_query($this->_link, $query)){
                    
// echo 'ExecuteS ' . $query . ' -- ' . $array . $use_cache. "\n";      
   $this->_lastCached = false;
   if (_PS_DEBUG_SQL_)
    $this->displayMySQLError($query);
   
                        if (!$array)
    return $this->_result;
   $resultArray = array();
   // Only SELECT queries and a few others return a valid resource usable with mysqli_fetch_assoc
   if ($this->_result !== true){                            
    while ($row = mysqli_fetch_assoc($this->_result))
     $resultArray[] = $row;
   }
   if ($use_cache AND _PS_CACHE_ENABLED_){
       Cache::getInstance()->setQuery($query, $resultArray);
   }
   return $resultArray;
  }
  if (_PS_DEBUG_SQL_)
   $this->displayMySQLError($query);
  return false;
 }

 public function nextRow($result = false)
 {
  return mysqli_fetch_assoc($result ? $result : $this->_result);
 }
 
 public function delete($table, $where = false, $limit = false, $use_cache = 1)
 {
     $this->_result = false;
  if ($this->_link)
  {
   $query  = 'DELETE FROM `'.pSQL($table).'`'.($where ? ' WHERE '.$where : '').($limit ? ' LIMIT '.(int)($limit) : '');
   $res =  mysqli_query($this->_link, $query);
// echo 'delete : '. $query ."\n";
   
   if ($use_cache AND _PS_CACHE_ENABLED_){
       Cache::getInstance()->deleteQuery($query);
   }
   return $res;
  }
   
  return false;
 }
 
 public function NumRows()
 {
  if (!$this->_lastCached AND $this->_link AND $this->_result)
  {
   $nrows = mysqli_num_rows($this->_result);
   if (_PS_CACHE_ENABLED_){
    Cache::getInstance()->setNumRows(md5($this->_lastQuery), $nrows);
   }
   return $nrows;
  }
  elseif (_PS_CACHE_ENABLED_ AND $this->_lastCached)
  {
   return Cache::getInstance()->getNumRows(md5($this->_lastQuery));
  }
 }
 
 public function Insert_ID()
 {
  if ($this->_link)
   return mysqli_insert_id($this->_link);
  return false;
 }
 
 public function Affected_Rows()
 {
  if ($this->_link)
   return mysqli_affected_rows($this->_link);
  return false;
 }

 protected function q($query, $use_cache = 1)
 {
  global $webservice_call;
  $this->_result = false;
  if ($this->_link)
  {
   $result =  mysqli_query($this->_link, $query);
// echo 'q : '. $query ."\n";
   
   $this->_lastQuery = $query;
   if ($webservice_call)
    $this->displayMySQLError($query);
   if ($use_cache AND _PS_CACHE_ENABLED_){
       Cache::getInstance()->deleteQuery($query);
   }
   return $result;
  }
  return false;
 }
 
 /**
  * Returns the text of the error message from previous MySQL operation
  *
  * @acces public
  * @return string error
  */
 public function getMsgError($query = false)
 {
  return mysqli_error($this->_link);
 }

 public function getNumberError()
 {
  return mysqli_errno($this->_link);
 }

 public function displayMySQLError($query = false)
 {
  global $webservice_call;
  if ($webservice_call && mysqli_errno($this->_link))
  {
   WebserviceRequest::getInstance()->setError(500, '[SQL Error] '.mysqli_error($this->_link).'. Query was : '.$query, 97);

  }
  elseif (_PS_DEBUG_SQL_ AND mysqli_errno($this->_link) AND !defined('PS_INSTALLATION_IN_PROGRESS'))
  {
   if ($query)
    die(Tools::displayError(mysqli_error($this->_link).'

'.$query.'
')); die(Tools::displayError((mysqli_error($this->_link)))); } } /** * tryToConnect return 0 if the connection succeed and the database can be selected. * @since 1.4.4.0, the parameter $newDbLink (default true) has been added. * * @param string $server mysql server name * @param string $user mysql user * @param string $pwd mysql user password * @param string $db mysql database name * @param boolean $newDbLink if set to true, the function will not create a new link if one already exists. * @return integer */ public static function tryToConnect($server, $user, $pwd, $db, $newDbLink = true) { if (!$link = @mysqli_connect($server, $user, $pwd)) return 1; if (!@mysqli_select_db($link,$db)) return 2; @mysqli_close($link); return 0; } public static function tryUTF8($server, $user, $pwd) { $link = @mysqli_connect($server, $user, $pwd); if (!mysqli_query($link,'SET NAMES \'utf8\'')) $ret = false; else $ret = true; @mysqli_close($link); return $ret; } }

Y en el archivo "classes/Db.php" cambiamos:

self::$_instance[(int)($idServer)] = new MySQL(self::$_servers[(int)($idServer)]['server'], self::$_servers[(int)($idServer)]['user'], self::$_servers[(int)($idServer)]['password'], self::$_servers[(int)($idServer)]['database']);

Por

self::$_instance[(int)($idServer)] = new MySQL2(self::$_servers[(int)($idServer)]['server'], self::$_servers[(int)($idServer)]['user'], self::$_servers[(int)($idServer)]['password'], self::$_servers[(int)($idServer)]['database']);

Suerte en la implementación !!
Enhanced by Zemanta

lunes, 27 de febrero de 2012

Prestashop y cache de página ZendFramework


En esta ocasión vamos a aplicar el cache de página que trae ZendFramework en Prestashop de una manera sencilla.

* Paso 0 : Preparativos

1. Debemos tener instaladas las librerías de ZendFramework dentro de Prestashop en
la carpeta: library/Zend

2. Habilitamos el cache de Prestashop:
config/settings.inc.php:
define('_PS_CACHING_SYSTEM_', 'CacheFS');
define('_PS_CACHE_ENABLED_', 1)
config/defines.inc.php:
define('_PS_CACHEFS_DIRECTORY_', dirname(__FILE__).'/../cache/');

Al estar utilizando Cache de Archivo tendremos que darle permisos a la carpeta indicada por la constante: _PS_CACHEFS_DIRECTORY_
chmod a+rw -Rf

* Paso 1 : Cache de Página

En este paso vamos a crear la lógica para el cache de archivos. Para esto creamos el archivo : config/cache.page.inc.php

<?php
if (function_exists('date_default_timezone_set'))
    @date_default_timezone_set('America/Lima') ;
define('APPLICATION_PATH', realpath(dirname(__FILE__)));
set_include_path(implode(PATH_SEPARATOR, array(
    realpath(APPLICATION_PATH . '/library'),
    get_include_path(),
)));
require_once('Zend/Cache.php');
if (_PS_CACHE_ENABLED_) {
    $frontendOpts = array(
    'lifetime' => 60*60*4,
    'debug_header' => false,
    'regexps' => array(
    '^/$' => array('cache' => true),
    '^/es/$' => array('cache' => true),
    '^/Myadmin/$' => array('cache' => false)               
    )
    );
    switch(_PS_CACHING_SYSTEM_){
    case 'MCached':
    $servers = MCachedCore::getMemcachedServers();
    if (!$servers) return false;
    foreach ($servers AS $server)
        $servidores[] = array('host' => $server['ip'], 'port' => $server['port']);   
    $backendOpts = array(
        'servers' => $servidores,
        'compression' => false
        );
    $cache = Zend_Cache::factory('Page', 'Memcached', $frontendOpts, $backendOpts);
    break;  
    default :
    $backendOpts = array(
        'cache_dir' => _PS_CACHEFS_DIRECTORY_,
         'hashed_directory_level' => 2
        );
    $cache = Zend_Cache::factory('Page', 'File', $frontendOpts, $backendOpts);
    break;
    }
    if (!isset($_GET['iso_lang'])){
    global $cookie;
    if (! isset($cookie)){
        $cookieLifetime = (time() + (((int) Configuration::get('PS_COOKIE_LIFETIME_FO') > 0 ? (int) Configuration::get('PS_COOKIE_LIFETIME_FO') : 1) * 3600));
        $cookie = new Cookie('ps', '', $cookieLifetime);
    }
    $lang = $cookie->id_lang;
    } else $lang = $_GET['iso_lang'];
    $cacheName = substr(str_replace('.','_',$_SERVER['SCRIPT_NAME']), 1) . '_' . $lang . '_'. md5($_SERVER['QUERY_STRING']);
    $cache->start($cacheName);
}


Como observamos el cache tiene un tiempo de (60*60*4) 4 horas y el nombre del mismo estará formado de la página visitada, el lenguaje y los valores enviados por $_GET.

* Paso 2: Aplicando el cache a la página principal, categorias y productos.

Este paso en realidad es muy sencillo, de incluir el archivo de cache.page.inc.php luego del archivo config.inc.php :
require(dirname(__FILE__) . '/config/config.inc.php');
require(dirname(__FILE__) . '/config/cache.page.inc.php');
Esto en los archivos:
index.php
category.php
product.php

* ¿No loguea al usuario?
Como veran en las secciones que indicamos ya se aplica cache de página; y probando la aplicación estas no cambiaran a pesar de que nos logueemos.

Una solución rápida para el caso de logueo es validar el uso de cache solo cuando no este logueado:

require(dirname(__FILE__) . '/config/config.inc.php');
global $cookie;
if (! isset($cookie)){
  $cookieLifetime = (time() + (((int) Configuration::get('PS_COOKIE_LIFETIME_FO') > 0 ? (int) Configuration::get('PS_COOKIE_LIFETIME_FO') : 1) * 3600));
  $cookie = new Cookie('ps', '', $cookieLifetime);
}
if(! $cookie->isLogged()){
   require(dirname(__FILE__) . '/config/cache.page.inc.php');
}

** Otra solución


Una solución compleja y recomendable sería (sin diferenciar el cache) mediante llamadas AJAX refrescar solo las secciones que estan relacionadas exclusivamente al Cliente (Login de usuario y Carrito de compras)
Enhanced by Zemanta

Emacs en windows: arranque rápido

En windows la carga de emacs implica una demora en windows pero se puede mejorar usando el demonio de emacs y modificar la llamada usando el...