Error 500 con Nginx+Chroot+PHP5-FPM+PhpMyadmin

Despues de hacer la instalación de Nginx y PHP5-FPM con Chroot (Jail) e instalar MySQL PhpMyAdmin la página me daba un error 500.

Investigando veo que el problema esta en la siguiente línea del archivo library/common.inc.php de PhpMyAdmin.

date_default_timezone_set(@date_default_timezone_get());

El problema está en que la función date_default_timezone_get() y todo se debe a que no se tienen los archivos necesarios para buscar la timezone del servidor, como lo muestra el log de nginx

[error] 12058#0: *13 FastCGI sent in stderr: “PHP message: PHP Fatal error: date_default_timezone_get(): Timezone database is corrupt – this should *never* happen! in /var/www/phpmyadmin/libraries/common.inc.php on line 276” while reading response header from upstream, client: 111.111.111.111, server: miservidor.com, request: “GET /phpmyadmin/ HTTP/1.1”, upstream: “fastcgi://127.0.0.1:9000”, host: “miservidor.com”

La solución es instalar la timezonedb con PHP-PEAR ( pecl ), procedemos con el siguiente código:

apt-get install php-pear php5-dev
pecl install timezonedb
echo ‘extension=timezonedb.so’> /etc/php5/mods-available/timezonedb.ini
ln -sf /etc/php5/mods-available/timezonedb.ini /etc/php5/fpm/conf.d/30-timezonedb.ini
service php5-fpm restart

Y listo!!.. ya debe de funcionar correctamente la página de PhpMyAdmin

MySQL: Como sumar un campo tipo Time

Si tienen un campo tipo Time (formato: 00:00:00) en su base de datos MySQL, y quieren hacer una suma con la tipica consulta:

SELECT SUM(campo_hora) FROM tabla

Verán que no regresa el resultado deseado…, eso es por el tipo de dato, entonces lo que se tiene que hacer es convertir a tipo numérico (segundos), sumar y después volver a convertir a tipo time., todo tan simple como usar una instrucción como sigue:

SELECT SEC_TO_TIME( SUM( TIME_TO_SEC( campo_hora ) ) ) FROM tabla

Y listo!!.., asunto arreglado.

MySQL y Visual Basic: El proveedor de datos u otro servicio devolvió un estado E_FAIL

Estaba revisando un sistema creado en visual basic 6 y a veces me marcaba el siguiente error:

El proveedor de datos u otro servicio devolvió un estado E_FAIL.

Viendo la consulta SQL me doy cuenta que la constante es que siempre había por lo menos 1 fecha con formato 0000-00-00 o mejor dicho NULL.

Y revisando la estructura de las tablas, el campo estaba definidio como datetime o date pero decía NOT NULL, la solución es poner los campos fecha a NULL, así ya no arrojara el ODBC el error de E_FAIL.

PHP: Convertir fecha de Twitter del formato RFC 2822 a uno de MySQL

Pues he estado probando la API de twitter y el campo created_at tiene la fecha en formato RFC 2822, osea en español algo así: Sun, 14 Aug 2005 16:13:03 +0000, el problema esta al guardar la información en la base de datos MySQL, ya que solo acepta formato “YYYY-MM-DD HH:MM:SS” entonces, ocupamos modificar esta información.

la solución esta en utilizar 2 funciones de PHP: strtotime y date

strtotime lo que hace es convertir una descripción de fecha/hora textual en Inglés a una fecha Unix y con comando date le damos el formato que deseemos.

Teniendo algo así.

date(‘Y-m-d H:i:s’,strtotime($json->created_at))

Codeigniter: Modificar LIMIT para el driver MSSQL

Después de encontrar la solución para que funcione el LIMIT de MySQL en Microsoft SQL Server ahora sigue el turno de modificar el código de Codeigniter para así tener algo transparente para nuestras consultas SQL.

Lo primero que se debe de hacer es modificar la librería de carga del Codeigniter, ( $this->load-> )
Vamos a trabajar en la carpeta: /system/application/libraries/ y creamos un archivo llamado: MY_Loader.php con el siguiente código:

< ?php class MY_Loader extends CI_Loader{ / * Constructor, calls parent constructor. */ function MY_Loader() { parent::CI_Loader(); } / * Database Loader * * @access public * @param string the DB credentials * @param bool whether to return the DB object * @param bool whether to enable active record (this allows us to override the config setting) * @return object */ function database($params = '', $return = FALSE, $active_record = FALSE) { // Do we even need to load the database class? if (class_exists('CI_DB') AND $return == FALSE AND $active_record == FALSE) { return FALSE; } require_once(BASEPATH.'database/DB'.EXT); // Load the DB class $db =& DB($params, $active_record); $my_driver = config_item('subclass_prefix').'DB_'.$db->dbdriver.’_driver’;
$my_driver_file = APPPATH.’libraries/’.$my_driver.EXT;

if (file_exists($my_driver_file))
{
require_once($my_driver_file);
$db =& new $my_driver(get_object_vars($db));
}

if ($return === TRUE)
{
return $db;
}
// Grab the super object
$CI =& get_instance();

// Initialize the db variable. Needed to prevent
// reference errors with some configurations
$CI->db = ”;
$CI->db = $db;
// Assign the DB object to any existing models
$this->_ci_assign_to_models();
}

}

La idea de este archivo es extender la funcionalidad de carga de los drivers para la base de datos, despues en la misma carpeta de libraries creamos un archivo llamado: MY_DB_mssql_driver.php ya que estamos usando el driver mssql para nuestra conexión SQL Server

< ?php class MY_DB_mssql_driver extends CI_DB_mssql_driver { function __construct($params){ parent::__construct($params); log_message('debug', 'Extended DB driver class instantiated!'); } function _limit($sql, $limit, $offset){ if($offset == 0){ return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$limit.' ', $sql); }else{ $OrderBy = "ORDER BY "; if (count($this->ar_orderby) > 0){
$OrderBy .= implode(‘, ‘, $this->ar_orderby);

if ($this->ar_order !== FALSE)
{
$OrderBy .= ($this->ar_order == ‘desc’) ? ‘ DESC’ : ‘ ASC’;
}
}else{
$OrderBy .= “(SELECT 1)”;
}

$sql = preg_replace(‘/(\\’. $OrderBy .’\n?)/i’,”, $sql);
$sql = preg_replace(‘/(^\SELECT (DISTINCT)?)/i’,’\\1 ROW_NUMBER() OVER (‘.$OrderBy.’) AS rownum, ‘, $sql);
return “SELECT * \nFROM (\n” . $sql . “) AS A \nWHERE A.rownum BETWEEN (” .($offset + 1) . “) AND (“.($offset + $limit).”)”;
}
}

Y listo! con esto nuestra consulta LIMIT será transparente y se usará como siempre: $this->db->limit(2,10);

Aca les dejo las fuentes de esta información:

No existe offset (antes decia: LIMIT) en MS SQL Server

Así como suena el titulo, en Microsoft SQL Server no existe la función limit , para implementarla tienes que usar algunos trucos con subconsultas., algo tan sencillo en MySQL como: SELECT * FROM miTabla LIMIT 2,10 en SQL Server se vuelve una calamidad.

Buscando en Internet, encontré en Foros del Web una explicación de como hacer funcionar, se tiene que poner una subconsulta SQL con algo que diga: ROW_NUMBER() OVER (ORDER BY campo) as NumRows y despues se hace un WHERE con su respectivo Between para poner el limite: WHERE NumRows BETWEEN 2 AND 10

Aca un ejemplo más elaborado:

SELECT *
FROM (
SELECT ROW_NUMBER() OVER (ORDER BY mi_Campo1) AS NumRows, *
FROM mi_Tabla
) as AS_NumRows
WHERE AS_NumRows.NumRows BETWEEN 10 AND 20

Si se requiere algún WHERE en nuestra consulta SQL se debe de meter en la subquery, en caso que no tengamos ningun campo a ordenar se cambia lo que tiene ROW_NUMBER, ORDER BY por la siguiente información:

ROW_NUMBER() OVER (ORDER BY (SELECT 1))

Y listo!.., no he probado el rendimiento pero pues aquí una solución extra.

MySQL: Cannot add or update a child row: a foreign key constraint fails

Si al hacer un insert les marca el siguiente error en MySQL:

Cannot add or update a child row: a foreign key constraint fails

La solución es cambiar el motor de almacenamiento MyISAM a InnoDB de la tabla que tiene la referencia, una vez realizado este cambio ya debe de funcionar el insert (claro, siempre y cuando exista el valor del ID que hace referencia).

Aca pueden ver más información sobre las relaciones de tablas en MySQL

Resetear la contraseña del usuario Root en MySql

Si por alguna razón se les olvido la contraseña del usuario ROOT en MySQL existe una opción sencilla para cambiarla, el unico requisito es claro tener privilegios de root en su distribución de linux favorita, ya sea ubuntu, debian, centos, etc… en estos ejemplos usaremos Ubuntu (ó Debian debe de jalar igual)

El paso 1 es detener el servidor MySQL,

/etc/init.d/mysql stop

Despues iniciar MySQL saltando la autentificación y deshabilitando la escucha de la red, digo por aquello de los hackers, con el siguiente comando tambien habilitamos el servicio en background (con el amperson se indica eso)

mysqld –skip-grant-tables –skip-networking &

Ahora si, nos conectamos al servidor de MySQL, especificamente la tabla mysql

mysql mysql -u root

Y pues a ejecutar el siguiente comando:

UPDATE user SET password=PASSWORD(‘mi_nueva_clave’) WHERE user=”root”;
quit;

Y listo!, matamos el proceso y reiniciamos mysql normalmente., para ver el proceso cuando lo lanzamos en background nos aparecio un número del proceso.

kill -9 NUMERO

Y listo!, a iniciar el servicio (quizas con el restart mata el proceso, pero mejor el kill para estar seguros):

/etc/init.d/mysql restart

A disfrutar del MySQL y claro! no olvidar la clave! jeje.

MySQL: Importar y Exportar SQL

Si alguna vez tuvieron la necesidad de importar o exportar su base de datos de MySQL sin usar PHPMyAdmin o algún otro manejador de la base de datos, y pues deben de utilizar la linea de comandos, aquí pongo el mini-howto.

Para exportar una base de datos:
#Para ver la base de datos a exportar
mysql -u root -p
mysql > show database;

#Y fuera del shell del mysql ejecutar el comando mysqldump con el nombre de la base de datos
mysqldump -u usuario -p nombre_base_de_datos > archivo.sql

Para importar una base de datos se usa el siguiente comando:
#Para crear la base de datos por si no viene el comando en el archivo SQL
mysql -u root -p
mysql> create database nombre_base_de_datos;

#Ahora fuera del shell del mysql se ejecuta el comando inverso al mysqldump

mysql -u root -p nombre_base_de_datos < ruta_base_de_datos.sql