junio 2018

Leer un archivo ini o .env con PHP

Introducción

Conforme crecen nuestras aplicaciones en PHP, a veces necesitamos manejar muchas credenciales y configuraciones. Esto lo podemos hacer al leer un archivo ini en PHP.

Veamos el caso del framework Laravel, que guarda sus variables del entorno en un archivo llamado .env. No sé cómo sea parseado, pero el principio es el mismo.

Como dijimos al inicio del post, hoy veremos cómo parsear un archivo de configuración ini. Es un formato que Windows introdujo y quiere decir algo como Windows Initialization file según la Wikipedia.

Ejemplo de archivo INI

Un ejemplo (sacado de Wikipedia) podría verse así:

[Red]
; Poner UsarProxy=1 si no hay cortafuegos
UsarProxy=1
Proxy=192.168.0.1

[Preferencias]
PaginaInicio=https://wikipedia.org
Maximizar=1

Hay algunas cosas importantes:

  • Secciones: son representadas por un título encerrado en corchetes []
  • Valores: los valores que tienen la forma nombre=valor o nombre = valor o nombre = “valor”
  • Comentarios: inician con ;
  • Líneas en blanco: podemos dejar líneas en blanco, serán ignoradas al igual que los comentarios

Ahora sí vamos a interpretar un archivo ini con PHP.

Leer un archivo ini utilizando parse_ini_file

El lenguaje proporciona una función que recibe 3 argumentos: la ruta del archivo, un booleano indicando si procesará las secciones y un entero indicando el modo de lectura.

Para leer un archivo ini en PHP vamos a concentrarnos en los dos primeros argumentos, pero aquí dejo la documentación completa: PHP: parse_ini_file – Manual

Leer procesando secciones

Podemos leerlo procesando las secciones. Hablar es de mal gusto, así que vamos al código. Recordemos el archivo ini de arriba.

Suponiendo que el nombre del fichero es configuracion.ini lo leeríamos así:

<?php
$archivo = __DIR__ . "/configuracion.ini";

$contenido = parse_ini_file($archivo, true);

echo var_export($contenido, true);

Fácil y sencillo. La salida al leer un archivo ini sería esta:

array (
  'Red' =>
  array (
    'UsarProxy' => '1',
    'Proxy' => '192.168.0.1',
  ),
  'Preferencias' =>
  array (
    'PaginaInicio' => 'https://wikipedia.org',
    'Maximizar' => '1',
  ),
);

Como vemos, es un array multidimensional. Cada clave es una sección, que en este caso es Red y Preferencias. Y cada clave tiene un array con las claves indicando las configuraciones.

Por lo que si yo quisiera extraer la página de inicio, haría esto:

<?php
$archivo = __DIR__ . "/configuracion.ini";

$contenido = parse_ini_file($archivo, true);
$pagina_inicio = $contenido["Preferencias"]["PaginaInicio"];
echo "La página de inicio es: $pagina_inicio";

Lo que hay que hacer es simplemente acceder a los valores de nuestro arreglo.

Leer sin procesar secciones

Ahora supongamos que no queremos un arreglo bidimensional, sino uno sólo con claves y valores. Para ello, ignoraríamos las secciones.

Si leemos el mismo archivo con el código de abajo(notar que el segundo argumento de parse_ini_file es false)…

<?php
$archivo = __DIR__ . "/configuracion.ini";

$contenido = parse_ini_file($archivo, false);
echo var_export($contenido, true);

El resultado sería este:

array (
  'UsarProxy' => '1',
  'Proxy' => '192.168.0.1',
  'PaginaInicio' => 'https://wikipedia.org',
  'Maximizar' => '1',
)

Como vemos es un arreglo de una dimensión. Y la función puso todos los valores en él. Si queremos extraer la página de inicio haríamos esto:

<?php
$archivo = __DIR__ . "/configuracion.ini";

$contenido = parse_ini_file($archivo, false);
$pagina_inicio = $contenido["PaginaInicio"];
echo "La página de inicio es $pagina_inicio";

Nota: si encuentra claves repetidas, PHP tomará el último valor que encuentre.

Usos

En mi caso utilizo uno de estos archivos en una app para guardar mis credenciales de acceso a las bases de datos. Se ve algo así:

; <?php exit; ?>
; El comentario de arriba es para que, si el archivo es visto
; desde el navegador, se salga inmediatamente del script, ocultando
; la información que aquí existe

; En cambio, cuando es tratado como un archivo .ini, las
; líneas que comienzan con un ; son ignoradas


; Un archivo de configuración
; que guarda todas las credenciales
; para cada cosa

; Las líneas en blanco y aquellas que comienzan
; con un punto y coma (;) son ignoradas


USUARIO_MYSQL = "woopsie"
PASS_MYSQL = ""
NOMBRE_BD_MYSQL = "bla"
HOST_MYSQL = "localhost"

Sigue leyendo para saber algunas cosas sobre el primer comentario del archivo y la seguridad

Seguridad

Si exponemos este fichero al público (es decir, que sea accesible desde el navegador) recomiendo poner el siguiente comentario al inicio del archivo:

; <?php exit; ?>

Y guardar nuestro archivo con extensión php. Cuando sea interpretado como PHP, sólo imprimirá el ; pero inmediatamente se detendrá la ejecución con exit.

En cambio, cuando sea leído como un archivo INI, el comentario que inicia con ; será ignorado.

Habilitar archivos htaccess en Apache: configuración de servidor

Introducción

Por defecto, el servidor web Apache no permite la sobrescritura de configuraciones. Es decir, ignorará todos los archivos .htaccess que pongamos en nuestros directorios. Veremos hoy cómo habilitar archivos htaccess en Apache y de esta manera poder configurar directorios por separado, sacrificando un poco el rendimiento.

Leer archivos .htaccess

Si queremos que nuestros archivos sean leídos (aunque esto supone una carga más a nuestro servidor) debemos cambiar algunas cosas del fichero apache2.conf.

Normalmente está ubicado en /etc/apache2/apache2.conf y para editarlo usamos:

sudo nano /etc/apache2/apache2.conf

Dentro de nano, podemos buscar con Ctrl + W

Hay un fragmento que dice algo así:

<Directory /var/www/>
AllowOverride None
... aquí más cosas
</Directory>

Son las reglas del directorio /var/www. Vamos a cambiar la línea que dice AllowOverride None por AllowOverride All

De manera que quede así:

<Directory /var/www/>
AllowOverride All
... aquí más cosas
</Directory>

Y guardamos con Ctrl + O. Luego reiniciamos nuestro servidor con:

sudo service apache2 restart

Con lo que ya habríamos habilitado la sobrescritura o el override de configuraciones. Cabe mencionar que esto funciona en servidores en donde tenemos el acceso completo, no aquellos de hosting compartido.

Manejador de sesiones propio en PHP y MySQL

Introducción

Vamos a ver hoy cómo implementar un manejador de sesiones en PHP hecho por nosotros mismos para poder entender a fondo cómo funcionan.

Como todos sabemos, PHP provee el uso de sesiones cuya persistencia es lograda a través de archivos en el sistema.

Es decir, guarda y lee los datos de las sesiones en archivos (imaginemos que lo hace en ficheros txt para darnos una pequeña idea).

Esto está bien si no usaremos las sesiones en múltiples peticiones AJAX, en donde puede desatarse una lectura concurrente del archivo, lo que ocasionará bloqueos.

Debido a que PHP bloquea el fichero cuando se está leyendo, si se desea abrir el mismo, se generará un error. Por ello es que hoy veremos cómo implementar nuestro propio manejador de sesiones.

Será implementado en MySQL utilizando PDO. Vamos allá.

Continue reading…

Mostrar espacio disponible en Ubuntu desde terminal

Introducción

A veces necesitamos mostrar el espacio libre de nuestro disco duro utilizando la terminal o consola.

Veamos cómo hacerlo sobre Ubuntu, aunque supongo que debería funcionar para cualquier distribución de Linux.

Esto es sumamente útil cuando no tenemos interfaz gráfica y sólo tenemos acceso al servidor a través de SSH.

Mostrar espacio disponible

Ejecutamos este comando:

df -h --total

Lo que hace es que ejecuta al comando df con el argumento h y total.

El argumento h es para mostrar los valores en una forma entendible para los humanos.

La opción total es para que al final de la tabla muestre los totales, que es lo que nos importa si queremos una visión general.

Aquí un ejemplo de la salida:

En la penúltima fila tenemos los totales, y al final un porcentaje, lo que quiere decir que estamos usando el 12 por ciento de nuestro disco duro.

Java: remover parte de una cadena

Introducción

Codificando y decodificando algunas imágenes en base64 en Java me topé con el problema de que tenía que remover parte de una cadena. Por ejemplo, si tenemos esta cadena:

Hola, mundo. Programando en Java

¿Cómo podemos quitar la parte que dice “Programando en Java”?

Remover parte de una cadena o String en Java

Para ello utilizaremos un pequeño truco. Ya que no existe el método “eliminar” en las cadenas, podemos en lugar de ello remplazar por nada o por una cadena vacía. Es decir, buscamos todas las ocurrencias de una cadena y las remplazamos por “”, lo que automáticamente eliminará el texto.

Veamos cómo funciona el remplazo. Vamos a remplazar “Java” por “Go”:

class Main {
  public static void main(String[] args) {
    String cadena = "Java es un bonito lenguaje de programación";
    cadena = cadena.replace("Java", "Go");
    System.out.println(cadena); // Imprime Go es un bonito lenguaje de programación
  }
}

Al ejecutarlo, se imprime lo predicho. He aquí el resultado.

Sabiendo eso, ahora sí vamos a eliminar parte de una cadena.

class Main {
  public static void main(String[] args) {
    String cadena = "Hola, mundo. Programando en Java";
    cadena = cadena.replace("Programando en Java", ""); // Lo remplazamos por "", es decir, nada
    System.out.println(cadena); // Imprime Hola, mundo.
  }
}

Aquí los resultados.

Conclusión

Como vemos, utilizamos el método ya existente llamado replace. Cabe mencionar que remplaza todas las ocurrencias. Es decir, si remplazamos las letras “o” por “A” en la siguiente cadena:

Hola, mundo

Obtendremos esto:

HAla, mundA

Generar un token en PHP criptográficamente seguro

Introducción

A veces necesitamos generar un token en PHP o una cadena aleatoria. Por ejemplo, es muy común que cuando queremos restablecer nuestra contraseña se nos mande un mensaje al correo electrónico que teníamos registrado.

El mensaje probablemente tendrá un link como:

sitio.com/restablecer-pass?token=123

En donde 123 es el token. Hoy veremos cómo generar un token de esos pero sin depender del tiempo, haciéndolo criptográficamente seguro.

Ya que, como sabemos, si generamos un token aleatorio la mayoría de veces se basa en el tiempo Unix, cosa que puede ser (con cierta dificultad pero no por ello imposible) adivinada.

En este caso vamos a generar un token criptográficamente seguro, que de igual manera podríamos usar como contraseña, clave de cifrado, entre otros. Desde los usos más simples hasta los más complejos, y todo ello con la seguridad que se merece.

Esto funciona tanto para PHP 5 como para la versión 7.

Generar un  token en PHP de forma que este sea seguro

Vamos a ver cómo generar un token en PHP, que no es más que un conjunto de caracteres que no deben ser adivinados de ninguna manera (excepto por fuerza bruta, pero eso es otra historia). Hay 2 versiones de este script, la primera para PHP 5  y la segunda para PHP 7.

Esto es porque PHP 7 incorpora nuevas funciones que no están presentes en las otras versiones, por lo que debemos buscar alternativas.

En PHP 5

Si usamos PHP en su versión 5 (aunque deberíamos actualizarnos) esto generará un token seguro:

Dividimos la longitud entre 2, ya que al representar cada byte en formato hexadecimal estos se convierten en 2 dígitos.

Por ejemplo, “Hello” en hexadecimal es 48656c6c6f.

Y para llamarla la llamamos con un argumento: la longitud. Es decir, cuántos caracteres queremos o la longitud esperada de la cadena.

Ejemplos:

Es importante notar que cuando pasamos 7 devuelve en realidad una cadena de longitud 6, así que mejor pasamos números pares y mayores a 4.

En PHP 7

Modificaríamos la función y llamaríamos a random_bytes en lugar de openssl_random_pseudo_bytes. Queda así:

Ejemplos

Podemos llamar a la función y devolverá una cadena aleatoria, así:

Justo como se ve en la siguiente imagen:

Demostración de cómo generar un token en PHP que sea seguro criptográficamente

Demostración de cómo generar un token en PHP que sea seguro criptográficamente

Python y Codewars: baches en el camino

Introducción

Hay un ejercicio que aunque no es tan difícil sí que es entretenido. Se trata de contar los baches en un camino y diagnosticar si nuestro auto (suponiendo que tenemos uno) podrá llegar sano y salvo a casa.

El problema dice algo así:

Suponiendo que tenemos un auto y el amortiguador de éste sólo soporta pasar sobre 15 baches antes de romperse, escribir una función que reciba el camino como una cadena (ya veremos más adelante cómo es) y devuelva “Woohoo!” si llegaremos sanos a casa o “Car Dead” en caso contrario.

El camino es representado por _ o n, es decir, guiones bajos y letras ene. Si es un guión bajo entonces el camino está “plano” pero si encontramos una n significa que hay un bache.

Un ejemplo del camino podría ser: __n__ en donde hay 1 bache. En cambio, este: ___nn_nnn_n_n tiene 7 baches y este: _________ no tiene baches.

Solución

Muy fácil, contamos cuántas veces aparece n dentro de la cadena que recibimos. Si el conteo es menor o igual a 15, regresamos “Woohoo!” y en caso de que no, “Car Dead”. Así:

def bumps(road):
    return "Woohoo!" if road.count("n") <= 15 else "Car Dead"

Está un poco resumido, pero podría expandirse así:

def bumps(road):
    conteo = road.count("n")
    if conteo <= 15:
        return "Woohoo!"
    else:
        return "Car Dead"

Y para probar podemos hacer esto:

print(bumps("___n_n_n______________n"))# Woohoo!, pues sólo hay 4
print(bumps("n__nnnn__nn___nnnnnnnnnn________"))# Car Dead, porque hay 17
print(bumps("____nnnn___________nnnnn_______n_n_n_n_"))# Wohoo! porque hay 13

Con estos resultados:

Fue un ejercicio que me gustó mucho.

Apuntar a otra dirección ip en subdominio a través de cPanel

Introducción

En estos días estuve tratando de apuntar un sitio “normal” a un servidor dedicado. El sitio original fue rentado en los planes de hosting compartido que todos conocemos, pero aparte de ello había un servidor dedicado.

Como sabemos, los servidores dedicados no tienen un nombre de dominio (al menos que queramos comprar uno), sino una IP.

El sitio era de una aplicación web, presentaba todas sus características y todo ello en un dominio como ejemplo.com. Pero tenía una opción para probar directamente la app, y dicha app estaba en un servidor con una ip como 195.66.33.52.

Así que mi tarea fue hacer que un subdominio como app.ejemplo.com apuntara a dicha IP, configurando todo desde el cPanel, dejando que ejemplo.com apuntara a la IP del hosting compartido.

Apuntar subdominio a otra IP

Nota: esto supone que ya hemos creado un subdominio (cosa muy fácil pero que no veremos en este post) y que tenemos a la mano la IP de nuestro servidor.

En nuestro cPanel debemos tener una opción que dice Zone editor:

Entramos y debe mostrarnos nuestro dominio normal, hacemos click en Administrar:

Nos mostrará una lista de direcciones, entre ellas la que tiene el subdominio:

Hacemos click en Editar y se mostrará algo así:

Y en donde dice IPv4 address ponemos la IP de nuestro servidor, sin http:// ni nada de eso. Finalmente hacemos click en Save Record y listo.

Ahora podemos visitar app.ejemplo.com (dependiendo de tu dominio, claro) y obtendrá los datos del servidor con la IP que pusimos 🙂

 

Faker en Go: generador de datos falsos

Introducción

Hace algún tiempo desarrollé un seeder en Go, y para ello tuve que usar un faker o generador de datos falsos. Un faker, como yo lo defino, es algo que genera datos aleatorios falsos pero que parecen reales. Por ejemplo, generar un nombre como Marta Pérez Hernández o un número de teléfono como 2116258745. Pues hoy veremos un ejemplo de faker en Go.

Estos datos aunque parecen reales, no se sabe a ciencia cierta si lo son. Pero la mayoría de veces sirven para llenar bases de datos, así no nos quebramos la cabeza en inventar cosas.

Pues bien, hice un faker que genera nombres de productos, fechas entre años, números de teléfonos y nombres de personas. Está escrito en Go y no necesita ninguna librería adicional.

Faker en Go

Probar

He puesto este código en el Go Playground. Puedes ejecutarlo (haciendo click en Run) antes de ver el post: Click aquí

Por cierto, en el playground siempre dará los mismos resultados debido a la fecha y hora del servidor, pero si ejecutas el código en tu máquina por ti mismo debe funcionar correctamente.

Funcionamiento

Lo que hace este pequeño faker es tomar datos de un arreglo (tomándolos de manera aleatoria) y combinándolos. Por ejemplo, aquí tengo un arreglo de nombres masculinos:

nombresMasculinos := []string{"Aaron", "Adam", "Adrián", "Aitor", "Alberto", "Aleix", "Alejandro", "Alex", "Alonso", "Álvaro", "Ander", "Andrés",
		"Ángel", "Antonio", "Arnau", "Asier", "Biel", "Bruno", "Carlos", "César", "Cristian", "Daniel", "Dario", "David",
		"Diego", "Eduardo", "Enrique", "Eric", "Erik", "Fernando", "Francisco", "Francisco Javier", "Gabriel", "Gael", "Gerard", "Gonzalo",
		"Guillem", "Guillermo", "Héctor", "Hugo", "Ian", "Ignacio", "Iker", "Isaac", "Ismael", "Iván", "Izan", "Jaime",
		"Jan", "Javier", "Jesús", "Joel", "Jon", "Jordi", "Jorge", "José", "José Antonio", "José Manuel", "Juan", "Juan José",
		"Leo", "Lucas", "Luis", "Manuel", "Marc", "Marco", "Marcos", "Mario", "Martín", "Mateo", "Miguel", "Miguel Ángel",
		"Nicolás", "Oliver", "Omar", "Oriol", "Óscar", "Pablo", "Pedro", "Pol", "Rafael", "Raúl", "Rayan",
		"Roberto", "Rodrigo", "Rubén", "Samuel", "Santiago", "Saúl", "Sergio", "Unai", "Víctor", "Yago", "Yeray",}

Y hay otro arreglo de nombres femeninos (para que no se quejen las feministas):

nombresFemeninos := []string{"Abril", "Adriana", "Africa", "Aina", "Ainara", "Ainhoa", "Aitana", "Alba", "Alejandra", "Alexandra", "Alexia", "Alicia", "Alma",
		"Ana", "Andrea", "Ane", "Angela", "Anna", "Ariadna", "Aroa", "Aya", "Beatriz", "Berta", "Blanca", "Candela",
		"Carla", "Carlota", "Carmen", "Carolina", "Celia", "Clara", "Claudia", "Cristina", "Daniela", "Diana", "Elena", "Elsa",
		"Emma", "Erika", "Eva", "Fátima", "Gabriela", "Helena", "Inés", "Irene", "Iria", "Isabel", "Jana", "Jimena",
		"Joan", "Julia", "Laia", "Lara", "Laura", "Leire", "Leyre", "Lidia", "Lola", "Lucía", "Luna", "Malak",
		"Manuela", "Mar", "Mara", "María", "Marina", "Marta", "Martí", "Martina", "Mireia", "Miriam", "Nadia", "Nahia",
		"Naia", "Naiara", "Natalia", "Nayara", "Nerea", "Nil", "Noa", "Noelia", "Nora", "Nuria", "Olivia", "Ona",
		"Paola", "Patricia", "Pau", "Paula", "Raquel", "Rocío", "Salma", "Sandra", "Sara", "Silvia", "Sofía", "Teresa",
		"Valentina", "Valeria", "Vega", "Vera", "Victoria", "Yaiza", "Zoe",}

También hay apellidos.

Entonces con Go seleccionamos un número aleatorio que esté entre 0 y la longitud del arreglo. Para esto usamos Intn del paquete rand. Lo que hace esta función es que devuelve un número entre 0 y el argumento que le pasemos.

Por ejemplo, si llamamos a Intn con 5, puede dar un 0, un 1, un 2, 3 o 4. Pero cuidado aquí: no puede darnos un 5, pues devuelve el número en un intervalo [0, n) en donde, como recordemos, devolverá un número mayor o igual a 0 pero menor a n.

Entonces elegimos un dato aleatorio así:

nombre := nombres[seeder.Intn(len(nombres))]

Si tenemos 5 nombres, la función len devolverá 5, pero si intentamos acceder a esa posición (nombres[5]) marcará un error, pues los arreglos comienzan en 0. Así que está bien que usemos Intn, pues devolverá siempre un número menor al que le damos.

Muéstrame el código

Y bien, aquí el código. Es un struct, que podríamos abstraer como una clase.

package main

import (
	"fmt"
	"math/rand"
	"time"
)

type Faker struct {
	seed *rand.Rand
}

func (f *Faker) fechaAleatoriaEntreAnios(minimo, maximo int) time.Time {
	min := time.Date(minimo, 1, 0, 0, 0, 0, 0, time.UTC).Unix()
	max := time.Date(maximo, 1, 0, 0, 0, 0, 0, time.UTC).Unix()
	delta := max - min
	sec := f.seed.Int63n(delta) + min
	t := time.Unix(sec, 0)
	return t
}

func (f *Faker) numerosAleatorios(cuantos int) string {
	letras := "0123456789"
	b := make([]byte, cuantos)
	for i := range b {
		b[i] = letras[f.seed.Intn(len(letras))]
	}
	return string(b)
}

func (f *Faker) verdura() string {
	verduras := []string{"Jitomate", "Sandía", "Limón", "Tomate", "Zanahoria", "Papaya", "Piña", "Manzana", "Pera"}
	descriptores := []string{"Japonés", "Agrio", "Rojo", "Verde", "Fresco", "Bola", "Maradol", "Prémium"}
	return fmt.Sprintf("%s %s", verduras[f.seed.Intn(len(verduras))], descriptores[f.seed.Intn(len(descriptores))])
}

func (f *Faker) botana() string {
	nombres := []string{"Galletas chokis", "Sabritas", "Fritos", "Crujitos", "Doritos", "Rufles"}
	sabores := []string{"chocolate", "queso", "picante", "chorizo", "sal y limón", "habanero", "jalapeño"}
	return fmt.Sprintf("%s sabor %s %d gramos", nombres[f.seed.Intn(len(nombres))], sabores[f.seed.Intn(len(sabores))], f.seed.Intn(999))
}

func (f *Faker) refresco() string {
	nombres := []string{"Coca cola", "Pepsi", "Fanta", "Delaware punch", "Boing"}
	sabores := []string{"Guayaba", "Fresa", "Naranja", "Tamarindo", "Mango"}
	return fmt.Sprintf("%s %d ml sabor %s", nombres[f.seed.Intn(len(nombres))], f.seed.Intn(500), sabores[f.seed.Intn(len(sabores))])
}

func (f *Faker) electronico() string {
	nombres := []string{"Tableta", "Teléfono", "Computadora", "Procesador", "Mouse", "Teclado",}
	marcas := []string{"Samsung", "Xiaomi", "Nokia", "Blackberry", "Intel", "AMD", "Compaq", "HP", "Mac"}
	colores := []string{"Dorado", "Plateado", "Azul", "Blanco", "Rosa"}
	return fmt.Sprintf("%s %s color %s", nombres[f.seed.Intn(len(nombres))], marcas[f.seed.Intn(len(marcas))], colores[f.seed.Intn(len(colores))])
}

func (f *Faker) producto() string {
	numero := f.seed.Intn(4)
	switch numero {
	case 1:
		return f.verdura()
		break
	case 2:
		return f.botana()
		break
	case 3:
		return f.refresco()
		break
	case 4:
		return f.electronico()
		break
	}
	return f.electronico()
}

func (f *Faker) nombre() string {
	nombresMasculinos := []string{"Aaron", "Adam", "Adrián", "Aitor", "Alberto", "Aleix", "Alejandro", "Alex", "Alonso", "Álvaro", "Ander", "Andrés",
		"Ángel", "Antonio", "Arnau", "Asier", "Biel", "Bruno", "Carlos", "César", "Cristian", "Daniel", "Dario", "David",
		"Diego", "Eduardo", "Enrique", "Eric", "Erik", "Fernando", "Francisco", "Francisco Javier", "Gabriel", "Gael", "Gerard", "Gonzalo",
		"Guillem", "Guillermo", "Héctor", "Hugo", "Ian", "Ignacio", "Iker", "Isaac", "Ismael", "Iván", "Izan", "Jaime",
		"Jan", "Javier", "Jesús", "Joel", "Jon", "Jordi", "Jorge", "José", "José Antonio", "José Manuel", "Juan", "Juan José",
		"Leo", "Lucas", "Luis", "Manuel", "Marc", "Marco", "Marcos", "Mario", "Martín", "Mateo", "Miguel", "Miguel Ángel",
		"Nicolás", "Oliver", "Omar", "Oriol", "Óscar", "Pablo", "Pedro", "Pol", "Rafael", "Raúl", "Rayan",
		"Roberto", "Rodrigo", "Rubén", "Samuel", "Santiago", "Saúl", "Sergio", "Unai", "Víctor", "Yago", "Yeray",}

	nombresFemeninos := []string{"Abril", "Adriana", "Africa", "Aina", "Ainara", "Ainhoa", "Aitana", "Alba", "Alejandra", "Alexandra", "Alexia", "Alicia", "Alma",
		"Ana", "Andrea", "Ane", "Angela", "Anna", "Ariadna", "Aroa", "Aya", "Beatriz", "Berta", "Blanca", "Candela",
		"Carla", "Carlota", "Carmen", "Carolina", "Celia", "Clara", "Claudia", "Cristina", "Daniela", "Diana", "Elena", "Elsa",
		"Emma", "Erika", "Eva", "Fátima", "Gabriela", "Helena", "Inés", "Irene", "Iria", "Isabel", "Jana", "Jimena",
		"Joan", "Julia", "Laia", "Lara", "Laura", "Leire", "Leyre", "Lidia", "Lola", "Lucía", "Luna", "Malak",
		"Manuela", "Mar", "Mara", "María", "Marina", "Marta", "Martí", "Martina", "Mireia", "Miriam", "Nadia", "Nahia",
		"Naia", "Naiara", "Natalia", "Nayara", "Nerea", "Nil", "Noa", "Noelia", "Nora", "Nuria", "Olivia", "Ona",
		"Paola", "Patricia", "Pau", "Paula", "Raquel", "Rocío", "Salma", "Sandra", "Sara", "Silvia", "Sofía", "Teresa",
		"Valentina", "Valeria", "Vega", "Vera", "Victoria", "Yaiza", "Zoe",}

	apellidos := []string{"Abad", "Abeyta", "Abrego", "Abreu", "Acevedo", "Acosta", "Acuña", "Adame", "Adorno", "Agosto", "Aguado",
		"Aguayo", "Aguilar", "Aguilera", "Aguirre", "Alanis", "Alaniz", "Alarcón", "Alba", "Alcala", "Alcaráz", "Alcántar", "Alejandro",
		"Alemán", "Alfaro", "Alfonso", "Alicea", "Almanza", "Almaráz", "Almonte", "Alonso", "Alonzo", "Altamirano", "Alva", "Alvarado",
		"Amador", "Amaya", "Anaya", "Andreu", "Andrés", "Anguiano", "Angulo", "Antón", "Aparicio", "Apodaca", "Aponte", "Aragón",
		"Aranda", "Araña", "Arce", "Archuleta", "Arellano", "Arenas", "Arevalo", "Arguello", "Arias", "Armas", "Armendáriz", "Armenta",
		"Armijo", "Arredondo", "Arreola", "Arriaga", "Arribas", "Arroyo", "Arteaga", "Asensio", "Atencio", "Avilés", "Ayala", "Baca",
		"Badillo", "Baeza", "Bahena", "Balderas", "Ballesteros", "Banda", "Barajas", "Barela", "Barragán", "Barraza", "Barrera",
		"Barreto", "Barrientos", "Barrios", "Barroso", "Batista", "Bautista", "Bañuelos", "Becerra", "Beltrán", "Benavides",
		"Benavídez", "Benito", "Benítez", "Bermejo", "Bermúdez", "Bernal", "Berríos", "Blanco", "Blasco", "Blázquez", "Bonilla",
		"Borrego", "Botello", "Bravo", "Briones", "Briseño", "Brito", "Bueno", "Burgos", "Bustamante", "Bustos", "Báez", "Betancourt",
		"Caballero", "Cabello", "Cabrera", "Cabán", "Cadena", "Caldera", "Calderón", "Calero", "Calvillo", "Calvo", "Camacho",
		"Camarillo", "Campos", "Canales", "Candelaria", "Cano", "Cantú", "Caraballo", "Carbajal", "Carballo", "Carbonell",
		"Cárdenas", "Cardona", "Carmona", "Caro", "Carranza", "Carrasco", "Carrasquillo", "Carrera", "Carrero", "Carretero",
		"Carreón", "Carrillo", "Carrión", "Carvajal", "Casado", "Casanova", "Casares", "Casas", "Casillas", "Castañeda", "Castaño",
		"Castellano", "Castellanos", "Castillo", "Castro", "Casárez", "Cavazos", "Cazares", "Ceballos", "Cedillo", "Ceja", "Centeno",
		"Cepeda", "Cerda", "Cervantes", "Cervántez", "Chacón", "Chapa", "Chavarría", "Chávez", "Cintrón", "Cisneros", "Clemente",
		"Cobo", "Collado", "Collazo", "Colunga", "Colón", "Concepción", "Conde", "Contreras", "Cordero", "Cornejo", "Corona",
		"Coronado", "Corral", "Corrales", "Correa", "Cortés", "Cortez", "Cortés", "Costa", "Cotto", "Covarrubias", "Crespo",
		"Cruz", "Cuellar", "Cuenca", "Cuesta", "Cuevas", "Curiel", "Córdoba", "Córdova", "De la Cruz", "De la Fuente",
		"De la Torre", "Del Río", "Delacrúz", "Delafuente", "Delagarza", "Delao", "Delapaz", "Delarosa", "Delatorre", "Deleón",
		"Delgadillo", "Delgado", "Delrío", "Delvalle", "Díez", "Domenech", "Domingo", "Domínguez", "Domínquez", "Duarte",
		"Dueñas", "Duran", "Dávila", "Díaz", "Echevarría", "Elizondo", "Enríquez", "Escalante", "Escamilla", "Escobar", "Escobedo",
		"Escribano", "Escudero", "Esparza", "Espinal", "Espino", "Espinosa", "Espinoza", "Esquibel", "Esquivel", "Esteban", "Esteve",
		"Estrada", "Estévez", "Expósito", "Fajardo", "Farías", "Feliciano", "Fernández", "Ferrer", "Fierro", "Figueroa", "Flores",
		"Flórez", "Fonseca", "Font", "Franco", "Frías", "Fuentes", "Gaitán", "Galarza", "Galindo", "Gallardo", "Gallego", "Gallegos",
		"Galván", "Galán", "Gamboa", "Gámez", "Gaona", "Garay", "García", "Garibay", "Garica", "Garrido", "Garza", "Gastélum",
		"Gaytán", "Gil", "Gimeno", "Giménez", "Girón", "Godoy", "Godínez", "Gonzáles", "González", "Gracia", "Granado", "Granados",
		"Griego", "Grijalva", "Guajardo", "Guardado", "Guerra", "Guerrero", "Guevara", "Guillen", "Gurule", "Gutiérrez", "Guzmán",
		"Gálvez", "Gómez", "Haro", "Henríquez", "Heredia", "Hernándes", "Hernando", "Hernádez", "Hernández", "Herrera", "Herrero",
		"Hidalgo", "Hinojosa", "Holguín", "Huerta", "Hurtado", "Ibarra", "Ibáñez", "Iglesias", "Irizarry", "Izquierdo", "Jaime",
		"Jaimes", "Jaramillo", "Jasso", "Jiménez", "Jimínez", "Juan", "Jurado", "Juárez", "Jáquez", "Laboy", "Lara", "Laureano",
		"Leal", "Lebrón", "Ledesma", "Leiva", "Lemus", "Lerma", "Leyva", "León", "Limón", "Linares", "Lira", "Llamas", "Llorente",
		"Loera", "Lomeli", "Longoria", "Lorente", "Lorenzo", "Lovato", "Loya", "Lozada", "Lozano", "Lucas", "Lucero", "Lucio",
		"Luevano", "Lugo", "Luis", "Luján", "Luna", "Luque", "Lázaro", "López", "Macias", "Macías", "Madera", "Madrid", "Madrigal",
		"Maestas", "Magaña", "Malave", "Maldonado", "Manzanares", "Manzano", "Marco", "Marcos", "Mares", "Marrero", "Marroquín",
		"Martos", "Martí", "Martín", "Martínez", "Marín", "Más", "Mascareñas", "Mata", "Mateo", "Mateos", "Matos", "Matías",
		"Maya", "Mayorga", "Medina", "Medrano", "Mejía", "Melgar", "Meléndez", "Mena", "Menchaca", "Mendoza", "Menéndez",
		"Meraz", "Mercado", "Merino", "Mesa", "Meza", "Miguel", "Millán", "Miramontes", "Miranda", "Mireles", "Mojica", "Molina",
		"Mondragón", "Monroy", "Montalvo", "Montañez", "Montaño", "Montemayor", "Montenegro", "Montero", "Montes", "Montez",
		"Montoya", "Mora", "Moral", "Morales", "Morán", "Moreno", "Mota", "Moya", "Munguía", "Murillo", "Muro", "Muñiz", "Muñoz",
		"Márquez", "Méndez", "Naranjo", "Narváez", "Nava", "Navarrete", "Navarro", "Navas", "Nazario", "Negrete", "Negrón", "Nevárez",
		"Nieto", "Nieves", "Niño", "Noriega", "Nájera", "Núñez", "Ocampo", "Ocasio", "Ochoa", "Ojeda", "Oliva", "Olivares",
		"Olivas", "Oliver", "Olivera", "Olivo", "Olivárez", "Olmos", "Olvera", "Ontiveros", "Oquendo", "Ordoñez", "Ordóñez",
		"Orellana", "Ornelas", "Orosco", "Orozco", "Orta", "Ortega", "Ortíz", "Osorio", "Otero", "Ozuna", "Pabón", "Pacheco",
		"Padilla", "Padrón", "Pagan", "Palacios", "Palomino", "Palomo", "Pantoja", "Pardo", "Paredes", "Parra", "Partida",
		"Pascual", "Pastor", "Patiño", "Paz", "Pedraza", "Pedroza", "Pelayo", "Peláez", "Perales", "Peralta", "Perea", "Pereira",
		"Peres", "Peña", "Pichardo", "Pineda", "Pizarro", "Piña", "Piñeiro", "Plaza", "Polanco", "Polo", "Ponce", "Pons", "Porras",
		"Portillo", "Posada", "Pozo", "Prado", "Preciado", "Prieto", "Puente", "Puga", "Puig", "Pulido", "Páez", "Pérez", "Quesada",
		"Quezada", "Quintana", "Quintanilla", "Quintero", "Quiroz", "Quiñones", "Quiñónez", "Rael", "Ramos", "Ramírez",
		"Ramón", "Rangel", "Rascón", "Raya", "Razo", "Redondo", "Regalado", "Reina", "Rendón", "Rentería", "Requena", "Reséndez",
		"Rey", "Reyes", "Reyna", "Reynoso", "Rico", "Riera", "Rincón", "Riojas", "Rivas", "Rivera", "Rivero", "Robledo", "Robles",
		"Roca", "Rocha", "Rodarte", "Rodrigo", "Rodríguez", "Rodríquez", "Roig", "Rojas", "Rojo", "Roldán", "Rolón", "Romero",
		"Romo", "Román", "Roque", "Ros", "Rosa", "Rosado", "Rosales", "Rosario", "Rosas", "Roybal", "Rubio", "Rueda", "Ruelas",
		"Ruiz", "Ruvalcaba", "Ruíz", "Ríos", "Saavedra", "Saiz", "Salas", "Salazar", "Salcedo", "Salcido", "Saldaña", "Saldivar",
		"Salgado", "Salinas", "Salvador", "Samaniego", "Sanabria", "Sánchez", "Sancho", "Sandoval", "Santacruz", "Santamaría",
		"Santana", "Santiago", "Santillán", "Santos", "Sanz", "Sarabia", "Sauceda", "Saucedo", "Sedillo", "Segovia", "Segura",
		"Sepúlveda", "Serna", "Serra", "Serrano", "Serrato", "Sevilla", "Sierra", "Silva", "Simón", "Sisneros", "Sola", "Solano",
		"Soler", "Soliz", "Solorio", "Solorzano", "Solís", "Soria", "Soriano", "Sosa", "Sotelo", "Soto", "Suárez", "Sáenz",
		"Sáez", "Sánchez", "Tafoya", "Tamayo", "Tamez", "Tapia", "Tejada", "Tejeda", "Tello", "Terrazas", "Terán", "Tijerina",
		"Tirado", "Toledo", "Toro", "Torres", "Tovar", "Trejo", "Treviño", "Trujillo", "Téllez", "Tórrez", "Ulibarri", "Ulloa",
		"Urbina", "Ureña", "Uribe", "Urrutia", "Urías", "Vaca", "Valadez", "Valdez", "Valdivia", "Valdés", "Valencia",
		"Valentín", "Valenzuela", "Valero", "Valladares", "Valle", "Vallejo", "Valles", "Valverde", "Vanegas", "Varela",
		"Vargas", "Vega", "Vela", "Velasco", "Velásquez", "Velázquez", "Venegas", "Vera", "Verdugo", "Verduzco", "Vergara",
		"Vicente", "Vidal", "Viera", "Vigil", "Vila", "Villa", "Villagómez", "Villalba", "Villalobos", "Villalpando", "Villanueva",
		"Villar", "Villareal", "Villarreal", "Villaseñor", "Villegas", "Vásquez", "Vázquez", "Vélez", "Véliz", "Ybarra",
		"Yáñez", "Zambrano", "Zamora", "Zamudio", "Zapata", "Zaragoza", "Zarate", "Zavala", "Zayas", "Zelaya", "Zepeda",
		"Zúñiga", "de Anda", "de Jesús", "Águilar", "Álvarez", "Ávalos", "Ávila",}
	var nombre string
	if f.seed.Intn(2) == 1 {
		nombre = nombresFemeninos[f.seed.Intn(len(nombresFemeninos))]
	} else {
		nombre = nombresMasculinos[f.seed.Intn(len(nombresMasculinos))]
	}
	return fmt.Sprintf("%s %s %s", nombre, apellidos[f.seed.Intn(len(apellidos))], apellidos[f.seed.Intn(len(apellidos))])
}

Para usarlo simplemente creamos una instancia, le pasamos el seeder y listo. Así:

func main() {

	//Necesitamos alimentar el seeder sólo una vez antes de usarlo
	fuente := rand.NewSource(time.Now().Unix())
	random := rand.New(fuente)

	//Creamos una instancia y le pasamos la semilla para poder elegir cosas aleatorias
	faker := Faker{
		seed: random,
	}

	// Hora de usar el faker :-)
	fmt.Printf("Un producto: %s\n", faker.producto())

	//También se puede dentro de un ciclo
	for x := 0; x <= 10; x++ {
		fmt.Printf("Alguna fecha aleatoria entre 2010 y 2020: %v\n", faker.fechaAleatoriaEntreAnios(2010, 2020))
	}

	//Un nombre
	nombre := faker.nombre()
	fmt.Printf("El nombre: %s\n", nombre)

	//Número aleatorio. Como un número telefónico o un código de barras
	numero := faker.numerosAleatorios(10)
	fmt.Printf("Un número aleatorio de 10 dígitos: %s", numero)
}

En mi caso puse todo en el mismo archivo, y al ejecutarlo con go run faker.go obtengo esto:

Probando nuestro faker en Go

Probando nuestro faker en Go

Yo lo utilicé para un seeder y trabaja muy bien. Obviamente tiene algunos “errores” que podemos ver, por ejemplo, no hay tabletas AMD, pero como lo dije, es un faker: datos falsos.

Espero mejorarlo con el tiempo.

 

Restringir acceso dependiendo de la hora o fecha usando PHP

Introducción

Esto resultará un ejercicio sencillo pero a la vez interesante que podemos implementar en PHP. Se trata de restringir o bloquear el acceso a determinadas páginas, o a determinadas acciones dependiendo de la hora del día, e incluso dependiendo del día, mes, año, etcétera. Para esto usaremos el lenguaje más popular del lado del servidor: PHP.

Además, esto permite que, aunque el usuario cambie la hora de su pc nosotros podamos seguir restringiéndolo. Ya que nadie (sólo nosotros) podrá cambiar la hora del servidor.

Entendiendo el algoritmo

Simplemente vamos a tomar la fecha actual cada vez que se consulte el script. Y dependiendo de ello realizaremos ciertas acciones.

Consultando fecha actual

Cuando consultamos la fecha, puede que ésta esté mal configurada por la zona horaria: cosa que puede traernos grandes problemas. Para ello, simplemente tenemos que establecerla bien usando date_default_timezone_set. En mi caso pondré la zona horaria de la Ciudad de México, así:

date_default_timezone_set("America/Mexico_City");

Si tienes dudas sobre esto, ya escribí un post de cómo establecer la zona horaria en diferentes lugares del mundo.

Ahora sí vamos a trabajar.

Restringir en PHP dependiendo de la hora o día

Permitir sólo si está en determinado rango

Por ejemplo, supongamos que sólo permitiremos que los visitantes vean nuestro sitio de 8 a 10 de la mañana.

Entonces consultaríamos la hora actual utilizando date(“H”) y luego convirtiendo ese valor a entero (porque recordemos que date(“H”) devuelve el número con ceros a la izquierda, por ejemplo 02 para las 2 de la madrugada).

Finalmente compararíamos y el código queda así:

<?php
$desde = 8; # Desde las ocho de la mañana
$hasta = 10; # Hasta las 10

$hora_actual = intval(date("H"));
if ($hora_actual >= $desde && $hora_actual < $hasta) {
    # Aquí la acción que se realice en el horario permitido
    echo "Bienvenido, visitante";
} else {
    # Mostrar un aviso
    echo "No se permiten visitantes a esta hora del día";
}

Hay que ser cuidadosos en el if. Como vemos, comparamos si es menor a “$hasta”. Ya que así, permitirá entrar hasta 9:59 pero cuando sean las 10 (o un número mayor, incluso con minutos) ya no dejará pasar.

Si nosotros hubiésemos comparado con menor o igual, el rango se habría ampliado hasta las 10:59.

Permitir sólo si está en una hora específica

Ahora veamos cómo hacer que se muestre la página pero sólo a una hora, por ejemplo, a las 11 de la mañana.

En otras palabras, estará disponible desde 11:00 hasta 11:59. Utilizaremos igualmente date(“H”) y el código quedará más reducido:

<?php
$permitido = 11; # Sólo a las 11 de la mañana

$hora_actual = intval(date("H"));
if ($hora_actual === $permitido) {
    # Aquí la acción que se realice en el horario permitido
    echo "Bienvenido, visitante";
} else {
    # Mostrar un aviso
    echo "No se permiten visitantes a esta hora del día";
}

Como lo dije, sólo se permitirá desde 11:00 hasta 11:59

Dependiendo del día

También podemos ver los días del mes (del 1 al 30 o 28 o 31, dependiendo del mes). Por ejemplo, ¿qué tal si nuestro sitio sólo puede ser visitado desde el día 14 hasta el día 21?

Lo que tendríamos que hacer sería consultar el día del mes, y comparar. Casi como en los ejemplos de arriba pero ahora utilizamos date(“j”). El código queda así:

<?php
$desde = 14; # Desde el día 14
$hasta = 21; # Hasta el día 21

$dia_actual = intval(date("j")); #Convertir siempre a entero para evitar errores
if ($dia_actual >= $desde && $dia_actual <= $hasta) {
    # Aquí la acción que se realice en el horario permitido
    echo "Bienvenido, visitante";
} else {
    # Mostrar un aviso
    echo "No se permiten visitantes en este día";
}

Así, se podrá acceder desde el 14 hasta el 21, pero el 22 ya no. Ni los otros días.

Dependiendo del día de la semana (lunes, martes, etcétera)

Si queremos que nuestro sitio sólo se vea los domingos, o un día de la semana (sin importar el número del día) podemos usar date(“w”) que devuelve un número del 0 al 6, el 0 es domingo y el 6 es sábado.

Sabiendo eso, para permitir que sólo los Lunes (día número 1, porque domingo es 0) se pueda acceder, hacemos esto:

<?php
$lunes = 1; #Domingo 0, Lunes 1... Sábado 6

$dia_actual = intval(date("w")); #Convertir siempre a entero para evitar errores
if ($dia_actual === $lunes) {
    # Aquí la acción que se realice en el horario permitido
    echo "Bienvenido, visitante";
} else {
    # Mostrar un aviso
    echo "No se permiten visitantes en este día";
}

 

En muchas horas pero no rangos

Para el caso de que necesitemos permitir el sitio en muchas horas pero no en un rango, por ejemplo, a las 2 de la madrugada, a las 5 de la tarde y a las 11 de la noche (2, 17 y 23 horas) podemos utilizar in_array.

<?php
$permitidos = [2, 17, 23]; # A las 2 a.m., 5 p.m. y 11 p.m.

$hora_actual = intval(date("H"));
if (in_array($hora_actual, $permitidos)) {
    # Aquí la acción que se realice en el horario permitido
    echo "Bienvenido, visitante";
} else {
    # Mostrar un aviso
    echo "No se permiten visitantes a esta hora del día";
}

Con algunas modificaciones incluso podríamos permitir en muchos días, meses o años.

Conclusión

Lo único que tenemos que hacer es entender bien las formas de trabajar con fechas y horas en PHP, para que, dependiendo de ello, realicemos condiciones. Con la función date podemos saber el año, mes, día, segundos, día del año (hasta 365) y mucho más.

Referencias

PHP: date – Manual

Obtener arquitectura de procesador usando Linux

Introducción

Hay ocasiones en las que necesitamos saber o conocer la arquitectura física del procesador. Una cosa es la arquitectura del sistema operativo, y otra la arquitectura del procesador en sí.

Por ejemplo, puede que tengamos un sistema operativo de 32 bits pero en realidad nuestro procesador soporte uno de 64 bits.

Hoy veremos cómo hacerlo desde Linux con un comando sencillo. Recuerda que hay live cd’s que no necesitan instalación: insertas el disco, reinicias la pc y esperas a que se cargue el sistema en la RAM.

Conocer arquitectura de procesador

Una vez que hemos iniciado nuestro sistema Linux, abrimos una terminal. No necesitamos ser usuarios con permisos. Ejecutamos lo siguiente:

lscpu

Y la salida será algo así:

Architecture:          x86_64                                                                                                                          
CPU op-mode(s):        32-bit, 64-bit                                                                                                                  
Byte Order:            Little Endian                                                                                                                   
CPU(s):                12                                                                                                                              
On-line CPU(s) list:   0-11                                                                                                                            
Thread(s) per core:    2                                                                                                                               
Core(s) per socket:    6                                                                                                                               
Socket(s):             1                                                                                                                               
NUMA node(s):          1                                                                                                                               
Vendor ID:             GenuineIntel                                                                                                                    
CPU family:            6                                                                                                                               
Model:                 63                                                                                                                              
Model name:            Intel(R) Xeon(R) CPU E5-1650 v3 @ 3.50GHz                                                                                       
Stepping:              2                                                                                                                               
CPU MHz:               3599.941                                                                                                                        
CPU max MHz:           3800.0000                                                                                                                       
CPU min MHz:           1200.0000                                                                                                                       
BogoMIPS:              6983.22                                                                                                                         
Virtualization:        VT-x                                                                                                                            
L1d cache:             32K                                                                                                                             
L1i cache:             32K                                                                                                                             
L2 cache:              256K                                                                                                                            
L3 cache:              15360K                                                                                                                          
NUMA node0 CPU(s):     0-11                                                                                                                            
Flags:                 fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall 
nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor ds_cpl vmx
 smx est tm2 ssse3 fma cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm ida arat epb 
pln pts dtherm tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid cqm xsaveopt cqm_llc cqm_occup_llc

Lo que nos importa realmente será la parte que dice Architecture y CPU op-mode(s).

Si en Architecture dice i686 o en CPU op-mode(s) dice únicamente 32-bit, entonces el procesador es de 32 bits.

En cambio, si en Architecture dice x86_x64 o en CPU op-mode(s) tiene 64-bit (o 32-bit, 64-bit) entonces es de 64 bits.

Por lo que si vemos esta imagen:

Nos damos cuenta de que es una computadora cuyo procesador es de 64 bits.

Referencias

How to identify 64 bit processor with cat /proc/cpuinfo

Operaciones y operadores aritméticos en Python

Operaciones y operadores aritméticos en Python

Introducción

Este es un post en donde explicaremos con ejemplos los operadores aritméticos que existen en Python.

Operadores aritméticos

Suma

Para sumar dos números utilizamos el operador +. Suma 2 o más números. Para sumar dos números hacemos esto:

numero1 = 2
numero2 = 10
suma = numero1 + numero2

Si queremos sumar 3 números:

numero1 = 2
numero2 = 10
numero3 = 8
suma = numero1 + numero2 + numero3

Y así infinitamente.

Si queremos sumar la misma cantidad de una variable podemos hacer algo así:

numero1 = 10
numero2 = 5
numero1 = numero1 + numero2

En este caso, a numero1 le asignamos la suma de el valor del mismo número mas el valor de numero2 .

Pero podemos simplificarlo así:

numero1 = 10
numero2 = 5
numero1 += numero2

Utilizamos entonces el operador +=

Resta

Igualmente podemos restar múltiples valores. Para restar hacemos esto:

numero1 = 28
numero2 = 21
resta = numero1 - numero2

Podemos restar cualquier cantidad de números:

un_numero = 100
otro_numero = 20
otro_numero_mas = 30
resta = un_numero - otro_numero - otro_numero_mas

Si queremos restar determinada cantidad a una variable podemos hacer esto:

numero = 10
numero = numero - 5 #Ahora  es 5, porque 10 - 5 = 5

Pero igualmente podemos utilizar la forma corta:

numero = 10
numero -= 5

Multiplicación

El producto de dos números. Para multiplicar utilizamos el asterisco o *. Por ejemplo:

base = 10
altura = 2
area = base * altura

Y no necesariamente tienen que ser variables, también puede ser así:

area = 10 * 2

No olvidemos que podemos multiplicar cualquier cantidad de números:

volumen = 10 * 20 * 5

División

Casi igual que la multiplicación, pero ahora utilizamos la barra inclinada o diagonal: /

Si queremos dividir dos números:

promedio = 500/5

O 3:

variable = 100 / 2 / 3

Y así infinitamente. Por cierto, podemos usar paréntesis si queremos atrapar el resultado de la división de un grupo de números.

Por ejemplo, si deseamos dividir 100 entre el resultado de dividir 2 entre 3 sería así:

variable = 100 / (2 / 3)

Cuyo resultado es 150. Y si lo hacemos sin paréntesis, el resultado sería 16.66.

Esto no quiere decir que siempre usemos paréntesis, pero sí que debemos tener cuidado al hacer nuestras operaciones.

Módulo

Este operador devuelve el sobrante de una división entera, o así es como yo lo defino.

Si dividimos 5 / 2 tenemos a 2.5 como resultado, pero si lo hiciéramos “enteramente” el resultado sería 2 y sobraría 1. Pues esto es lo que hace este operador.

Es representado con el símbolo de porcentaje o %.

Por ejemplo…

sobrante = 5 % 2

Cuyo resultado es 1.

Este operador es usado mayormente para detectar si un número es par o impar. Al dividir un número entre 2, siempre sobrará 1 o 0. Tenemos el caso de 10, al dividirlo sale 5 y sobran 0, por lo tanto es par.

Contrario a dividir 11 entre 2, cuyo sobrante es 1.

Entonces, para saber si un número es par podemos hacer un if:

numero = 15
if numero % 2 == 0:
  print("Es par")
else:
  print("Es impar")

Al ejecutar el código, se imprimirá Es impar.

Exponente

Este operador permite elevar cierto número a una potencia. Por ejemplo, si elevamos el 5 a la potencia 2 tenemos 25. Si lo elevamos a la 3 entonces es 125, y así sucesivamente.

Es representado con 2 asteriscos o ** y se usa como si hiciéramos una multiplicación. Así:

cinco_al_cuadrado = 5 ** 2

El resultado será 25. Y podemos elevar cualquier número a cualquier potencia.

División redondeada hacia abajo

Para terminar veamos este operador que igualmente es muy útil. Sirve para dividir 2 números, pero redondea hacia abajo el resultado. Veamos el ejemplo de dividir 9 entre 2, cuyo resultado es 4.5.

Si lo redondeamos hacia abajo, el resultado es 4.

redondeado = 9 // 2

Notar por favor que redondea hacia abajo, no redondea. Por lo que aunque el resultado sea, por ejemplo, 4.9, se redondeará a 4.

Veamos estos ejemplos:

Y con eso terminamos.

Python: función que regresa el número 5 sin usar números ni operadores

Introducción

Continuando con algunos ejercicios de codewars, esta mañana me topé con uno muy interesante que me hizo pensar más de lo que debería.

Se trataba de algo muy, muy simple: escribir una función que regresara el número 5 utilizando el lenguaje Python. Algo así:

def regresar_cinco():
  return 5

Pero con algunas restricciones: no usar números, ni operadores aritméticos. Es decir, estaba prohibido usar 0123456789 y /*-+

Así que no podías hacer algo como regresar 4 + 1 o cosas de esas.

Solución

Después de pensar por algunos minutos, me di cuenta de que se podía regresar la longitud de una cadena definida por nosotros mismos.

La palabra “hello” así como “asdfg”, “luiss” y otras tienen una longitud de 5, por lo que nada costaba hacer esto:

def regresar_cinco():
  return len("hello")

Y no iba contra las reglas, pues no usamos ningún operador ni número. He aquí el programa ejecutándose en una sesión REPL:

Python: función que regresa número, pero sin escribir números u operadores

Python: función que regresa número, pero sin escribir números u operadores

Con eso terminamos por hoy.