martes, 24 de enero de 2017

Crear documentación de código de laravel con APIGEN

Esta solamente es una entreda para editar!


Api gen se descarga en:
http://www.apigen.org/

Lista de tags que se pueden usar:
https://www.phpdoc.org/docs/latest/index.html

El comando a ejecutar es:

apigen generate --source ./app --exclude=*/commands/*,*/config/*,*/database/*,*/lang/*,*/start/*,*/storage/*,*/views/*,filters.php,routes.php --destination ./public/api --no-source-code

martes, 26 de julio de 2016

Carbon no reconoce Locale

Si llegaste hasta esta entrada es porque has utilizado Carbon en algún proyecto o, como es mi caso,  utilizas Laravel que tiene a Carbon como una de sus dependencias. En cualquiera de los casos sabemos que es una librería que ayuda en gran manera al manejo de fechas al momento de programar.

Dentro de un proyecto que hemos estado trabajando nos encontramos con la necesidad de mostrar las fechas en formato más legible, por ejemplo: Martes, 26 de Julio del 2016, resultaba que en una de las computadoras del equipo (En concreto la mía) si funcionaba bien cuando escribíamos el:

setlocale(LC_TIME, 'es_SV');

$now = \Carbon\Carbon::now() ;
       

$data['now_str'] = $now->formatLocalized('%A, %d de %B del %Y');


Pero en otras resultaba en Inglés, de igual manera en el servidor principal así era, viendo un poco la documentación de Carbon vemos que utiliza la función setlocale() de php http://php.net/setlocale, la cual funciona con los idiomas que tiene instalado el sistema operativo, he ahí la razón del porqué a mi si me lo mostraba bien.


Para Linux


Esto lo he comprobado en Ubuntu y Fedora, espero que en otras distros no varíe mucho.

Indagando un poco leí que podemos listar los idiomas instalados yendo a una terminal y ejecutando:

locale -a

Que nos muestra algo parecido a:







Sino aparece el "locale" que nos interesa podemos instalarlo con:

sudo locale-gen es_SV

Luego ejecutamos los dos comandos:

sudo update-locale

y

sudo dpkg-reconfigure locales



Y listo, no necesitamos ni reiniciar los servicios, por lo menos a mi no hubo necesidad de hacerlo.


Para Windows


Con esto quedo pendiente, tengo que hacer unas pruebas aún

Carbon no reconoce un Locale

Si llegaste hasta esta entrada es porque has utilizado Carbon en algún proyecto o, como es mi caso,  utilizas Laravel que tiene a Carbon como una de sus dependencias. En cualquiera de los casos sabemos que es una librería que ayuda en gran manera al manejo de fechas al momento de programar.

Dentro de un proyecto que hemos estado trabajando nos encontramos con la necesidad de mostrar las fechas en formato más legible, por ejemplo: Martes, 26 de Julio del 2016, resultaba que en una de las computadoras del equipo (En concreto la mía) si funcionaba bien cuando escribíamos el:

setlocale(LC_TIME, 'es_SV');

$now = \Carbon\Carbon::now() ;
       
$data['now_str'] = $now->formatLocalized('%A, %d de %B del %Y');

Pero en otras resultaba en Inglés, de igual manera en el servidor principal así era, viendo un poco la documentación de Carbon vemos que utiliza la función setlocale() de php http://php.net/setlocale, la cual funciona con los idiomas que tiene instalado el sistema operativo, he ahí la razón del porqué a mi si me lo mostraba bien.


Para Linux

Esto lo he comprobado en Ubuntu y Fedora, espero que en otras distros no varíe mucho.

Indagando un poco leí que podemos listar los idiomas instalados yendo a una terminal y ejecutando:

locale -a

Que nos muestra algo parecido a:







Sino aparece el "locale" que nos interesa podemos instalarlo con:

sudo locale-gen es_SV

Y listo, no necesitamos ni reiniciar los servicios, por lo menos a mi no hubo necesidad de hacerlo.


Para Windows

Con esto quedo pendiente, tengo que hacer unas pruebas aún

miércoles, 14 de enero de 2015

[Solucionado] La obtención de la llave GPG ha fallado:[Errno 14] curl#37 - "Couldn't open file /etc/pki/rpm-gpg/RPM-GPG-KEY-rpmfusion-nonfree-fedora-19"

Cuando recien instalas cualquier version de fedora y agregar los repositorios de rpmfusion ya sean free o non free suelen dar este problema por razones que no comprendo XD, para solucionarlo es relativamente sencillo, lo malo es que casi no se encuentra información sobre ello, por lo menos no para todas las versiones, sino para versiones de Fedora especificas.

Sin más preambulo solucionemos esta vaina.

Pasos!

  1. Primero hay que agregar las key de rpmfusion, donde las encuentro?, pues en http://rpmfusion.org/keys, ahí están todas las versiones, al seleccionar cualquiera y dar click en "download" te lleva a otra pagina que paradojicamente muestra siempre todas, ahora bien, hay que descargar las keys que a nosotros nos interesan, las de nuestra version, descarguenlas, no intenten hacer el import desde la consola con la url que falla, o al menos a mi me sucedió eso.
  2. Ahora que ya están descargadas nos quedaran como RPM-GPG-KEY-rpmfusion-nonfree-fedora-19, que es mi caso claro, en la carpeta de descargas, ubicamos y copiamos su dirección, incluyendo su nombre.
  3. Ahora abrimos una terminal y escribimos:
    sudo rpm --import /home/m0rf3o/Descargas/RPM-GPG-KEY-rpmfusion-free-fedora-19
    Para las free, recuerden que a mi la primera parte es distinta de cada maquina, dependiendo de tu usuario y adonde guardaste el archivo.
  4. Ingresamos nuestra contraseña que nos la pedirá.
  5. Ahora
    sudo rpm --import /home/m0rf3o/Descargas/RPM-GPG-KEY-rpmfusion-nonfree-fedora-19
    Para las non free.
  6. Luego solo instalamos:
     su -c 'yum localinstall --nogpgcheck http://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-stable.noarch.rpm http://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-stable.noarch.rpm
  7. Ingresamos nuevamente la contraseña
  8. Actualizamos:
    sudo yum update

Ahora a disfrutar de instalar lo que gustes.

miércoles, 19 de marzo de 2014

Encontrar que fecha cae un día de una semana x en MySql

SELECT DATE_SUB( DATE_ADD( MAKEDATE( 2014, 1 ) , INTERVAL 11 WEEK ) , INTERVAL WEEKDAY( DATE_ADD( MAKEDATE( 2014, 1 ) , INTERVAL 11 WEEK ) ) -4 DAY ) AS viernes;
Donde 11 es el número de la semana, 2014 el años y 4 representa al viernes que se busca. Esta query devuelve el viernes de la semana 11, para comprenderla la veremos parte por parte: -MAKEDATE( 2014, 1) devuelve la fecha del primer día del año 2014 -DATE_ADD( MAKEDATE( 2014, 1 ) , INTERVAL 11 WEEK ) devuelve la fecha del primer día del 2014 más exactamente 11 semanas después -WEEKDAY( DATE_ADD( MAKEDATE( 2014, 1 ) , INTERVAL 11 WEEK ) ) -4 DAY devuelve el día de la semana 11 a partir del 1 de enero del 2014, la semana comenzando desde cero a 6 y a eso le resta el 4 días (notése el 4, ese representa al día viernes, si quisiéramos el martes sería 1, pues para MySql la semana comienza en 0, osea lunes). -Toda la query: retorna la resta de la fecha de 11 semanas después del 1 de enero menos los días restantes de la cuenta anterior

lunes, 4 de noviembre de 2013

Select adentro de un trigger en MySql

A la hora de hacer un trigger en ocaciones nos es necesario obtener información de otras tablas ademas de la que está siendo tratada por el trigger, en la mayoría de los manuales que encontré hablan solamente de un registro, en este caso trataremos para más de un registro.

En nuestro caso hipotético crearemos 3 tablas, una donde estarán los vehículos, una donde tendremos los tipos de mantenimiento que se puedan dar y otra donde estarán el listado de los vehículos con los mantenimientos, es decir, será una tabla transaccional donde relacionaremos cada vehículo con cada mantenimiento.

El trigger insertará registros por cada vehículo ingresado en la primer tabla mencionada, obteniendo los id de cada tipo de mantenimiento en la segunda tabla y almacenando un registro por cada tipo de mantenimiento para el vehículo recién ingresado.

Primero crearemos la base de datos:

CREATE DATABASE `vehiculos_manttos`;



Tendremos 3 tablas, una llamada vehiculos con un id y un nombre, para simplificar las cosas:

CREATE TABLE `vehiculos` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `nombre` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ;

La segunda tabla la llamaremos mantenimientos_tipo con un id y un nombre:

CREATE TABLE `mantenimientos_tipo` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `mantenimiento_tipocol` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`id`)
);

La tercera tabla será la transaccional, donde almacenaremos los mantenimientos, se llamará mantenimientos y tendrá un id (Para identificar cada registro), un id_vehiculo (Relacionada con la tabla vehiculos), y un id_tipo (Que estará relacionada con la tabla mantenimientos_tipo).

CREATE TABLE `mantenimientos` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `id_vehiculo` int(11) DEFAULT NULL,
  `id_tipo` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `fk_mantenimientos_1_idx` (`id_vehiculo`),
  KEY `fk_mantenimientos_2_idx` (`id_tipo`),
  CONSTRAINT `fk_mantenimientos_1` FOREIGN KEY (`id_vehiculo`) REFERENCES `vehiculos` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `fk_mantenimientos_2` FOREIGN KEY (`id_tipo`) REFERENCES `mantenimientos_tipo` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
);

Ingresemos un par de datos de prueba para tipo de mantenimientos:

INSERT INTO `mantenimientos_tipo` (`id`, `mantenimiento_tipocol`) VALUES (null, 'Cambio de aceite');

INSERT INTO `mantenimientos_tipo` (`id`, `mantenimiento_tipocol`) VALUES (null, 'Recarga de aire');

Ok, las tablas para nuestro ejemplo están creadas y tenemos un par de datos de prueba, ahora crearemos el trigger:

delimiter $$

CREATE TRIGGER `vehiculos_manttos`.`futures_manttos` --Nombre del trigger
AFTER INSERT ON `vehiculos_manttos`.`vehiculos` --Despues que inserte en la tabla vehiculos
FOR EACH ROW --Por cada registro insertado que haga...
BEGIN
    --Declare variables necesarias
    DECLARE done INT DEFAULT FALSE; --Esta variable controlará el flujo del select, para saber si ya se llegó al último registro
    DECLARE c1 INT;
    DECLARE cur CURSOR FOR SELECT id FROM mantenimientos_tipo; --Se crea un cursos para los registros que devolverá la query 'select id from mantenimientos_tipo;'
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; --Se prepara la bandera como cierta
    OPEN cur; --Entramos en el cursor que tiene los registros
        ins_loop: LOOP
            FETCH cur INTO c1; --Guardamos el registro del id devuelto en c1
            IF done THEN
                LEAVE ins_loop; --Si ya no hay registro entonces que salga del loop
            END IF;
            INSERT INTO mantenimientos VALUES (null,NEW.id,c1); --Insertamos un registro por cada registro de mantenimientos_tipo en mantenimientos con el nuevo id que se creó en el insert que dispara el trigger
        END LOOP;
    CLOSE cur;
END
$$


Despues de unas pruebas te darás cuenta que es menos complicado de lo que parece, haz una prueba insertando un registro en behiculos y verás que se crearán 2 registro en mantenimientos, uno por cada registro de mantenimientos_tipo.

Suerte!

miércoles, 30 de octubre de 2013

Montar usb o particiones en Fedora 19 sin que pida contraseña

Fedora es un poco mas quisquillosa con eso de la seguridad, por eso que cada vez que insertamos una usb o que queremos montar una partición del disco duro pide el password, pues podemos decirle que no lo haga de la siguiente manera:

1. Abrimos una consola y abrimos con el editor de nuestra preferencia /usr/share/polkit-1/actions/org.freedesktop.udisks2.policy

2. Buscamos [En nano es Ctrl+w] filesystem-mount-system y la linea que a la que nos lleba debe contener esto: <action id="org.freedesktop.udisks2.filesystem-mount-system">

3. Luego bajamos, unas lineas (No importa cuantas porque eso dependerá de la cantidad de idiomas que tenga instalado tu sistema) hasta encontrar las siguientes viñetas
<allow_active>auth_admin_keep</allow_active>, es importante que bajes con el cursor y no las busques porque podrías encontrar otra linea que no es la en cuestion, lo unico que tienes que hacer es cambiar auth_admin_keep por yes y  te quedará mas o menos así:



4. Luego guarda el archivo [En nano es Ctrl+O] y listo, conecta una usb para que corrobores que todo ha funcionado, no necesitas reiniciar, sólo cierra el navegador de archivos por si las dudas.

martes, 22 de octubre de 2013

Configurando SELinux para Apache y Mysql

El detalle cuando instalamos un Linux con SELinux y nunca es primera vez que lo usamos es que no sabemos configurarlo, yo me topé con que monté mi servidor apache y mysql pero no funcionaban, me aparechia algo como:

Warning: mysqli_connect(): (HY000/2002): Permission denied in /var/www/html/*/conex.php on line 26
No se puede conectar con el servidor
Warning: mysqli_close() expects parameter 1 to be mysqli, boolean given in /var/www/html/*/conex.php on line 39

Porque no tenia los permisos para conectar con el socket, el detalle se arregla facilmente, solamente tienes que dar permisos al httpd que conecte, y a la conexión entre httpd con la base de datos, de la siguiente manera:

Abres una consola y como super usuario ingresas: sudo setsebool -P httpd_can_network_connect 1


Y luego escribes sudo setsebool -P httpd_can_network_connect_db 1


No te preocupes si tarda un poco entre cada comando, si todo sale bien vuelves a intentar abrir la página y todo bien.

Estos permisos booleanos son mas extensos, si quieres hechar un ojo a la cantidad de opciones puedes teclear en la consola: /usr/sbin/getsebool -a y veras todas las políticas de SELinux y su estados.

Suerte!

martes, 4 de junio de 2013

Desarrollando aplicaciones seguras en PHP

Tener una aplicación en la web es una bandera que llama a muchos curiosos a probar si tienen las habilidades necesarias para poder “volcar” nuestro código, así que es algo que siempre deberíamos de tener en cuenta, recordemos que no hay aplicaciones 100% seguras, porque el ser excesivamente seguras las hace débiles nuevamente, ya hay ataques que se aprovechan de la misma seguridad de las aplicaciones, sobrecargándolas de trabajo, pero siempre hay que encontrar un equilibrio entre seguridad y eficiencia/usabilidad.

Php es un lenguaje potente, y el interprete puede ejecutar comandos en el sistema del servidor web o puede abrir conexiones de red, lo que hace al lenguaje inseguro si se omiten ciertas reglas de seguridad, tanto en el servido como en la aplicación o página web que se ejecute. En éste caso hablaremos sobre la el lado del desarrollador, la persona encargada de preparar la aplicación o la página web.

Sobre el sistema de archivos:


PHP ofrece la posibilidad de abrir, escribir, eliminar, mover, copiar y hacer una infinidad de acciones con los archivos del servidor, una parte de la responsabilidad de estos permisos recae en el administrador del servidor (No siempre el desarrollador) y la otra sobre los hombros del desarrollador.
Imaginemos un script capas de eliminar un archivo cualquiera que solo reciba por parámetro el nombre, el desarrollador tendería a pensar que con recibir el nombre es suficiente para eliminarlo;


Este script esta esperando un nombre tipo “archivo.txt”, pero que pasaría si en lugar de eso se ingresara un nombre “../index.php”?


Como arreglar esto?. Hay que estar seguros que el nombre enviados desde el formulario no contiene ninguna dirección o parámetros de dirección, como lo son “..” y “/”, una forma rápida sería:



Otro detalle a tener en cuenta es que PHP usa funciones de C para administrar archivos lo cual nos lleva a la posibilidad de poder utilizar los Bytes nulos (\0), que son la forma en como c da como finalizada un string, aquí un ejemplo de esta vulnerabilidad:



Por consiguiente cuando se utilizan funciones que manipulan archivos hay que validarlos correctamente, he aquí el script mejorado:


Sobre las Bases de Datos:


Hoy en día difícilmente construyamos una aplicación sin tener una base de datos por lo cual considero importante agregar éste apartado.

Si la base de datos corre sobre diferentes servidores la mejor forma de comunicación es usando ssh para encriptar la comunicación entre la base de datos y el servidor web.

Al conectarse con la base de datos hay que tomar en cuenta los permisos que tiene el usuario con que se conecta, si el usuario es el dueño de la base de datos (Por lo general es el que ejecuta la creación del esquema) tiene control total sobre la base de datos, pudiendo eliminar tablas completas e incluso la base de datos a su antojo, es mejor tener un usuario que solo pueda hacer los INSERT, DELETE y UPDATE sobre las tablas, así dificultas más el trabajo del atacante.

Almacenar los datos mas importantes encriptados, como son las contraseñas en la base de datos, si la base de datos cae en malas manos no queremos que ellos sepan las contraseñas de nuestros clientes por supuesto, esta es una buena forma de hacerlo, no recomiendo nunca usar un mecanismo genérico para la encriptación, por ejemplo md5 y sha1, que hay varias paginas que las desencriptan en un par de segundos como http://md5.rednoize.com/, prefiero usar crypt() que permite usar una semilla o si prefieren pueden usar algo mas elaborado como http://www.emm-gfx.net/2008/11/encriptar-y-desencriptar-cadena-php/.

Limpiar las variables que vengan del usuario hacia la base de datos, para evitar inyecciones SQL, en muchas ocasiones solemos dejar el código en espera de variables exactas, por ejemplo números si estamos en una paginado, veamos a continuación:


Si en este caso la variable $_GET['page'] fuera
1; delete from mi_tabla where id=12;

Eliminaría el registro de esa tabla donde el id fuera 12, claro supondría que el usuario supiera el nombre de la tabla, el del campo id y que acertara a una id que existiera pero con un poco de tiempo lo lograrías, igual puede ejecutar mas comandos peligrosos incluso llegar a ejecutar comandos a nivel de servidor.
Para evitar este tipo de detalles es necesario verificar las variables que vienen del usuario, verificando el tipo de dato que se espera, en el caso anterior era un dígito, podría utilizarse la función is_numeric() para estar seguro, dejando el script de la siguiente forma:


En el caso que estemos hablando de una string al momento de recibirla hay que pasarla por el filtro del driver de conexión que estemos usando para evitar que las comillas corten nuestra query:


Nota: Si usas mysqli en lugar de mysql sería $var = mysqli::escape_string($_GET['var']);


Sobre el reporte de errores:


Muchas veces mientras desarrollamos necesitamos saber que sucede con la aplicación para poder reparar un error, por lo cual utilizamos los errores para guiarnos, en desarrollo esta bien hacer eso, pero en producción es una debilidad mostrar errores al usuario pues puede recolectar información valiosa sobre nuestro código que luego utilizaría en nuestra contra.
En ocasiones se utiliza cosas como die(mysql_error()) para saber que pasó en una query a la base de datos que no funcionó como lo esperábamos, al momento de sacar esa aplicación a producción debemos de deshacernos de todas esas muestras de errores mostrando solamente errores personalizados como die('Ocurrió un error interno del servidor, estamos trabajando en eso, disculpe').
Igual el interprete de PHP suele mostrar warnings y errores, por lo cuál deberíamos usar, si el servidor lo permite:



Sobre XSS (Cross-Site Scripting):


Este ataque consiste en ejecutar código html o javascript en nuestra página, eso sucede cuando nosotros imprimimos una variable que contiene html peligroso que el navegador interpreta, por ejemplo:


Sí $_GET['msj'] llevara “<script type='text/javascript'>alert('hola')</script>” cuando se imprimiera aparecería una ventana en el navegador del cliente diciendo hola, parece bastante débil, pero con ese tipo de ataques pueden llegar a cambiar la apariencia de nuestra página o hasta robar las cookies de nuestros usuarios, esa variable también pudo haber sido ingresada a la base de datos y al salir seguiría teniendo el mismo poder, para evitar este tipo de ataques habría que limpiar la variable como aparece a continuación:


htmlspecialchars() convierte los caracteres peligrosos en sus valores html evitando que se puedan ejecutar, si el valor se fuera a ingresar a la base de datos sería aquí:


Claro, recordemos que ahí también tendríamos que ponerle el filtro de inyección sql para estar completamente seguros, pero para el ejemplo es válido.


Son unos cuantos tips de todos los que tenemos que tener en cuenta a la hora de programar, porque hay una gran cantidad de ataques mas, pero son los principales, espero que les sea de ayuda.

domingo, 2 de junio de 2013

mPushState, una solución para pushstate con soporte cross browser


En ocasiones estamos trabajando en desarrollo web, los nuevos estándares están bastante altos, se requiere cada vez aplicaciones mas rápidas, para lo cual se recurre a Ajax), pero el detalle es que el cliente navega por nuestra página cargando distinto contenido asíncrono, y cuando éste quiere compartir lo que esta viendo con otra persona se encuentra con que el link enviado no guía a la otra persona hasta donde él estaba navegando, o si quiere guardarlo en marcador sucede lo mismo, tiene que buscar nuevamente el punto en que se quedó, navegando por segunda, tercera o cuantas veces requiera nuestra página para encontrar el contenido deceado, para ello existe “pushstate”, una funcionalidad para poder modificar la url del cliente mientras él navega asíncrono por nuestra web.


Actualmente HTML5 soporta “pushstate” para manejar estas variables de navegación sin tener que recargar la ventana, pero actualmente mas del 30% de las personas utilizan Internet Explorer 8 o inferior que no soportan HTML5 y por consiguiente pushstate.


La solución, mPushState v1.2: una librería que nos permite agregar, quitar y editar variables de la url sin recargar la ventana del navegador de forma fácil y rápida, con soporte para los ie8 e inferiores a travez del hash, así como para los navegadores que ya trabajan con HTML5.


La librería se encuentra en https://bitbucket.org/m0rf3o/mpushstate, desarrollada por tu servidor y liberada como código libre.


Es fácil de usar, solamente se instancia un objeto mPushState y éste se encarga de todo, obtiene las variables de la url, las edita, elimina o agrega mas si lo deceas.


Por ejemplo:

var pushstate = new mPushState();


//Obtiene una variable si existe
var valor= pushstate.getVar('nombreDeVariable');


//Elimina la variable anterior
pushstate.delVar('nombreDeVariable');


//Agrega una variable llamada 'nuevaVariable' con el contenido 'valor'
pushstate.adVar('nuevaVariable', 'valor');


//Cambia el contenido de la variable 'nuevaVariable'
pushstate.adVar('nuevaVariable', 'valorNuevo');



Es de lo más sencillo y práctico, espero que te sea de útilidad.