Category Archives: php

Generar un zip de backup del servidor FTP

basandome en el código
he modificado la clase para añadirle seguridad (*):

Para ello partimos de una estructura de servidor:

Donde colocamos el fichero zip.php en el raiz

Dentro del fichero configuramos la ruta donde se van a guardar los archivos y las exclusiones que queremos hacer, en este caso los directorios dir2 y dir4 y el propio fichero de generar el zip.

Una vez que invocamos el fichero desde navegador


obtenemos un zip como:


<?php
	//funciones
	function show($str){
		echo $str . "<br/>\n";
		flush();
		ob_flush();
	}
	function secured($nombre,$directorio){
		return str_replace($directorio."/backup",$directorio."/secured_backup",$nombre);
	}
	
	//configuracion
	ini_set('max_execution_time', 5000);
	$maxFilePerArchive = 20000;
	$directorio="zipBk";
	$debug=false;
	//directorios y ficheros que no quieres que se añadan al archivo
	$excludes=array("dir2","dir4","zip.php");
	
	
	//parametros recibidos
	if (isset($_REQUEST['pass'])){
		$password=$_REQUEST['pass'];
	}else{
		$password="";
	}
	if (isset($_REQUEST['delete'])){
		$delete=true;
	}else{
		$delete=false;
	}
	if (isset($_REQUEST['ver'])){
		$ver=true;
	}else{
		$ver=false;
	}
	if (isset($_REQUEST['dias'])){
		$dias=$_REQUEST['dias'];
	}else{
		$dias=2;
	}
	if (isset($_REQUEST['help'])){
		show("Puedes pasar los parametros<br>
		<strong>pass</strong> Para poner password al zip<br>
		<strong>ver</strong> Para ver los archivos que son, pero sin crear el zip<br>
		<strong>delete</strong> Para borrar los archivos zip anteriores, se puede pasar un parametro dias ( indicando el numero de dias de margen para borrar )<br>
		");
		die;
	}
	
	// increase script timeout value
	
	if ($directorio!="" && $directorio!="." && !file_exists($directorio)) {
		mkdir($directorio, 0777, true);
		if($debug){show("Se ha creado el directorio $directorio porque no existia");}
	}
	if ($delete){
		
		show("Borramos los archivos anteriores a 2 dias");
		$ficheros=0;
		$borrados=0;
		$ahora=time();
		foreach (glob($directorio."/*.zip") as $file) {
			if (is_file($file)){
				$ficheros++;
				
				if ($ahora - filemtime($file) >= 60*60*24*$dias){ // 1 days
					$borrados++;
					echo $file;
					unlink($file);
				}
				echo "<br>";
			}
		}
		show("Hemos borrado $borrados archivos");die;
	}
	
	$numFiles = 0;
	$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator("./"));
	foreach ($iterator as $key=>$value){
		$key=substr($key,2,strlen($key)-1);
		if (! preg_match('/'.$directorio.'\/backup_'.'/', $key) && !preg_match('/'.$directorio.'\/secured_backup_'.'/', $key)){
			if (!(substr($key,-2)==".." || substr($key,-1)==".")){
				if ($excludes){
					$puede=true;
					foreach ($excludes as $exclude)
					{
						if (preg_match('/^'.$exclude.'/', $key))
						{
							$puede = false;
						} 
					}
				}else{
					$puede=true;
				}
				if ($puede){
					$numFiles += 1;
					if ($ver){
						show("Se insertara el archivo $key");
					}
				}
			}
		}
	}
	show( "Comprimiremos $numFiles archivos" );
	if (!$ver){
		$date = getdate();
		$enlaces=array();
		$splitNum = 0;
		$archive = $directorio."/backup_" . $date[0];
		$currentArchive = $archive . "_" . $splitNum . ".zip";
		$enlaces[]=$currentArchive;
		$zip = new ZipArchive();
		if ($zip->open($currentArchive, ZIPARCHIVE::CREATE) !== TRUE) {
			die ("No se puede abrir el archivo");
		}
		
		
		$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator("./"));
		$numFiles = 0;
		$counter = 0;
		
		foreach ($iterator as $key=>$value){
			$counter += 1;
			if ($counter >= $maxFilePerArchive) {
				$zip->close();
				if ($password!=""){
					try{
						system('zip -P '.$password.' '.secured($currentArchive).' '.$currentArchive);
						unlink($currentArchive);
					}catch(Exception $ex){
					
					}
				}
				$currentArchive = $archive . "_" . $splitNum++ . ".zip";
				$enlaces[]=$currentArchive;
				show( "Limite de ficheros: partimos el archivo, Nuevo archivo es $currentArchive" ); 
				
				$zip = new ZipArchive();
				if ($zip->open($currentArchive, ZIPARCHIVE::CREATE) !== TRUE) {
					die ("No se puede crear el archivo");
				}
				
				$counter = 0;
			}
			$key=substr($key,2,strlen($key)-1);
			if (! preg_match('/'.$directorio.'\/backup_'.'/', $key) && !preg_match('/'.$directorio.'\/secured_backup_'.'/', $key)){
				if (substr($key,-2)==".." || substr($key,-1)=="."){
					if ($debug){show( "Excluimos $key" );}
				}else{
					if ($excludes){
						$puede=true;
						foreach ($excludes as $exclude)
						{
							if (preg_match('/^'.$exclude.'/', $key))
							{
								$puede = false;
							} 
						}
					}else{
						$puede=true;
					}
					if ($puede){
						$zip->addFile(realpath($key), $key) or die ("ERROR: No se puede añadir el fichero: $key");
						$numFiles += 1;
						if ($debug){show( "Añadimos $key" );}
					}
				}
				
			} else {
				if($debug){show( "No se comprime el archivo,por ser una copia previa-> $key" );}
			}
		}
		// close and save archive
		$zip->addFromString("LEEME_".time().".txt", "#1 Fichero generado automaticamenta\nPor un proceso para realizar backup de todo el FTP. ");
		$zip->close();
		if ($password!=""){
			try{
				system('zip -P '.$password.' '.secured($currentArchive).' '.$currentArchive);
				unlink($currentArchive);
			}catch(Exception $ex){
			
			}
		}
		
		if ($password=="" ){
			show( "El fichero no tiene clave, llama al script pasando el parametro ?pass=xxxx para mayor seguridad" );
		}
		if ($password!=""){$enlaces=secured($enlaces);}
		echo "<br>";
		if($enlaces){
			foreach($enlaces as $enlace){
				if (file_exists($enlace)){
					echo "<a href='".$enlace."'>".$enlace."</a><br>";
				}else{
					echo "No se pudo generar el fichero $enlace <br>";
				}
			}
		}
	}
?>

(*) Como la clase ZipArchive de php no soporta clave, se genera un segundo zip mediante llamada al sistema operativo que si que pone contraseña al original y lo borra.

Corregir fallo prestashop 1.7 carousel

Una vez que he instalado prestashop 1.7 y accedo a la tienda veo que el componente carousel que viene con el tema por defecto no tiene enlace

Aunque en la parte de administración veo que si que está definido:

 

Para arreglarlo es necesario modificar el fichero:

themes/classic/modules/ps_imageslider/views/templates/hook/slider.tpl

Añadiendo el elemento a, dentro de figure:

Una vez hecho, es necesario vaciar la caché para que podamos ver el resultado:

 

 

 

 

Pensando en cambiar de hosting

Será porque hoy es sábado y voy bien de tiempo con mis proyectos que tengo a medias, pero hoy me apetece escribir una entrada mas larga.

Llevo tiempo con mi pagina web en 1and1, y creo que es el momento de pensar si es el mejor hosting en el que puedo tener no solo el blog, sino todas las paginas correspondientes a mis aplicaciones móviles, tanto de IOS como de Android, ademas de aquellas necesarias para el correcto funcionamiento de varias aplicaciones que he desarrollado a lo largo de los años.

Ultimamente he desarrollado varias aplicaciones como Datercam para Android ( ya existía para IOS) que permite poner información como la fecha, la hora, las coordenadas gps y la ubicación ( obtenida mediante google ) a las fotos, para que no olvides cuando y donde hiciste una foto.

O mi ultima aplicación Emojime publicada hace 3 días, que permite coger una foto, bien sea de la cámara o del carrete, detectar las caras y cargar emoticonos de forma aleatoria, lo que permite “jugar” a encontrar la combinación de caras que mejor se adapte a la foto, una vez tienes el resultado puedes compartirla o guardarla.

Pero volviendo al tema con el que empece, últimamente he tenido problemas con mi pagina en 1and1, momentos en los que no puede acceder, errores internos del servidor ( que luego no dan mas información ) o simplemente que la velocidad no es la deseada.

A eso se junta que hace tiempo me cambiaron la tarifa de forma unilateral, después de 8 años con ellos ya no podían mantenerme el contrato que tenia con ellos, y me pasaban a uno superior ofreciendo cosas que no necesito y con ello un aumento de precio considerable.

Otro de los motivos por los que tengo que pensar en cambiar de hosting es que me gustaría que tuviera acceso a la base de datos de forma nativa mediante host y puerto, mientras que ahora solo puedo acceder mediante phpmyadmin una vez que me he logueado en el panel de control, lo que relentiza bastante el trabajo con base de datos.

Hace unos días que encontré un articulo  donde hablaban de tres hosting baratos y exponían una serie de pruebas que habian hecho para valorar cual era la mejor, los tres candidatos eran: Webempresa, Raiola y Sered, y las pruebas que realizaban eran: benchmark, velocidad de renderización, estabilidad del servidor o load impact entre otros.

Aquí me pilla de novato, pues no tenia ni idea de en que consistían muchas de las pruebas que se realizaban, pero me ha servido para aprender mas acerca de los pasos necesarios para que tu web esté en un hosting capaz de soportar cargas sin que el usuario se vea afectado. Es mas creo que estas pruebas pueden ser aplicadas en mi puesto de trabajo y se lo comentaré a la gente de sistemas para organizar un plan de actuación.

Aunque en el articulo si mostraban un ganador, como en casi todas las comparativas  cada una de ellas destacaba en algún punto por lo que el resultado no era fácil de determinar.

Como en el articulo no hablaban de si el acceso a base de datos era con phpmyadmin o si por el contrario permitían acceso directo no me queda mas remedio que preguntarlo directamente, recurro a llamar por teléfono y quedo a la espera, en unos segundos me atiende un empleado muy amable que me responde a mi gran duda, y la respuesta es afirmativa, CPANEL permite habilitar conexión externa con la base de datos, por lo que acaba de convencerme para tomarlo como claro candidato a ser mi proximo hosting, a ver si el proximo post ya está ahí alojado.

 

 

Redirigir trafico de un dominio viejo a uno nuevo

Vamos a utilizar htaccess para que cualquier dirección del viejo dominio apunte al nuevo

RewriteEngine on
RewriteCond %{HTTP_HOST} ^viejodominio.com [NC,OR]
RewriteCond %{HTTP_HOST} ^www.viejodominio.com [NC]
RewriteRule ^(.*)$ http://www.nuevodominio.com [L,R=301,NC]

Si en el nuevo dominio la estructura es la misma que en el viejo, podemos hacer que la mantenga cambiando la ultima linea

RewriteRule ^(.*)$ http://www.nuevodominio.com/$1 [L,R=301,NC]

Y como bonus en el nuevo dominio vamos a hacer que cualquier dirección que no exista (Error 404) nos lleve a la pagina principal

ErrorDocument 404 /index.php

proteger un fichero php mediante usuario y clave

Para proteger un archivo vamos a utilizar .htaccess

<FilesMatch "fichero_a_proteger.php">
AuthName "Acceso restringido"
AuthType Basic
AuthUserFile  /ruta/absoluta/fichero/.htpasswd
require valid-user
</FilesMatch>

para ello tenemos que crear un fichero de claves .htpasswd

prueba:$apr1$sw7c8otq$YXGtq/vVLMc3jl4yOPCGt.

Lo podemos hacer desde esta pagina enlace

Y en el fichero htaccess tenemos que poner la ruta absoluta del servidor al archivo htpasswd, para ello podemos utilizar el codigo PHP siguiente:

$dir = dirname(__FILE__);
echo "Full path to this dir: " . $dir . "";

PHP y el error al restar fechas después del cambio de hora

partimos de una funcion en PHP que resta dias

function restadias($fecha,$dias){
	list( $dia, $mes, $year ) = split( '/', $fecha );
	//teniendo la fecha tenemos que obtener el lunes y el viernes de esa semana.
	$f=mktime(0 , 0, 0, (int)$mes  , (int)$dia, (int)$year);
	$sumadias=60*60*24*($dias);
	$l=$f-$sumadias;
		$dia1=date('j',$l);
	if ($dia1<10){
		$d="0".$dia1;
	}else{
		$d=$dia1;
	}
	$mes1=date('n',$l);
	if ($mes1<10){
		$m="0".$mes1;
	}else{
		$m=$mes1;
	}
	$year1=date('Y',$l);
	$nf   = $d."/".$m."/".$year1;
	
	return $nf;
}

Si vemos la función, lo que hace es partir la fecha de texto dd/mm/aaaa y obtener el valor en segundos con mktime, luego los días que va a restar los multiplica por el número de segundos del día y hace la resta, el resultado lo formatea otra vez en formato dd/mm/aaaa

Así para el ejemplo:

echo restadias("03/03/2016",1);

El resultado es o debería de ser 02/03/2016

Pero para restadias(“28/03/2016”,1) cuando debería de darnos el día 27 nos devuelve un fatídico 26/03/2016.


1459123200 - 86400  = 1459036800

Y todo por el cambio de hora, como la función realiza el mktime pasando 0 en horas, minutos y segundos, al restar 86400 segundos según la funcion $dia1=date(‘j’,$l)
Y lo vemos mejor viendo la hora:

date("H",$l);

Donde parte de las 0 y nos devuelve 23.

para solucionarlo, modificamos la función restadias por:

function restadias($fecha,$dias){
	list( $dia, $mes, $year ) = split( '/', $fecha );
	//teniendo la fecha tenemos que obtener el lunes y el viernes de esa semana.
	$f=mktime(12 , 0, 0, (int)$mes  , (int)$dia, (int)$year);
	$sumadias=60*60*24*($dias);
	$l=$f-$sumadias;
		$dia1=date('j',$l);
	if ($dia1<10){
		$d="0".$dia1;
	}else{
		$d=$dia1;
	}
	$mes1=date('n',$l);
	if ($mes1<10){
		$m="0".$mes1;
	}else{
		$m=$mes1;
	}
	$year1=date('Y',$l);
	$nf   = $d."/".$m."/".$year1;
	
	return $nf;
}

Donde hemos puesto como hora las 12, asi nos evitamos el problema del cambio de hora, de 2 a 3 de la mañana.

Cortar un texto para mandarlo por SMS sin cortar palabras

Vamos a preparar un script que nos trocea un texto en multiples SMS sin cortar palabras y añadiendo al final un contador de mensajes.

function ArrayTextosSMS($texto){
		$frases=array();
		$palabras=explode(" ",$texto);
		$frase="";
		$numpalabras=count($palabras);
		foreach($palabras as $palabra){
			$fraseadd=$frase." ".$palabra;
			if (strlen($fraseadd)&gt;150){
				array_push($frases,trim($frase));
				$frase=$palabra;
			}else{
				$frase=$frase." ".$palabra;
			}
		}
		if ($frase!=""){
			array_push($frases,trim($frase));
		}
		$numfrases=count($frases);
		//añadimos un contador
		if ($numfrases&gt;1){
			for($i=0;$i&lt;$numfrases;$i++){
					$j=$i+1;
				$frases[$i]=$frases[$i]." ($j/$numfrases)";
			}
		}
		return $frases;
		
	}

el ejemplo es:

$texto="Este es un texto muy largo que queremos mandar mediante SMS, para ello hemos creado un script que nos lo trocea en partes de 150 caracteres y ademas le añade un contador de numero de mensajes. Ahora hay que encontrar un proveedor que nos permita mandar los sms, a ser posible de manera gratuita, pero todavia no he dado con ello. Si algun dia lo encuentro, lo compartiré en este mismo hilo";

print_r(ArrayTextosSMS($texto));die;

Que nos da como resultado:

Array
(
    [0] =&gt; Este es un texto muy largo que queremos mandar mediante SMS, para ello hemos creado un script que nos lo trocea en partes de 150 caracteres y ademas (1/3)
    [1] =&gt; le añade un contador de numero de mensajes. Ahora hay que encontrar un proveedor que nos permita mandar los sms, a ser posible de manera gratuita, (2/3)
    [2] =&gt; pero todavía no he dado con ello. Si algún día lo encuentro, lo compartiré en este mismo hilo (3/3)
)

El código esta disponible tambien en JAVA