Limpiando entradas de datos de usuario en OsCommerce

Escrito el 02/October/2008 por juan_belon

Como echaba en falta una función decente para eliminar caracteres extraños, he creado esta opción para la función de OsCommerce "tep_sanitize_string" , de forma que ahora además tenga un modo "paranoid" con el que sólo nos deje el texto y nada más…para campos peligrosos como para pasarelas de pago y demás es encantador jejeje

Nos vamos a /catalog/includes/functions/general.php y reemplazamos la función tep_sanitize_string por esta:


<?php
function tep_sanitize_string($string,$paranoid=false) {
$string ereg_replace(‘ +'‘ 'trim($string));
if (!
$paranoid)
return 
preg_replace("/[&lt;&gt;]/"‘_'$string);
else {
$string preg_replace(‘/&lt;(.|\s)*?&gt;/'"$string);
$string str_replace(‘&lt;',",$string);
$string str_replace(‘&gt;',"",$string);
return 
ereg_replace(‘(([^0-9a-z&lt;&gt;A-Z_\.\ \@])+)'"",$string);
}
}

?>


Todo sobre Funciones en PHP

Escrito el 07/April/2008 por juan_belon

He considerado oportuno explicar desde las cosas más básicas y sencillas con respecto a las funciones hasta las más complejas, ya que nos pueden ahorrar inventarnos otros mecanismos más inadecuados si no conocemos las maravillosas características que se pueden tener un método o función bien construido. Empecemos pues por lo más fácil y vayamos aumentando el nivel

Declarar una función simple: desde PHP4 se pueden declarar antes y después del lugar donde es llamada.


<?php
function imprimirNegrita($texto){
echo 
"<b>$texto</b>";
}
echo 
"Linea sin negrita<br />";
imprimirNegrita("Linea en negrita<br />");

?>


La sentencia return
En un punto de la función se encontrará en un estado final y dispuesta a devolverle el control a quien la llamó, por ejemplo cuando llega al final del bloque de código de la función, la ejecución coge entonces la línea siguiente de aquella donde fue llamada. Otra forma de para la ejecución de la función es usar la sentencia return. Seguramente existirán varias en una función, pero usar demasiados puede ser una barrera para comprender el flujo de la ejecución y hace más difícil la lectura del código. Lo ideal es tener una entrada y una salida pero en la práctica hay casos en los que es más que aceptable tener múltiples sentencias return.


<?php
function hacerNegrita($texto){
$texto "<b>$texto</b>";
return 
$texto;
}
echo 
"Linea sin negrita<br />";
echo 
hacerNegrita("Linea en negrita<br />");

?>


Paso por referencia y por valor:
Para la mayor parte de los tipos de datos ,las variables pasadas como argumentos de la función se hacen por valor, en PHP4 se puede forzar a pasarlos por referencia mediante el uso de "&" justo antes del nombre de la variable: "&$variable". Las funciones también disponen de esta característica si realizamos algo como lo siguiente:


<?php
function &amp;obtenerMatrizAleatoria(){
$matriz = array();
for ( 
$i=0$i 10$i++ ){
$a[] = rand(1,100);
}

return $a;
}

$nuevaMatriz =&ampobtenerMatrizAleatoria();

?>


Sin embargo, hay que tener en cuenta que el uso de & estará "vetado" a partir de PHP6.x o superiores y si usamos la referencia con una sentencia new aparecerá un error de tipo STRICT a partir de la versión 5 de PHP.


<?php
class MiClase {
/** Constructor de MiClase */
function MiClase(){}
}
$c =&amp; new MiClase(); //Devuelve "deprecated" en PHP5.x+

?>


Ámbitos
El ámbito ,también llamado "scope", se creaó para evitar colisiones entre variables de diferentes funcione, PHP incluye dicha noción de ámbito. Cada línea de código pertenece a un determinado "scope". El código dentro de una función se considera que pertenece al ámbito de la propia función. El código fuera de la función pertenece al ámbito global del fichero. El ámbito es la propiedad que determina qué tabla de memoria se usa para almacenar las variables y alternativamente qué variables son accesibles. Por lo tanto ,las variables de una función son locales a ésta,por lo que no se podrán modificar desde fuera de ella ya que son de propiedad privada. Sin embargo las variables globales fuera de la función han de declararse como globales accesibles por medio de la sentencia "global" antes del nombre de variable, ejemplo: "global $mivariable" es accesible en una función si realizamos dicho acceso de la variable declarada fuera:


<?php
$ciudad  
"Granada";
function 
miCiudad(){
global 
$ciudad;
mostrarCiudad($ciudad);
}
function 
mostrarCiudad($nombre){
echo 
"La ciudad seleccionada es :".$nombre."<br />";
}
function 
OtraCiudad(){
$ciudad "Sevilla";
mostrarCiudad($ciudad);
}
miCiudad();
OtraCiudad();

}

?>


Cuando se ejecuta el script se muestra Granada y Sevilla en ese orden. Aunque hayamos modificado $ciudad dentro de la función OtraCiudad() ,no es la misma que la del ámbito global.

La sentencia global lleva una variable a un espacio de nombres de una función,desde ese momento se puede modificar dentro o fuera de aquella. Así es posible referenciar la variable a través del array $_GLOBALS donde se indexan por el nombre, de forma que podríamos acceder a "global $ciudad" por medio de "$_GLOBALS['ciudad']".

Variables estáticas
Recordemos que cuando creamos una variable dentro de una función sólo existe mientras la función se esté ejecutando. Una vez que la ejecución finalice y se pase el control al proceso que realizó la llamada, todo el espacio de variables para esa función es borrado, a veces esto no es lo deseable porque necesitamos que la función recuerde el último estado de las variables entre llamadas, esto se puede implementar por medio del uso de la sentencia "static".
En el comienzo de la función antes de los comandos debes declarar las variables que van a ser estáticas,entonces mantendrán su valor incluso después de abandonar la función. Veamos un ejemplo sencillo para usar esto (alternar colores de las celdas de una tabla):


<?php
function alternarColor(){
//Recordar Color usado
static $color "#00FF00″;
if (
$color=="#00FF00″){
$color "#CCFFCC";
} else {
$color "#00FF00″;
}
return 
$color;
}
echo 
‘<table>';
for (
$i=1$i 11$i++){
$color alternarColor();
//Mostrar la fila en el color alternado:
echo ‘<tr><td bgcolor="‘.$color.‘">Fila '.$i.‘</td>'."\n";
}
echo 
‘</table>';

?>


Argumentos
Cuando se declara una función es posible que necesitemos usar argumentos dentro del paréntesis y separados por comas, si se usa el operador & se pasan por referencia (se pasa la dirección de memoria de la variable desde la llamada) y si no se especifica se pasan por valor (se hace una copia de la variable), los cambios realizados sólo permanecen después de salir de la función con el paso por referencia.
Un argumento puede tener un valor por defecto, esto se hace con una asignación (usando el "=" ) al especificar el nombre de variable dentro del paréntesis de la declaración de la función, ejemplo:


<?php
function mostrarColor($texto$color="black", &amp;$cuenta=NULL){
echo 
‘<span style="color:'.$black.‘;">'.$texto.‘</span>';
//La función isset() comprueba que $cuenta no tenga un valor NULL (nulo).
if (isset($cuenta) &amp;&ampis_numeric($cuenta)) $cuenta intval($cuenta)+1;
}

mostrarColor("Texto en negro").‘<br />';
mostrarColor("Texto en azul","blue").‘<br />';
//Ahora declaramos $c para pasársela como argumento a la función:
$c 0;
mostrarColor("Texto en rojo con cuenta","red",$c).‘<br />';
mostrarColor("Texto en verde con cuenta","green",$c).‘<br />';
echo 
"Cuenta total: $c <br />";

?>


La cuenta ha de tener 2 al final de la ejecución.

Funciones para recuperar propiedades de una función
Podemos acceder a los argumentos por su posición usando tres funciones:

  • func_get_arg($numero_argumento): el primer argumento tiene índice 0.
  • func_get_args(): el primer argumento también tiene índice 0.
  • func_num_args(): devuelve el número de argumentos de una función

Ejemplo para usar estas funciones:


<?php
function crearLista(){
echo 
"<ol>\n";
$n func_num_args();
for (
$i=0$i $n $i++ ) {
echo 
"<li>"func_get_arg($i)."\n";
}
echo 
"</ol>\n";
crearLista("GNU/Linux","Apache","MySQL","PHP","XML");
}

?>


Para recuperar los nombres de las clases existe "get_class($variable_instancia_objeto)" que devuelve el nombre como una cadena, para obtener sus métodos en un array de los nombres de los métodos de la clase, usa "get_class_methods($nombre_clase)" o la alternativa con el objeto: "get_class_methods($variable_instancia_objeto)". Para obtener las variables de una clase en un array , usa "get_class_vars($nombre_clase)" y la variante para el objeto instanciado es "get_object_vars($variable_instancia_objeto)". Además podemos recuperar el nombre del padre de la clase con "get_parent_class($variable_instancia_objeto)" o bien con "get_parent_class($nombre_clase)". Quizás una útil función es "is_a(object $instancia, string $clase)", que sirve para comprobar si una determinada variable $instancia de objeto es del tipo especificado en la cadena $clase. De hecho, si la clase ha heredado de otra se pueden comprobar con "is_subclass_of(object $instancia, string $nombre_clase)", por último para comprobar si existe un método en la instancia de un objeto dado: boolean method_exists(object $instancia, string $nombre_metodo)".

Recursividad
¡Qué sería de las funciones sin la recursividad! . Nuestras funciones hacen llamadas a otras funciones y estas al mismo tiempo pueden hacer llamadas a si mismas. El proceso de una función que se llama a sí misma se llama Recursividad. Esta definición circular lleva a la elegancia del diseño de algoritmos, también se puede definir como la solución a un problema que se subdivide en subproblemas más pequeños varias veces. Son muy comunes en Matemáticas, ejemplo: la serie de Fibonacci. En zenphp podemos encontrar funciones implementadas que usan esta técnica [ver]. A veces puede resultar complejo comprender un algoritmo recursivo y nos lleva un tiempo realizar la traza de la ejecución. Se suele utilizar por motivos de eficiencia, ya que 10 llamadas en PHP necesita mantener 10 copias es necesario que nos ocupemos manualmente de las variables…

Ejemplo de uso de la recursión en una función:


<?php
function comprobarEntero($numero){
if (
$numero ){
return 
comprobarEntero($numero-1);
} elseif (
$numero 0){
return 
comprobarEntero((-1)*$numero-;
} else {
if (
$numero 0  &amp;&amp;  $numero 1) return "No";
else return 
"Si";
}
}

echo "Es 0 un entero?".comprobarEntero(0)."<br>";
echo 
"Es 7 un entero?".comprobarEntero(7)."<br />";
echo 
"Es 2.7 un entero?".comprobarEntero(2.7)."<br />";
echo 
"Es -7 un entero?".comprobarEntero(-7)."<br />";

?>


Llamadas dinámicas a funciones
Puede que no sepas qué función llamar cuando estás escribiendo un script de PHP, posiblemente sea porque los datos en los que te bases determinen qué hacer durante la ejecución, una forma de llevar esto a cabo es establecer una variable con el nombre de una función y después usarla como si fuera una función.
Si a una variable le sigue un paréntesis se interpreta de esta forma, se tratará como una función, veamos un ejemplo:


<?php
function mostrar($texto)
{
echo 
$texto;
}
function 
mostrarNegrita($texto){
echo 
‘<b>'.$texto.‘</b>';
}
$miFuncion ‘mostrar';
$miFuncion("Hola!").‘<br />';
$miFuncion ‘mostrarNegrita';
$miFuncion("Hola en negrita!").‘<br />';

?>


Si no sabes exactamente como funcionará exactamente puedes crear una función anónima por medio de la función "create_function".

Funciones definidas por el usuario
La función "create_function" crea una función y devuelve un nombre único, por eso son funciones anónimas, eso permite escribir funciones que dependen de información sólo disponible en tiempo de ejecución, aunque puedes almacenar el nombre de esta nueva función en una variable para lalmarla después, create_function es quizás el método más útil para definir funciones de tipo lambda, ejemplo:


<?php
$datos  
= array("zanahoria","manzana","naranja");
//añade subrayado bajo al final de cada palabra y convertir todo a mayúsculas:
array_walk($datoscreate_function(‘&amp;$v',
‘$v = "_".strtoupper($v)."_";')
);
print_r($datos);

?>



Puedes crear y usar tus propias funciones con "call_user_func($nombre_funcion,…)", ejecuta una función definida por el usuario, donde "…" a continuación son los argumentos a pasar a dicha función en tiempo de ejecución. Puedes usarla para llamar a un método de un objeto ,entonces en lugar de un nombre usa un array donde el primer argumento es el objeto donde reside el método y el segundo el nombre de la función,ahi termina el array, el resto igual que antes…

call_user_func_array($funcion, $array_de_parametros ) es igual que call_user_func excepto porque hay un array de parámetros en lugar de varios argumentos.

Un método no recomendado es eval(), intenta ejecutar el argumento pasado, que es código PHP, ejemplo:


<?php
$codigo 
‘<b>< ?php print(date("d-m-Y"));?></b>';
eval (
"?>".$codigo);

?>


Y hasta aquí sobre funciones, seguid leyendo el código de zenphp para ver más ejemplos complejos.

Equilibrando la carga de procesamiento

Escrito el 30/January/2008 por juan_belon

A veces deberemos hacer más consultas que procesamiento y otras veces es al revés, por eso debemos conocer los mecanismos equivalentes como instrucciones tanto para PHP como para mySQL o cualquier otro motor de base de datos.
Ejemplo, si necesitamos construir una tabla, un listado que extraemos de una serie de tuplas de una consulta de la base de datos ,pero sólo queremos mostrar del campo título ,digamos unos 20 ó 30 caracteres, en lugar de seleccionar todas las tuplas que podrían ser miles, y tienen cada una 250…y después recortar la cadena con substr() de PHP, lo que hacemos es seleccionar sólo esos 20 ó 30 caracteres desde la base de datos con una instrucción mejorada de mySQL: "SELECT SUBSTRING(campo, 1,20) as campo from tabla" o bien SELECT SUBSTRING(campo, 1,30) o cualquier otra subcadena, recortando el texto en el motor de base de datos lo hace más eficiente y carga menos el buffer. Observar que se empieza con 1 y no con 0 (por si os da quebraderos de cabeza…)

Saludos de un programador PHP.
(keep up the good code!!=)

Usando el sistema de memoria con PHP

Escrito el 25/January/2008 por juan_belon

PHP ofrece una extensión para usar el sistema de memoria de System V de S.O. tipo Unix, GNU/Linux, Solaris, etc a través de llamadas al sistema ,estamos hablando de semáforos.

La memoria compartida es memoria virtual compartida por procesos separados. Ayuda a solventar problemas de comunicación entre procesos ejecutándose en la misma máquina. Un método obvio debería ser escribir información en un fichero, pero el acceso a un medio permanente es relativamente lento. La memoria compartida permite la creación de memoria de sistema que pueda ser accedida por múltiples procesos, lo que es mucho más rápido. Como el uso exclusivo de la memoria es esencial, se debe usar un orden de bloqueo. Esto se suele hacer con semáforos. Si se usan las funciones de memoria compartida primero tenemos que asegurarnos de que se incluye el soporte de semáforos de System V.

Una discusión completa del uso de las funciones de memoria compartida se encuentra en http://www.whatis.com

La función integer_shm_attach(integer key, integer size, integer permissions) fue añadida por Christian Cartus. (thank you)

Un ejemplo:


<?php
/**
* Este ejemplo usa un semáforo para usar la
* memoria compartida para comunicarse
* entre múltiples procesos.
* Para liberar la memoria creada se debe
* de usar shm_remove
*/

//definir las llaves enteras de los semáforos
define(‘SEM_GRANADA_PHP',1970);
// la memoria compartida (MC):
define(‘MC_GRANADA_PHP',1970);
//llave para la variable:
define(‘MC_MENSAJE',1970);

//Obtener o crear el semáforo
$sem sem_get(SEM_GRANADA_PHP,1);
//sólo se puede obtener una vez:
if (sem_acquire($sem))
{

//asociar a la memoria:
$mem shm_attach(MC_GRANADA_PHP,1024);
//Hacemos que entre en un KiloByte.
//Obtenemos el mensaje:
if ($anterior_mensaje shm_get_var($memMC_MENSAJE)){
echo 
"Valor anterior: $anterior_mensaje &lt;br&gt;\n";
}
//crear nuevo mensaje:
$nuevo_mensaje getmypid()." aqui a las ".microtime();
//poner el nuevo valor:
shm_put_var($memMC_MENSAJE$nuevo_valor);
//desasociar de la memoria compartida:
shm_detach($mem);
//liberar el semáforo:
sem_release($sem);
}
else {
echo 
"No se pudo obtener el semáforo!";

}

?>


shm_remove:


<?php
//Con las mismas constantes
//obtenemos el semáforo:
$sem sem_get(SEM_GRANADA_PHP1);
if (
sem_acquire($sem)){
//añadir a la memoria compartida
$mem shm_attach($memMC_MENSAJE);
//quitar la memoria compartida:
shm_remove($mem);
//borrar el semáforo:
sem_release($sem);
} else {
echo 
"No se pudo obtener el semáforo!";
}

?>


Dias entre dos fechas

Escrito el 09/January/2008 por juan_belon

La versión más resumida que he podido crear de la función:


<?php
/**
* Calcula la diferencia entre dos fechas y devuelve el número de dias resultante:
* Pasar las fechas como cadenas en el formato: date('d/m/Y')
*
* @param str $fecha_ini
* @param str $fecha_fin
* @return str
*/
function zen_comparaFechas ($fecha_ini$fecha_fin){
//Inicialización
$matriz_f_ini explode ("/"$fecha_ini);
$matriz_f_fin explode ("/"$fecha_fin);
//Cálculo
return gregoriantojd($matriz_f_fin[1], $matriz_f_fin[0], $matriz_f_fin[2]) - gregoriantojd($matriz_f_ini[1], $matriz_f_ini[0], $matriz_f_ini[2]);
}

?>


Último artículo del año: Componentes imprescindibles del desarrollador web

Escrito el 31/December/2007 por juan_belon

No puede faltar un artículo en el último día del año ,¿no?!, además es Navidad jeje

Tampoco puede faltar en los módulos del Firefox de todo desarrollador Firebug e YSlow!

Gracias a éste último, combinado con Firebug podemos analizar la fuente de las esperas más largas por carga en nuestra web,es necesario para saber cómo mejorar nuestras prácticas de programación y escritura de aplicaciones para el marco de internet.

Los consejos de YSlow son buenos consejeros y nos enseñan como construir etags,hacer cacheable ajax,…y en general nos dan unas sencillas reglas para hacer que las cargas sean más rápidas, usar ficheros comprimidos con gzip, evitar las expresiones dentro de CSS,etc.

Todo un regalo de Reyes Majos para esta entrada del 2oo8!

Salu2 y cuidaros!

Evitando malgasto de memoria con objetos

Escrito el 14/December/2007 por juan_belon

¿Por qué?: Fácil: porque si queremos mantener referencias a objetos dentro de otros objetos veremos que si hacemos una clase llamada clase_prueba y la instanciamos:

<?php
$a = new clase_prueba();
?>

Si queremos referenciarla y no realizar copias innecesarias de TODO el objeto simplemente hacemos:

<?php
$a =& new clase_prueba();
$b =& $a;
?>

De forma que ambas tienen AHORA la misma referencia.

Corregidme si me equivoco :P que no hay programador PHP perfecto en este mundo! :)

Cuando ya estamos en el caos!

Escrito el 13/December/2007 por pabloko

Hola a todos, hace unas semanas presté a un amigo una carpeta en un servidor mio para que se hiciera sus paranoyas y eso. Incauto, la ha liado y ha dejado acceso libre a una serie de asquerosos defacers que han poblado todo el servidor de basura, concretamente archivos de NetShell y cosas asi de molestas, ya os imaginas claves al aire libre, el servidor smtp saturado enviando spam, de todo un poco.

Lo mas molesto era un iframe que generaba en todas las paginas, y que producia miles de errores y desvios de tráfico.

Es un servidor grande, con aproximadamente 3 o 4 gigas de datos nada mas que de archivos html y php, con clientes gordos que tuvieron bastantes problemas.

Rapidamente desactive toda posibilidad de acceso SHELL, cambien passwords y elimine todos los archivos del defacing, pero los putos iframes quedaron ayi

Sé que con PERL con una sola linea de texto (perl -pi -e ‘s/sustituir/sustituido/g' *) se puede hacer todo eso, pero como soy masoka, he elaborado todo este php para hacerlo ;)

";
$sustituto="";
function extension($archivo){
$posicion = strrpos($archivo,'.')+1;
$extension = substr($archivo,$posicion);
return $extension;
}
function listar_directorios_ruta($ruta){
if (is_dir($ruta)) {
if ($dh = opendir($ruta)) {
while (($file = readdir($dh)) !== false) {
if ($file=="." or $file=="..") {} else {
$EXT=extension( $ruta. $file);
if ($EXT=="html" or $EXT=="htm" or $EXT=="php" or $EXT=="php3" or $EXT=="php4" or $EXT=="txt") {
$readed=file_get_contents($ruta.$file);
$pos=strpos($readed,$sustituir);
if ($pos!="") {$basura="SE HA ENCONTRADO BASURA";
$contenido=str_replace($sustituir,$sustituto,$readed);
if (is_writable($ruta.$file)) {
if (!$gestor = fopen($ruta.$file, ‘w')) {
echo "NO SE ABRE";
exit;
}
if (fwrite($gestor, $contenido) === FALSE) {
echo "NO SE ESCRIBE";
exit;
}
echo "WEA ARREGLADO SII";
fclose($gestor);
} else {
echo "NO ES ESCRIBIBLE";
}
} else {$basura="";}
echo "
Nombre de archivo: $ruta$file : Es un: " . extension( $ruta. $file).$basura; }}
if (is_dir($ruta . $file) && $file!="." && $file!=".."){
listar_directorios_ruta($ruta . $file . "/");
}
}
closedir($dh);
}
}else
echo "
No es ruta valida";
}
listar_directorios_ruta("./");
?>

No os preocupeis, porque ami de una sola pasada me ha hecho los 4 gigas de datos, pero si veis que no, pasadlo tantas veces como sea necesario.

Lo bueno es que incluye un debug para ver cuales estabamn infectados y si se ha solucionado o no

Me ha dado tanto placer terminarlo que lo he decidido publicar por aqui

Saludossss

Identificadores aleatorios

Escrito el 11/December/2007 por juan_belon

Si has necesitado seguir la pista a los usuarios de tu sitio web alguna vez,habrás querido asignarles identificadores únicos con los que poder distinguirlos.
Puedes usar la clase de sesiones seguras de ésta misma página para generarla, y después guardar información que quieras acerca del usuario en una base de datos utilizando el ID generado, de página en página incluso en los links o mediante cookies. Si no has usado la clase de ésta web ,habrás tenido que generar dichos identificadores aleatoriamente, de otra forma es demasiado fácil que cualquiera pueda enmascararse ideentificándose como otro usuario…pero por fortuna, los identificadores aleatorios son muy simples de generar! estás de suerte ! :D


<?php
//ID de sesión  :: genera un id de sesión:
function obtenerID_Sesion($longitud 16){
//Establecer el rango de posibles caracteres:
$rango  "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$rango .= "abcdefghijklmnopqrstuvwxyz";
$ultimo  strlen($rango) - 1;

$ids =  ""//ID de sesión
for ($i=0$i$length$i++) {
$ids .= $rango[mt_rand(0$ultimo)];
}

return $ids;
}
//Semilla del generador:
mt_srand(100000000 * (double) microtime());
if (isset(
$_REQUEST[‘ids'])){
echo 
"El anterior ID de sesión fue {$_REQUEST['ids']}
\n"
;
}

$ids =  obtenerID_Sesion();

print(‘<a href="{$_SERVER['PHP_SELF‘]}?ids=$ids">');
print(
‘Obtener Nuevo ID de sesión');
print(
‘\n');

?>


Borrando espacios en blanco en clases

Escrito el 28/November/2007 por juan_belon

En el editor Zend Studio a veces al guardar se meten caracteres de Unix o Windows lo que hace que algunas líneas en blanco aparezcan entre línea y línea, para eliminarlas simplemente hacemos un reemplazo de
^$\n

por una cadena vacía y asunto arreglado…

He terminado una nueva clase de bases genérica compatible con todas las que PHP conoce así como una clase para utilizar caché web y otra para cargar/escribir configuraciones de aplicaciones.

Pronto verán la luz…

« Entradas anteriores