shell bypass 403
<?php
/**
* A partir de los XML de importación, carga los datos
* Desarrollado a partir de las versiones anteriores, corrigiendo algunos errores, mejorando el número de consultas,
* incluyendo el uso de una librería de conexión a la BD,...
*
* @author Víctor Velasco <v.velasco@interactivaclic.com>
* @version 1.0, 2017-11-03
*/
class Importador {
private $db; //Instancia de la clase Database
private $xml;
private $xmlFile;
private $provsBD = array();
private $pobsBD = array();
private $pobAreaBD = array();
private $tipologiasBD = array();
private $tiposInmBD = array();
private $zonasBD = array();
private $trazar = true;
private $time = 0;
private $idAgencia = 0;
private $gestiones = array(
'Vender' => 1,
'Alquilar' => 2,
'Traspasar' => 3,
'Vender o Alquilar' => 4,
'Vender o Traspasar' => 5, //Añadido 8/11/2017 - Víctor Velasco
'Temporada Alquiler' => 6, //Añadido 8/11/2017 - Víctor Velasco
'Traspasar o Alquilar' => 7 //Añadido 8/11/2017 - Víctor Velasco
);
//$archivos_xml = array(XML_FILE_ASOCIACION);
function __construct(Database $db) {
$this->db = $db;
$this->db->query("SET NAMES 'utf8'");
}
/**
* Carga las tablas de Inmuebles:
* Inmuebles, Inmuebles-Documentos e Inmuebles-Galerías
*/
public function inmuebles($idAgencia, $xmlFile, $trazar = true) {
$this->tiempo();
$this->trazar = $trazar;
$this->idAgencia = $idAgencia;
$this->xmlFile = $xmlFile;
$this->xml = new XMLReader();
$this->traza("<h1>Importación de inmuebles desde: $this->xmlFile</h1>");
$this->importInmuebles();
$this->tiempo(true);
}
private function importInmuebles() {
//Cargo los datos auxiliares a través del gestor de Inmuebles
$this->setDatosAuxiliares();
$this->xml->open($this->xmlFile);
$this->traza('<h2>Importando inmuebles...........</h2>');
$this->vaciaInmuebles();
/* Recorremos el xml en busca de todos los inmuebles */
$rootElement = 'propiedades';
$element = 'propiedad';
$inmuebles = array();
$total = 0;
while ($this->xml->read()) {
if ($this->xml->localName === $element && $this->xml->nodeType == XMLReader::ELEMENT) {
$inmueble = simplexml_load_string($this->xml->readOuterXml(), 'SimpleXMLElement', LIBXML_NOCDATA);
$inmueble_id = (string) $inmueble->id;
if (empty($inmuebles[$inmueble_id])) {
//Compruebo datos auxiliares
$procesados = $this->compruebaInmueble($inmueble);
if (!empty($procesados)) {
//Proceso el inmueble y lo intento insertar
$id_insertado = $this->procesaInmueble($inmueble, $procesados);
if ($id_insertado !== false) {
$inmuebles[$inmueble_id] = $id_insertado;
$total++;
// Galería del inmueble
$numFotos = (int) $inmueble->numfotos;
if ($numFotos > 0) {
$this->procesaFotos($inmueble, $numFotos, $id_insertado);
}
}
}
}
}
}
$this->traza("<p class='resumen'>Inmuebles insertados: $total</p>");
}
/**
* Carga los datos auxiliares para la validación y la carga.
*/
private function setDatosAuxiliares() {
$this->provsBD = $this->loadProvincias();
$this->pobsBD = $this->loadPoblaciones();
$this->tiposInmBD = $this->loadTiposInmueble();
$this->zonasBD = $this->loadZonas();
}
/**
* Comprueba que los datos relativos al inmueble que han de estar en las tablas auxiliares, están y son coherentes.
* Devuelve un array con lo procesado, para no repetir los cálculos.
* O false si no se cumplen las condiciones del inmueble.
*/
private function compruebaInmueble($inmueble) {
$identificacion = empty(trim($inmueble->ref)) ? $inmueble->id : $inmueble->ref;
//Provincia
if (empty(trim($inmueble->provincia))) {
$this->traza("<p class='error'>Datos erróneos en el XML. Inmueble: {$identificacion}. Dato: Provincia.</p>");
return false;
}
$provincia = $this->capitaliza((string) $inmueble->provincia);
if (empty($this->provsBD[$provincia])) {
$this->traza("<p class='error'>Hay que actualizar la tabla de provincias. Inmueble: {$identificacion}. Provincia: {$provincia}.</p>");
return false;
}
$id_provincia = $this->provsBD[$provincia];
//Población
if (empty(trim($inmueble->ciudad))) {
$this->traza("<p class='error'>Datos erróneos en el XML. Inmueble: {$identificacion}. Dato: Población.</p>");
return false;
}
$poblacion = $this->capitaliza((string) $inmueble->ciudad);
if (empty($this->pobsBD[$poblacion]) || $this->pobsBD[$poblacion]['id_provincia'] != $id_provincia) {
$this->traza("<p class='error'>Hay que actualizar la tabla de poblaciones. Inmueble: {$identificacion}. Población: {$poblacion}.</p>");
return false;
}
$id_poblacion = $this->pobsBD[$poblacion]['id'];
$id_area = $this->pobsBD[$poblacion]['id_area']; //Asumo que está bien la zona tal cual sale de las poblaciones
//Tipo de Inmueble
if (empty(trim($inmueble->tipo_ofer))) {
$this->traza("<p class='error'>Datos erróneos en el XML. Inmueble: {$identificacion}. Dato: Tipo de Inmueble (tipo_ofer).</p>");
return false;
}
$nombre_tipo_inmueble = $this->capitaliza((string) $inmueble->tipo_ofer);
if (empty($this->tiposInmBD[$nombre_tipo_inmueble])) {
$this->traza("<p class='error'>Hay que actualizar la tabla de Tipos de inmueble. Inmueble: {$identificacion}. Tipo de inmueble: {$nombre_tipo_inmueble}.</p>");
return false;
}
$id_tipo_inmueble = $this->tiposInmBD[$nombre_tipo_inmueble]['id'];
//Zona: Esta puede llegar vacía y no es error
if (empty(trim($inmueble->zona))) {
$this->traza("<p class='aviso'>Aviso: Falta <b>ZONA</b> en el XML. Inmueble: {$identificacion}.<br><em>*El inmueble se insertará sin zona</em></p>");
$id_zona = 0;
$nombre_zona = '';
} else {
$nombre_zona = $this->capitaliza($inmueble->zona);
if (empty($this->zonasBD[$nombre_zona])) {
$this->traza("<p class='error'>Hay que actualizar la tabla de Zonas. Inmueble: {$identificacion}. Zona: {$nombre_zona}.</p>");
return false;
}
$id_zona = $this->zonasBD[$nombre_zona];
}
//Devuelvo los datos procesados, para no repetirlo
$procesado = array(
'nombre_provincia' => $provincia,
'id_provincia' => $id_provincia,
'nombre_poblacion' => $poblacion,
'id_poblacion' => $id_poblacion,
'id_area' => $id_area,
'id_tipo_inmueble' => $id_tipo_inmueble,
'nombre_tipo_inmueble' => $nombre_tipo_inmueble,
'id_zona' => $id_zona,
'nombre_zona' => $nombre_zona
);
return $procesado;
}
/**
* Para un inmueble, asocia los datos y los carga en la BD
*/
private function procesaInmueble($inmueble, $procesado) {
//Datos intermedios
$gestion = (string) $inmueble->accion;
$id_gestion = empty($this->gestiones[$gestion]) ? 0 : $this->gestiones[$gestion];
$tipo_mensualidad = ($id_gestion == 2 || $id_gestion == 4 || $id_gestion == 6 || $id_gestion == 7) ? 'MES' : '';
$latitud = $this->formatCoord($inmueble->latitud);
$longitud = $this->formatCoord($inmueble->altitud);
$m2cons = $this->getInt($inmueble->m_cons, 2);
$m2utiles = $this->getInt($inmueble->m_uties, 2);
$m2sup = $this->getInt($inmueble->m_parcela, 2);
$superficie = max($m2utiles, $m2cons);
$habitaciones = $this->getInt($inmueble->habitaciones) + $this->getInt($inmueble->habdobles);
if ($superficie == 0) {
$superficie = $m2sup;
}
$certificado = '';
$certificadoRecibido = $this->getInt($inmueble->energiarecibido);
if ($certificadoRecibido == 1) {
$certificado = (string) $inmueble->energialetra;
} else {
$certificados = array(
0 => 'PENDIENTE',
2 => 'TRAMITES',
3 => 'EXENTO'
);
$certificado = empty($certificados[$certificadoRecibido]) ? 0 : $certificados[$certificadoRecibido];
}
$ahora = date("Y-m-d H:i:s");
//Datos a insertar en BD
$data = array(
'id' => (string) $inmueble->id,
'id_cliente' => 0,
'mi_agencia' => ((int) $inmueble->numagencia == $this->idAgencia) ? 1 : 0,
'urbaniza' => 0,
'mls' => 'inmovilla',
'referencia_unica' => (string) $inmueble->id,
'referencia' => (string) $inmueble->ref,
'id_promocion' => 0,
'id_pais' => 1,
'id_provincia' => $procesado['id_provincia'],
'id_area' => $procesado['id_area'],
'id_poblacion' => $procesado['id_poblacion'],
'id_zona' => $procesado['id_zona'],
'nombre_tipo_inmueble' => $procesado['nombre_tipo_inmueble'],
'id_tipo_inmueble' => $procesado['id_tipo_inmueble'],
'id_tipo_via' => 0,
'direccion_calle' => '',
'direccion_numero' => '',
'direccion_piso' => '',
'direccion_letra' => '',
'direccion_escalera' => '',
'cp' => (string) $inmueble->cp,
'id_gestion' => $id_gestion,
'precio_venta' => ((int) $inmueble->precioinmo > 0 ? $this->getInt($inmueble->precioinmo, 2) : 0),
'precio_alquiler' => ((int) $inmueble->precioalq > 0 ? $this->getInt($inmueble->precioalq, 2) : 0),
'precio_anterior' => ((int) $inmueble->outlet > 0 ? $this->getInt($inmueble->outlet, 2) : 0),
'tipo_mensualidad' => $tipo_mensualidad,
'habitaciones' => $habitaciones,
'banos' => (string) $inmueble->banyos,
'aseos' => (string) $inmueble->aseos,
'superficie' => $superficie,
'superficie_util' => $m2utiles,
'superficie_construida' => $m2cons,
'superficie_terreno' => $m2sup,
'latitud' => $latitud,
'longitud' => $longitud,
'map_point' => "Point($latitud , $longitud)",
'nuevo' => ((!empty($inmueble->conservacion) && (int) $inmueble->conservacion[1] > 60) ? 1 : 0),
'garaje' => (string) $inmueble->plaza_gara,
'calefaccion' => (string) $inmueble->calefaccion,
'aire_acondicionado' => (string) $inmueble->aire_con,
'piscina' => (intval((string) $inmueble->piscina_prop) == 0 ? (intval((string) $inmueble->piscina_com) == 0 ? 0 : 1) : 1),
'jardin' => ((int) $inmueble->jardin > 0 ? (string) $inmueble->jardin : 0),
'trastero' => (string) $inmueble->trastero,
'ascensor' => (string) $inmueble->ascensor,
'terraza' => (string) $inmueble->terraza,
'descripcion' => (string) $inmueble->descrip1,
'anyo_construccion' => 0,
'observaciones' => '',
'activa' => 1,
'banco' => (int) $inmueble->entidadbancaria,
'eficiencia_energetica' => $certificado,
'reservado' => 0,
'destacado' => (int) $inmueble->destacado,
'visitas' => 0,
'nfotos' => (int) $inmueble->numfotos,
'cod_ofer' => (string) $inmueble->cod_ofer,
'estadoficha' => (int) $inmueble->estadoficha,
'keyacci' => (int) $inmueble->keyacci,
'numsucursal' => ((int) $inmueble->numsucursal > 0 ? (string) $inmueble->numsucursal : null),
'url' => $this->getUrlInmueble(
$procesado['nombre_tipo_inmueble'],
$procesado['nombre_zona'],
$procesado['nombre_poblacion'],
$procesado['nombre_provincia'],
$habitaciones,
(string) $inmueble->ref
),
'created' => $ahora,
'modified' => $ahora
);
//Preparo los datos para inserción
$campos = array();
$valores = array();
foreach ($data as $indice => $valor) {
$campos[] = $indice;
$valores[] = ($indice == 'map_point') ? $valor : $this->db->quote($valor);
}
$c = implode(',', $campos);
$v = implode(',', $valores);
$sql = "INSERT INTO inmuebles ($c) VALUES ($v)";
if ($this->db->query($sql)) {
return $this->db->insert_id();
} else {
$error = $this->db->error();
$this->traza("<p class='error'>Error insertando inmueble {$inmueble->ref}. | <code>{$sql}</code> | Error: {$error}</p>");
return false;
}
}
/**
* Recorre el listado de fotos y lo inserta en la tabla de inmuebles_galeria
*/
private function procesaFotos($inmueble, $numFotos, $id_insertado) {
for ($i = 1; $i <= $numFotos; $i++) {
$principal = ($i == 1) ? 1 : 0;
$nodoFoto = "foto{$i}";
$url = (string) $inmueble->$nodoFoto;
$sql = "INSERT INTO inmuebles_galeria (id_inmueble,tipo,imagen,descripcion,url,principal,orden) VALUES ('$id_insertado','imagen','','','$url','$principal','$i')";
if (!$this->db->query($sql)) {
$this->traza("<p class='error'>Error insertando imagen {$i} del inmueble con id {$id_insertado}.</p>");
}
}
}
/**
* Formatea coordenadas (latitud, longitud)
*/
private function formatCoord($x) {
return preg_replace('/([^0-9\.\-]+)/', '', str_replace(':', '', trim((string) $x)));
}
/**
* Genera la URL del inmueble concatenando los datos recibidos
*/
function getUrlInmueble($nombre_tipo_inmueble, $nombre_zona, $nombre_poblacion, $nombre_provincia, $habitaciones, $referencia) {
$url = '';
$temp = array();
$temp[] = $nombre_tipo_inmueble;
if (!empty($nombre_zona)) {
$temp[] = $nombre_zona;
}
$temp[] = $nombre_poblacion;
$temp[] = $nombre_provincia;
if (!empty($habitaciones) || $habitaciones != 0) {
$temp[] = $habitaciones . '-habitacion' . (($habitaciones > 1) ? 'es' : '');
}
$url .= implode('-', $temp);
if (!empty($referencia)) {
$url .= '_' . format_url($referencia);
}
return '/' . $this->getSlug($url);
}
/**
* Vacio: Inmuebles, Inmuebles-Documentos e Inmuebles-Galerías
*/
private function vaciaInmuebles() {
if (!$this->db->query('DELETE FROM inmuebles')) {
$this->traza('<p class="error">No se ha podido vaciar la tabla de inmuebles</p>');
}
if (!$this->db->query('DELETE FROM inmuebles_documentos')) {
$this->traza('<p class="error">No se ha podido vaciar la tabla de inmuebles_documentos</p>');
}
if (!$this->db->query('DELETE FROM inmuebles_galeria')) {
$this->traza('<p class="error">No se ha podido vaciar la tabla de inmuebles_galeria</p>');
}
}
/**
* Prepara la carga de las tablas auxiliares:
* Provincias, Poblaciones, Zonas y Tipos de Inmueble
*/
public function auxiliares($xmlFile, $trazar = true) {
$this->tiempo();
$this->trazar = $trazar;
$this->xmlFile = $xmlFile;
$this->xml = new XMLReader();
$this->traza("<h1>Importación de tablas auxiliares desde: $this->xmlFile</h1>");
$this->importAuxiliares();
$this->tiempo(true);
}
/**
* Los 4 procesos de importación:
* carga las tablas de Provincias, Poblaciones, Zonas y Tipos de Inmueble
*/
private function importAuxiliares() {
//1.- Cargo y actualizo las provincias
$this->provsBD = $this->importProvincias();
//2.1.- Cargo las áreas de las poblaciones
$this->pobAreaBD = $this->loadAreas();
//2.2.- Para cargar y actualizar las poblaciones, necesito asegurarme de que tengo áreas
if (!empty($this->pobAreaBD)) {
$this->pobsBD = $this->importPoblaciones();
} else {
$this->traza('<p>No se pueden importar las poblaciones porque no se han cargado sus áreas');
}
//3.- Borro y creo las zonas
$this->importZonas();
//4.1.- Cargo las tipologías para los tipos de inmueble
$this->tipologiasBD = $this->loadTipologias();
//4.2.- Cargo los tipos de Inmueble
$this->importTiposDeInmueble();
}
/**
* Introduce en la Base de Datos, las poblaciones que no están introducidas ya.
* Fuerza el valor del país a 1.
* A día de hoy (3/11/2017), el id_pais no se usa para nada.
* Devuelve un array con las provincias en mayúsculas como índice y el id como valor:
* $provsBD = array(
* 'CANTABRIA' => 1,
* 'BURGOS' => 2,
* ...
* )
* Este array incluye los datos que existían originalmente, más los cargados en esta ejecución.
*/
public function importProvincias() {
$this->xml->open($this->xmlFile);
$this->traza('<h2>Actualizando provincias...........</h2>');
//Cargo las provincias que ya tengo
$provsBD = $this->loadProvincias();
//En este array meteré las provincias que falten en la tabla "provincias"
$provincias = array();
/* Recorremos el xml en busca de todas las provincias */
$rootElement = 'propiedades';
$element = 'propiedad';
while ($this->xml->read()) {
if ($this->xml->localName == $element && $this->xml->nodeType == XMLReader::ELEMENT) {
$inmueble = simplexml_load_string($this->xml->readOuterXml(), 'SimpleXMLElement', LIBXML_NOCDATA);
$nombre = $this->capitaliza((string) $inmueble->provincia);
if (empty($provsBD[$nombre]) && empty($provincias[$nombre])) {
$provincias[$nombre] = $nombre;
}
}
}
$total = 0;
//Recorro el array de $provincias (las que faltan en la BD) y:
// - Las inserto en BD
// - Las añado al rray
if (!empty($provincias)) {
foreach ($provincias as $provincia) {
$sql = "INSERT INTO provincias (nombre,id_pais) VALUES ('{$provincia}', 1)";
if ($this->db->query($sql)) {
$this->traza("<p>Se ha insertado: <em>{$provincia}</em></p>");
$total++;
//Lo añado al array
$provsBD[$provincia] = $this->db->insert_id();
} else {
$this->traza("<p>Se ha producido un error al insertar: <em>{$provincia}</em> | <code>{$sql}</code></p>");
}
}
}
$this->traza("<p class='resumen'>Provincias insertadas: $total</p>");
return $provsBD;
}
/**
* Carga las provincias de la BD
*/
private function loadProvincias() {
$provsBD = array();
$resProvs = $this->db->query('SELECT id, nombre FROM provincias');
if ($resProvs) {
while ($rowProvs = $this->db->fetch($resProvs)) {
$provsBD[$this->capitaliza($rowProvs['nombre'])] = $rowProvs['id'];
}
}
return $provsBD;
}
/**
* Carga las provincias de la BD
* OJO: Si en el futuro hubiera diferentes poblaciones con el mismo nombre, tal como está hecho, fallaría
*/
private function loadPoblaciones() {
$pobsBD = array();
$resPobs = $this->db->query('SELECT * FROM poblaciones');
if ($resPobs) {
while ($rowPobs = $this->db->fetch($resPobs)) {
$pobsBD[$this->capitaliza($rowPobs['nombre'])] = array(
'id' => $rowPobs['id'],
'id_provincia' => $rowPobs['id_provincia'],
'id_area' => $rowPobs['id_area'],
'nombre' => $rowPobs['nombre'],
);
}
}
return $pobsBD;
}
/**
* Carga los tipos de inmueble de la BD
*/
private function loadTiposInmueble() {
$tiposInmBD = array();
$resTipos = $this->db->query('SELECT id, tipo_id, nombre FROM tipos_inmueble');
if ($resTipos) {
while ($rowTipos = $this->db->fetch($resTipos)) {
$tiposInmBD[$this->capitaliza($rowTipos['nombre'])] = array(
'id' => $rowTipos['id'],
'tipo_id' => $rowTipos['tipo_id'] //La tipología
);
}
}
return $tiposInmBD;
}
/**
* Carga las zonas de la BD
*/
private function loadZonas() {
$zonasBD = array();
$resZonas = $this->db->query('SELECT id, nombre FROM zonas');
if ($resZonas) {
while ($rowZonas = $this->db->fetch($resZonas)) {
$zonasBD[$this->capitaliza($rowZonas['nombre'])] = $rowZonas['id'];
}
}
return $zonasBD;
}
/**
* En la tabla "areas" están relacionadas las distintas áreas con los
* id's de las poblaciones (valor "ciudad" en el XML) de Inmovilla.
* Por ejemplo: La zona "Santander", está relacionada con 15099 (Santander), 952599 (Boo de Piélagos), etc.
*
* Aquí preparo un array que asocia el id de Inmovilla de una población, con el id de área de nuestra BD.
* Ejemplo:
* idPobArea = array(
* '15099' => 3,
* '952599' => 3,
* ...
* )
*
* Este array relacional es el que se devuelve.
* Se utilizará para cargar las poblaciones informando del área a la que pertenece cada una.
*/
private function loadAreas() {
$idPobArea = array();
//Cargo las áreas
$sqlAreas = 'SELECT id, nombre, localidades FROM areas';
$resAreas = $this->db->query($sqlAreas);
while ($rowAreas = $this->db->fetch($resAreas)) {
//$provsBD[$this->capitaliza($rowAreas['nombre'])] = $rowAreas['id'];
if (!empty($rowAreas['localidades'])) {
$idsPoblaciones = unserialize($rowAreas['localidades']);
$idArea = $rowAreas['id'];
foreach ($idsPoblaciones as $idPob) {
$idPobArea[$idPob] = $idArea;
}
}
}
return $idPobArea;
}
/**
* Carga las poblaciones que existen en la BD.
* Lee el XML e inserta o actualiza los datos de la BD: comprueba la capitalización de los nombres y el id_area
* Devuelve un array con las poblaciones con el formato:
* $pobsBD = array(
* 'Santander' => array(
* 'id' => 3,
* 'id_provincia' => 1,
* 'id_area' => 3,
* 'nombre' => 'Santander',
* 'provincia' => Cantabria
* ),
* ...
* )
*
* OJO: Si en el futuro hubiera diferentes poblaciones con el mismo nombre, tal como está hecho, fallaría
*/
public function importPoblaciones() {
$pobsBD = array();
$pobsNuevas = array();
$actualizarPobs = false;
$this->xml->open($this->xmlFile);
$this->traza('<h2>Actualizando poblaciones...........</h2>');
// Cargo las poblaciones que ya tengo y compruebo si se han de actualizar
$resPobs = $this->db->query('SELECT * FROM poblaciones');
if ($resPobs) {
while ($rowPobs = $this->db->fetch($resPobs)) {
$nombreCap = $this->capitaliza($rowPobs['nombre']);
$actualizar = false;
$id = $rowPobs['id'];
$nombre = trim($rowPobs['nombre']);
if ($nombre != $this->capitaliza($nombre)) {
//Si el nombre no está bien capitalizado, debo actualizar este campo
$actualizar = true;
$actualizarPobs = true;
$nombre = $this->capitaliza($nombre);
}
$pobsBD[$nombreCap] = array(
'id' => $id,
'id_provincia' => $rowPobs['id_provincia'],
'id_area' => $rowPobs['id_area'],
'nombre' => $nombre,
'actualizar' => $actualizar
);
}
}
// Recorremos el xml en busca de todas las poblaciones que no tenga cargadas
// También compruebo que los id_area coinciden con lo que tengo cargado
$rootElement = 'propiedades';
$element = 'propiedad';
while ($this->xml->read()) {
if ($this->xml->localName == $element && $this->xml->nodeType == XMLReader::ELEMENT) {
$inmueble = simplexml_load_string($this->xml->readOuterXml(), 'SimpleXMLElement', LIBXML_NOCDATA);
$nombrePob = $this->capitaliza((string) $inmueble->ciudad);
$idPobApi = (int) $inmueble->key_loca;
//Si no la tengo ya cargada o en la lista de nuevas, la añado
if (empty($pobsBD[$nombrePob]) && empty($pobsNuevas[$nombrePob])) {
$nombreProv = $this->capitaliza((string) $inmueble->provincia);
$idArea = empty($this->pobAreaBD[$idPobApi]) ? 0 : $this->pobAreaBD[$idPobApi];
$pobsNuevas[$nombrePob] = array(
'id' => null,
'id_provincia' => $this->provsBD[$nombreProv],
'id_area' => $idArea,
'nombre' => $nombrePob,
'actualizar' => false
);
$pobsBD[$nombrePob] = array(
'id' => 0,//Lo definiré tras la inserción
'id_provincia' => $this->provsBD[$nombreProv],
'id_area' => $idArea,
'nombre' => $nombrePob,
'actualizar' => false
);
} elseif (
(empty($this->pobAreaBD[$idPobApi]) && $pobsBD[$nombrePob]['id_area'] != 0) ||
(!empty($this->pobAreaBD[$idPobApi]) && $pobsBD[$nombrePob]['id_area'] != $this->pobAreaBD[$idPobApi])
) {
//Si el id_area no es el que corresponde, debo actualizar este campo en la BD
$actualizarPobs = true;
$id_area = empty($this->pobAreaBD[$id]) ? 0 : $this->pobAreaBD[$id];
$pobsBD[$nombrePob]['id_area'] = empty($this->pobAreaBD[$idPobApi]) ? 0 : $this->pobAreaBD[$idPobApi];
$pobsBD[$nombrePob]['actualizar'] = true;
}
}
}
//Inserciones: Nuevas poblaciones a la BD
$total = 0;
if (!empty($pobsNuevas)) {
foreach ($pobsNuevas as $pob) {
$sql = "INSERT INTO poblaciones (id_provincia,id_area,nombre) VALUES ({$pob['id_provincia']},{$pob['id_area']},'{$pob['nombre']}')";
if ($this->db->query($sql)) {
$this->traza("<p>Se ha insertado: <em>{$pob['nombre']}</em></p>");
$total++;
$pobsBD[$pob['nombre']]['id'] = $this->db->insert_id();
} else {
$this->traza("<p>Se ha producido un error al insertar: <em>{$pob['nombre']}</em>. | <code>{$sql}</code></p>");
}
}
}
$this->traza("<p class='resumen'>Poblaciones insertadas: $total</p>");
//Actualizaciones: Hay datos obsoletos que hay que actualizar (por capitalización del nombre o por la asociación con área)
$total = 0;
if ($actualizarPobs) {
foreach ($pobsBD as $pob) {
if ($pob['actualizar']) {
$sql = "UPDATE poblaciones SET id_area = {$pob['id_area']}, nombre = '{$pob['nombre']}' WHERE id = {$pob['id']}";
if ($this->db->query($sql)) {
$this->traza("<p>Se ha actualizado: <em>{$pob['nombre']}</em></p>");
$total++;
$pob['actualizar'] = false;
} else {
$this->traza("<p>Se ha producido un error al actualizar: <em>{$pob['nombre']}</em>. | <code>{$sql}</code></p>");
}
}
}
}
$this->traza("<p class='resumen'>Poblaciones actualizadas: $total</p>");
return $pobsBD;
}
/**
* Vacía las zonas y las recrea
*/
public function importZonas() {
$zonas = array();
$this->xml->open($this->xmlFile);
$this->traza('<h2>Actualizando zonas...........</h2>');
//Vacío las zonas
if (!$this->db->query('DELETE FROM zonas')) {
$this->traza('<p class="error">No se ha podido vaciar la tabla de zonas</p>');
}
// Busco las zonas en el XML
$rootElement = 'propiedades';
$element = 'propiedad';
while ($this->xml->read()) {
if ($this->xml->localName == $element && $this->xml->nodeType == XMLReader::ELEMENT) {
$inmueble = simplexml_load_string($this->xml->readOuterXml(), 'SimpleXMLElement', LIBXML_NOCDATA);
$nombre = $this->capitaliza((string) $inmueble->zona);
$poblacion = $this->capitaliza((string) $inmueble->ciudad);
$id_poblacion = $this->pobsBD[$poblacion]['id'];
if (!empty($nombre) && (empty($zonas[$nombre]) || (!empty($zonas[$nombre]) && $zonas[$nombre]['id_poblacion'] != $id_poblacion))) {
//Si no existe la zona en esa población, la añado a la lista
$zonas[$nombre] = array(
'nombre' => $nombre,
'id_poblacion' => $this->pobsBD[$poblacion]['id']
);
}
}
}
$total = 0;
if (!empty($zonas)) {
$total = 0;
foreach ($zonas as $zona) {
$sql = "INSERT INTO zonas (id_poblacion,nombre) VALUES ({$zona['id_poblacion']},'{$zona['nombre']}')";
if ($this->db->query($sql)) {
$this->traza("<p>Se ha insertado: <em>{$zona['nombre']}</em></p>");
$total++;
} else {
$this->traza("<p class='error'>Se ha producido un error al insertar: <em>{$zona['nombre']}</em>. | <code>{$sql}</code></p>");
}
}
}
$this->traza("<p class='resumen'>Zonas insertadas: $total</p>");
return $zonas;
}
/**
* La tabla "tipologias" agrupo en una categoría superior, los tipos de inmueble.
* Para mantener esta relación, cada tipología contiene un array serializado con los
* id's de los tipos (valor "key_tipo" en el XML) de Inmovilla.
* Por ejemplo: los tipos de inmueble "Casa", "Casa de Campo", "Casa de Pueblo",... pertenecen a la tipología "Casa".
*
* Aquí preparo un array que asocia el id de Inmovilla de un tipo de inmueble, con el id de la Tipología de nuestra BD.
* Ejemplo:
* idTipoInmueble = array(
* '199' => 8,
* '499' => 8,
* ...
* )
*
* Este array relacional es el que se devuelve.
* Se utilizará para cargar los tipos de inmueble informando de la tipología a la que pertenece cada uno.
*/
private function loadTipologias() {
//tipo_ofer
$idTipoInmueble = array();
//Cargo las áreas
$sqlTipologias = 'SELECT id, nombre, tipos FROM tipologias';
$resTipologias = $this->db->query($sqlTipologias);
while ($rowTipologias = $this->db->fetch($resTipologias)) {
if (!empty($rowTipologias['tipos'])) {
$idsTiposInm = unserialize($rowTipologias['tipos']);
$idTipologia = (int) $rowTipologias['id'];
foreach ($idsTiposInm as $tipoInmueble) {
$idTipoInmueble[$tipoInmueble] = $idTipologia;
}
}
}
return $idTipoInmueble;
}
/**
* Vacía los tipos de Inmueble y los recrea
*/
public function importTiposDeInmueble() {
$tipos_inmueble = array();
$this->xml->open($this->xmlFile);
$this->traza('<h2>Actualizando tipos_inmueble...........</h2>');
//Vacío los tipos de inmueble
if (!$this->db->query('DELETE FROM tipos_inmueble')) {
$this->traza('<p class="error">No se ha podido vaciar la tabla de tipos de inmueble</p>');
}
/* Recorremos el xml en busca de todos los tipos_inmueble */
$rootElement = 'propiedades';
$element = 'propiedad';
while ($this->xml->read()) {
if ($this->xml->localName == $element && $this->xml->nodeType == XMLReader::ELEMENT) {
$inmueble = simplexml_load_string($this->xml->readOuterXml(), 'SimpleXMLElement', LIBXML_NOCDATA);
if (!empty($inmueble->tipo_ofer) && !empty($inmueble->key_tipo)) {
$nombreTipoInmueble = $this->capitaliza((string) $inmueble->tipo_ofer);
if (empty($tipos_inmueble[$nombreTipoInmueble])) {
$slug = $this->getSlug($nombreTipoInmueble);
$inmovilla_id = (int) $inmueble->key_tipo;
$tipologia_id = empty($this->tipologiasBD[$inmovilla_id]) ? 0 : $this->tipologiasBD[$inmovilla_id];
$tipos_inmueble[$nombreTipoInmueble] = array(
'tipo_id' => $tipologia_id,
'nombre' => $nombreTipoInmueble,
'seo' => $slug,
'inmovilla_id' => $inmovilla_id,
);
}
} else {
$this->traza("<p class='error'>Error XML en {$inmueble}</p>");
}
}
}
$total = 0;
if (!empty($tipos_inmueble)) {
foreach ($tipos_inmueble as $t) {
$sql = "INSERT INTO tipos_inmueble (tipo_id, nombre, seo, inmovilla_id) VALUES ({$t['tipo_id']}, '{$t['nombre']}', '{$t['seo']}', {$t['inmovilla_id']})";
if ($this->db->query($sql)) {
$this->traza("<p>Se ha insertado: <em>{$t['nombre']}</em></p>");
$total++;
} else {
$this->traza("<p class='error'>Se ha producido un error al insertar: <em>{$t['nombre']}</em>. | <code>{$sql}</code></p>");
}
}
}
$this->traza("<p class='resumen'>Tipos de inmueble insertados: $total</p>");
}
private function getSlug($texto, $spacer = '-') {
$slug = trim($texto);
$slug = str_replace(array("á","à","ä","Á","À","Ä","ª"),"a",$slug);
$slug = str_replace(array("é","è","ë","É","È","Ë"),"e",$slug);
$slug = str_replace(array("í","ì","ï","Í","Ì","Ï"),"i",$slug);
$slug = str_replace(array("ó","ò","ö","Ó","Ò","Ö","º"),"o",$slug);
$slug = str_replace(array("ú","ù","ü","Ú","Ù","Ü"),"u",$slug);
$slug = str_replace(array("ñ","Ñ"),"n",$slug);
$slug = str_replace(array('"',"'","´","`"),'',$slug);
$slug = str_replace(array(",",".",";","¡","!","¿","?","(",")","/","\\"),$spacer,$slug);
$slug = str_replace(array("ç","Ç"),"c",$slug);
$slug = preg_replace("/[ \t\n\r]+/", $spacer, $slug);
$slug = preg_replace("/^[¡¿-]+/", "", $slug);
$slug = preg_replace("/[?!-]+$/", "", $slug);
$slug = str_replace(" ", $spacer, $slug);
$slug = str_replace(array("[","]"), "", $slug);
$slug = preg_replace("/[ -]+/", $spacer, $slug);
$slug = strtolower($slug);
return $slug;
}
/**
* Cada primera letra en mayúsculas.
* Uso esta función en conjunción con encode porque ucwords() no da el resultado deseado.
*/
private function capitaliza($valor) {
return mb_convert_case($this->limpiaErrores(trim($valor)), MB_CASE_TITLE);
}
/**
* Elimino o sustituyo caracteres que veo que recurrentemente llegan erroneos
*/
private function limpiaErrores($valor) {
$valor = str_replace(
array('ä', 'â', 'Â', 'Ä'),
array('a', 'a', 'A', 'A'),
$valor
);
$valor = str_replace(
array('ë', 'ê','Ê', 'Ë'),
array('e', 'e','E', 'E'),
$valor
);
$valor = str_replace(
array('î', 'Î'),
array('i', 'I'),
$valor
);
$valor = str_replace(
array('ã', 'ö', 'ô', 'Ã', 'Ö', 'Ô'),
array('ó', 'o', 'o', 'Ó', 'O', 'O'),
$valor
);
$valor = str_replace(
array('ü', 'û', 'Û', 'Ü'),
array('u', 'u', 'U', 'U'),
$valor
);
$valor = str_replace('*', '', $valor);
return $valor;
}
/**
* Extraigo el valor entero de un nodo.
* Compruebo que esté dentro del rango de enteros de MySQL.
* Si se sale, devuelvo 0 porque considero que es un dato erroneo.
* Si no tiene decimales:
* Valor máximo para un entero de 10m posiciones con signo en MySQL: -2147483648 / +2147483647
* Si tiene decimales, 10 posiciones rellenas de "9" a las que quito las posiciones decimales
* Ejemplo con 2 decimales: 99999999.99
*/
private function getInt($valor, $decimalesCampo = 0) {
$v = intval(trim((string) $valor));
if ($decimalesCampo == 0) {
if ($v > 2147483647 || $v < -2147483648) {
return 0;
}
} else {
$max = 9999999999 / pow(10, $decimalesCampo);
if ($v >= $max || $v <= -($max-1)) {
return 0;
}
}
return $v;
}
/**
* Si está establecido que hay trazas, imprimo el mensaje que recibo en el documento.
*/
public function traza($html) {
if ($this->trazar) {
echo $html;
}
}
/**
* Mide el tiempo de un proceso.
* Al llamarlo con false, marca el inicio.
* Al llamarlo con true, marca el fin y lo imprime.
*/
private function tiempo($fin = false) {
if (!$fin) {
//Inicio
$this->time = microtime(true);
} else {
//Fin
$time_end = microtime(true);
$duration = $time_end - $this->time;
$mm = (int) ($duration / 60);
$ss = (int) $duration - $mm * 60;
$this->traza("<p class='tiempo'>Duración del proceso: {$mm} minutos, {$ss} segundos.</p>");
}
}
}
?>