diff --git a/.gitignore b/.gitignore index 4e4a072..0e827d0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ nbproject tmp/* .DS_Store +/img.data/ \ No newline at end of file diff --git a/AportaContenido.php b/AportaContenido.php index 0b38bcb..ab60c27 100644 --- a/AportaContenido.php +++ b/AportaContenido.php @@ -124,14 +124,14 @@ class AportaContenido { public function __call($metodo, $parametros) { switch ($metodo) { // Dependiendo del método invocado case 'titulo': // devolvemos el título - return PROGRAMA.VERSION; + return PROGRAMA." v".VERSION; case 'usuario': if ($this->registrado) return "Usuario=$this->usuario"; else return ''; case 'fecha': return $this->fechaActual(); - case 'aplicacion': return PROGRAMA.VERSION; + case 'aplicacion': return PROGRAMA." v".VERSION; case 'menu': // el menú if ($this->registrado) { return $this->miMenu->insertaMenu(); @@ -187,7 +187,7 @@ class AportaContenido { case 'ubicaciones': case 'test': case 'elementos': - $this->cargaDatosURL(); + $this->DatosURL(); if ($this->datosURL['opc'] == "informe") { if (!$this->pefil['Informe']) { $this->procesaURL(); @@ -284,31 +284,19 @@ class AportaContenido { } case 'copiaseg': if ($this->perfil['Config']) { - $archivo_sql = "tmp/copiaseg.sql"; - $archivo = $archivo_sql . ".gz"; - if (file_exists($archivo)) { - unlink($archivo); - } - $comando = escapeshellcmd(MYSQLDUMP . ' -h ' . SERVIDOR . ' -P ' . PUERTO . ' -u ' . USUARIO . ' --password=' . CLAVE . ' --result-file=' . $archivo_sql . ' ' . BASEDATOS); - $comando2 = escapeshellcmd(GZIP . ' -9f ' . $archivo_sql); - exec($comando); - exec($comando2); - if (filesize($archivo) < 1024) { - //No se ha realizado la copia de seguridad - $mensaje = "La copia de seguridad no se ha realizado correctamente.

"; - $mensaje .= "Compruebe que las rutas a los programas mysqldump y gzip en configuración están correctamente establecidas "; - $mensaje .= "y que los datos de acceso a la base de datos sean correctos.
"; - $mensaje .= "mysqldump=[" . MYSQLDUMP . "]
"; - $mensaje .= "gzip=[" . GZIP . "]"; - $cabecera = "ERROR"; - $tipo = "danger"; + $copia = new CopiaSeguridad(); + if ($_GET['confirmado'] == "1") { + if (!$copia->creaCopia()) { + $tipo = "danger"; + $cabecera = "ERROR"; + } else { + $tipo = "info"; + $cabecera = "INFORMACIÓN"; + } + return $this->panel($cabecera, $copia->mensaje(), $tipo); } else { - $mensaje .= 'Copia de seguridad realizada con éxito.

Pulse sobre el siguiente enlace para descargar:

'; - $mensaje .= 'Descargar Copia de Seguridad de Datos
'; - $cabecera = "Información"; - $tipo = "success"; + return $copia->dialogo(); } - return $this->panel($cabecera,$mensaje,$tipo); } else { return $this->mensajePermisos("Copias de seguridad"); } diff --git a/CopiaSeguridad.php b/CopiaSeguridad.php new file mode 100644 index 0000000..db5941f --- /dev/null +++ b/CopiaSeguridad.php @@ -0,0 +1,131 @@ +. + * + */ +class CopiaSeguridad { + private $mensaje; + private $baseDatos; + private $imagenes; + + public function __construct() + { + $opcion = $_GET['opc']; + } + public function creaCopia() + { + if (!$this->copiaBaseDatos()) { + return false; + } + if (!$this->copiaImagenes()) { + return false; + } + if (!$this->empaqueta()) { + return false; + } + return true; + } + public function dialogo() + { + $dialogo = '
+

Copia de Seguridad

+

¿Desea realizar una copia de seguridad de todos los datos de la Base de Datos y de todas las Imágenes?

+

Volver + Continuar

+
'; + return $dialogo; + } + private function copiaBaseDatos() + { + $archivo_sql = "tmp/baseDatos" . BASEDATOS . ".sql"; + $baseDatosComprimida = $archivo_sql . ".gz"; + $this->baseDatos = $baseDatosComprimida; + if (file_exists($baseDatosComprimida)) { + unlink($baseDatosComprimida); + } + $comando = escapeshellcmd(MYSQLDUMP . ' -h ' . SERVIDOR . ' -P ' . PUERTO . ' -u ' . USUARIO . ' --password=' . CLAVE . ' --result-file=' . $archivo_sql . ' ' . BASEDATOS); + $comando2 = escapeshellcmd(GZIP . ' -9f ' . $archivo_sql); + exec($comando); + exec($comando2); + if (filesize($baseDatosComprimida) < 1024) { + //No se ha realizado la copia de seguridad + $mensaje = "La copia de seguridad no se ha realizado correctamente.

"; + $mensaje .= "Compruebe que las rutas a los programas mysqldump y gzip en configuración están correctamente establecidas "; + $mensaje .= "y que los datos de acceso a la base de datos sean correctos.
"; + $mensaje .= "mysqldump=[" . MYSQLDUMP . "]
"; + $mensaje .= "gzip=[" . GZIP . "]"; + $this->mensaje = $mensaje; + $this->error = true; + return false; + } + return true; + } + private function copiaImagenes() + { + $copiaImagenes = "tmp/Imagenes.tbz"; + $this->imagenes = $copiaImagenes; + if (file_exists($copiaImagenes)) { + unlink($copiaImagenes); + } + $comando = escapeshellcmd('tar cf ' . $copiaImagenes . ' ' . IMAGEDATA); + exec($comando); + + if (filesize($copiaImagenes) == 0) { + $this->error = true; + $mensaje = "No se ha podido comprimir el directorio de las imágenes " . IMAGEDATA . "
"; + $mensaje .= "Compruebe que la ruta de acceso al programa tar en configuración está correctamente establecida"; + $this->mensaje = $mensaje; + return false; + } + return true; + } + private function empaqueta() + { + // Empaqueta los dos archivos en el que va a devolver + $nombreCopia = "tmp/Copia" . BASEDATOS . strftime("%Y%m%d%H%M") . ".tar"; + if (file_exists($nombreCopia)) { + unlink($nombreCopia); + } + $comando = escapeshellcmd('tar cf ' . $nombreCopia . ' ' . $this->baseDatos . ' ' . $this->imagenes); + exec($comando); + if (filesize($nombreCopia) ==0 || !file_exists($nombreCopia)) { + $this->error = true; + $mensaje = "No se ha creado el paquete con los archivos de imágenes en [" . $this->imagenes . "] y
"; + $mensaje .= " con el archivo de Base de Datos [" . $this->baseDatos . "]

"; + $mensaje .= "Compruebe que los datos de configuración están correctamente establecidos
"; + $mensaje .= "El comando de copia fue [" . $comando . "]
"; + $mensaje .= "gzip=[" . GZIP . "]"; + $this->mensaje = $mensaje; + return false; + } + $this->error = false; + unlink ($this->baseDatos); + unlink ($this->imagenes); + $mensaje = 'Copia de seguridad realizada con éxito.

Pulse sobre el siguiente enlace para descargar:

'; + $mensaje .= 'Descargar Copia de Seguridad de Datos

'; + $mensaje .= 'El paquete de copia contiene un archivo con la copia de la información de la base de datos y un archivo que contiene el directorio de las fotografías e imágenes asociadas a los datos'; + $this->mensaje = $mensaje; + return true; + } + public function mensaje () + { + return $this->mensaje; + } +} + +?> diff --git a/Distribucion.php b/Distribucion.php index fb50160..80822b6 100644 --- a/Distribucion.php +++ b/Distribucion.php @@ -70,7 +70,7 @@ class Distribucion { // if(strstr($_SERVER['HTTP_ACCEPT_ENCODING'],'gzip')) { // // introducimos la cabecera que indica que el contenido está comprimido // header('Content-Encoding: gzip'); -// // y comprime al m�ximo la información antes de enviarla +// // y comprime al máximo la información antes de enviarla // return gzencode($pagina, 9); // } return $pagina; // enviamos sin comprimir diff --git a/Imagen.php b/Imagen.php new file mode 100644 index 0000000..fa268b9 --- /dev/null +++ b/Imagen.php @@ -0,0 +1,170 @@ +. + * + */ +//Para comprimir las imágenes +require_once('Zebra_Image.php'); +define("HAYQUEGRABAR", 1); +define("HAYQUEBORRAR", 2); +define("NOHACERNADA", 3); + +class Imagen { + private $archivoSubido; + public $archivoComprimido; + private $extension; + private $dirData; + + public function __construct() + { + $this->dirData = IMAGEDATA; + } + + public function determinaAccion($campo) + { + if (isset($_POST[$campo]) && $_POST[$campo] == "") { + return HAYQUEBORRAR; //Hay que borrar el archivo de imagen + } elseif ($_FILES[$campo]['error'] == 0) { + return HAYQUEGRABAR; //Hay que guardar el archivo de imagen enviado + } else { + return NOHACERNADA; //No hay que hacer nada + } + } + + public function procesaEnvio($campo, &$mensaje) + { + try { + // Undefined | Multiple Files | $_FILES Corruption Attack + // If this request falls under any of them, treat it invalid. + if ( + !isset($_FILES[$campo]['error']) || + is_array($_FILES[$campo]['error']) + ) { + throw new RuntimeException('Parámetros inválidos.'); + } + + // Check $_FILES['upfile']['error'] value. + switch ($_FILES[$campo]['error']) { + case UPLOAD_ERR_OK: + break; + case UPLOAD_ERR_NO_FILE: + throw new RuntimeException('No se ha enviado ningún fichero.'); + case UPLOAD_ERR_INI_SIZE: + case UPLOAD_ERR_FORM_SIZE: + throw new RuntimeException('Se ha excedido el tamaño máximo.'); + default: + throw new RuntimeException('Error desconocido.'); + } + + // DO NOT TRUST $_FILES['upfile']['mime'] VALUE !! + // Check MIME Type by yourself. + $finfo = new finfo(FILEINFO_MIME_TYPE); + if (false === $ext = array_search( + $finfo->file($_FILES[$campo]['tmp_name']), + array( + 'jpg' => 'image/jpeg', + 'png' => 'image/png', + 'gif' => 'image/gif', + ), + true + )) { + throw new RuntimeException('Formato de imagen inválido, no es {jpg, png, gif}'); + } + $this->extension = $ext; + // You should name it uniquely. + // DO NOT USE $_FILES['upfile']['name'] WITHOUT ANY VALIDATION !! + // On this example, obtain safe unique name from its binary data. + $this->archivoSubido = sprintf('tmp/%s.%s', sha1_file($_FILES[$campo]['tmp_name']), $ext); + if (!move_uploaded_file($_FILES[$campo]['tmp_name'], $this->archivoSubido)) { + throw new RuntimeException('Fallo moviendo el archivo subido.'); + } + //Todo ha ido correcto + return true; + } catch (RuntimeException $e) { + $mensaje = $e->getMessage(); + return false; + } + } + + public static function borraImagenId($tabla, $id) + { + $extensiones = array ("png", "gif", "jpg"); + foreach ($extensiones as $extension) { + $archivo = IMAGEDATA . "/" . $tabla . "_" . $id . "." . $extension; + if (file_exists($archivo)) { + unlink ($archivo); + } + } + } + + public function mueveImagenId($tabla, $id, &$mensaje) + { + if (!$this->comprimeArchivo($tabla . "_" . $id, $mensaje)) { + return false; + } else { + return true; + } + } + + private function comprimeArchivo($id, &$mensaje) + { + $zebra = new Zebra_Image(); + $zebra->source_path = $this->archivoSubido; + $this->archivoComprimido = $this->dirData . "/" . $id . "." . $this->extension; + $zebra->target_path = $this->archivoComprimido; + $zebra->jpeg_quality = 100; + + // some additional properties that can be set + // read about them in the documentation + $zebra->preserve_aspect_ratio = true; + $zebra->enlarge_smaller_images = true; + $zebra->preserve_time = true; + + // resize the image to exactly 100x100 pixels by using the "crop from center" method + // (read more in the overview section or in the documentation) + // and if there is an error, check what the error is about + if (!$zebra->resize(640, 480, ZEBRA_IMAGE_CROP_CENTER)) { + // if there was an error, let's see what the error is about + switch ($zebra->error) { + case 1: $mensaje = 'El fichero origen no se ha encontrado!'; + break; + case 2: $mensaje = 'No se puede leer el archivo origen ' . $this->archivoSubido; + break; + case 3: $mensaje = 'No se pudo escribir el archivo destino ' . $this->archivoComprimido; + break; + case 4: $mensaje = 'Formato de fichero origen no soportado ' . $this->archivoSubido; + break; + case 5: $mensaje = 'Formato de fichero destino no soportado ' . $this->archivoComprimido; + break; + case 6: $mensaje = 'La versión de la biblioteca GD no soporta el formato de destino ' . $this->archivoComprimido; + break; + case 7: $mensaje = 'La biblioteca GD no está instalada'; + break; + case 8: $mensaje = 'el comando "chmod" está deshabilitado por configuración'; + break; + } + return false; + } else { + //Borra el archivo subido + unlink($this->archivoSubido); + return true; + } + } +} + +?> diff --git a/Mantenimiento.php b/Mantenimiento.php index 6fa20da..d24792f 100644 --- a/Mantenimiento.php +++ b/Mantenimiento.php @@ -206,6 +206,11 @@ class Mantenimiento { $this->campoBusca = $dato[1]; $valor = '' . $valor; } + if (strstr($this->campos[$clave]['Comment'], "imagen") && isset($valor)) { + $msj = ''; + $msj .= $this->creaModal($valor, $id); + $valor = $msj; + } if ($this->campos[$clave]['Type'] == "Boolean(1)") { $checked = $valor == '1' ? 'checked' : ''; $valor = ''; @@ -297,6 +302,8 @@ class Mantenimiento { } $this->datosURL['opc'] = 'inicial'; $this->datosURL['id'] = null; + //Comprueba si existe la imagen en datos para borrarla. + Imagen::borraImagenId($this->tabla, $id); $url = $this->montaURL(); header('Location: ' . $url); return; @@ -307,6 +314,7 @@ class Mantenimiento { $comando = "insert into " . $this->tabla . " ("; $lista = explode("&", $_POST['listacampos']); $primero = true; + $hayImagen = false; //Añade la lista de campos foreach ($lista as $campo) { if ($campo == "") { @@ -339,7 +347,21 @@ class Mantenimiento { } $valor = $_POST[$campo] == "on" ? '1' : $valor; } else { - $valor = $_POST[$campo] == "" ? "null" : '"' . $_POST[$campo] . '"'; + if (stristr($this->campos[$campo]['Comment'], "imagen")) { + //procesa el envío de la imagen + $imagen = new Imagen(); + $accion = $imagen->determinaAccion($campo); + if ($accion != NOHACERNADA) { + $mensaje = ""; + if (!$imagen->procesaEnvio($campo, $mensaje)) { + return $this->panelMensaje($mensaje, "danger", "ERROR PROCESANDO IMAGEN"); + } + $hayImagen = true; + $campoImagen = $campo; + } + } else { + $valor = $_POST[$campo] == "" ? "null" : '"' . $_POST[$campo] . '"'; + } } $comando.="$coma " . $valor; } @@ -347,14 +369,25 @@ class Mantenimiento { if (!$this->bdd->ejecuta($comando)) { return $this->errorBD($comando); } + $id = $this->bdd->ultimoId(); + if ($hayImagen) { + //Tiene que recuperar el id del registro insertado y actualizar el archivo de imagen + if (!$imagen->mueveImagenId($this->tabla, $id, $mensaje)) { + return $this->panelMensaje($mensaje, "danger", "ERROR COMPRIMIENDO IMAGEN"); + } + $comando = "update " . $this->tabla . " set " . $campoImagen . "='" . $imagen->archivoComprimido . "' where id='" . $id ."';"; + if (!$this->bdd->ejecuta($comando)) { + return $this->errorBD($comando); + } + } $this->datosURL['opc'] = 'inicial'; $this->datosURL['id'] = null; $cabecera = "refresh:".PAUSA.";url=".$this->montaURL(); header($cabecera); - return $this->panelMensaje("Se ha insertado el registro con la clave " . $this->bdd->ultimoId(), "info", "Información"); + return $this->panelMensaje("Se ha insertado el registro con la clave " . $id, "info", "Información"); //return "

montaURL()."\">Se ha insertado el registro con la clave " . $this->bdd->ultimoId() . "

"; } - + protected function modificar() { //Los datos a utilizar para actualizar la tupla vienen en $_POST. @@ -382,10 +415,34 @@ class Mantenimiento { $valor = $_POST[$campo] == "on" ? '1' : $valor; $comando.=$coma . ' ' . $campo . '="' . $valor . '"'; } else { - if (strlen(trim($_POST[$campo])) == 0) { - $comando.="$coma $campo=null"; + if (stristr($this->campos[$campo]['Comment'], "imagen")) { + $valor = $_POST[$campo]; + $imagen = new Imagen(); + $accion = $imagen->determinaAccion($campo); + if ($accion != NOHACERNADA) { + if ($accion == HAYQUEGRABAR) { + $mensaje = ""; + if (!$imagen->procesaEnvio($campo, $mensaje)) { + return $this->panelMensaje($mensaje, "danger", "ERROR PROCESANDO IMAGEN"); + } + $mensaje = ""; + if (!$imagen->mueveImagenId($this->tabla, $this->datosURL['id'], $mensaje)) { + return $this->panelMensaje($mensaje, "danger", "ERROR COMPRIMIENDO IMAGEN"); + } + $comando .= "$coma $campo='" . $imagen->archivoComprimido . "'"; + } else { + //Hay que borrar + Imagen::borraImagenId($this->tabla, $this->datosURL['id']); + $extensiones = array("png", "jpg", "gif"); + $comando .= "$coma $campo=null"; + } + } } else { - $comando.=$coma . ' ' . $campo . '="' . $_POST[$campo] . '"'; + if (strlen(trim($_POST[$campo])) == 0) { + $comando.="$coma $campo=null"; + } else { + $comando.=$coma . ' ' . $campo . '="' . $_POST[$campo] . '"'; + } } } } @@ -532,7 +589,7 @@ class Mantenimiento { break; } $accion = $this->montaURL(); - $salida.='
' . "\n"; + $salida.='
' . "\n"; $salida.="

$tipo\n"; foreach ($this->campos as $clave => $valor) { if ($valor["Editable"] == "no") { @@ -594,6 +651,14 @@ class Mantenimiento { $salida .= '

'; continue; } + if (stristr($this->campos[$campo]['Comment'], "imagen")) { + $salida .= $this->creaCampoImagen($campo, $valorDato, $tipo); + continue; + } + if (stristr($this->campos[$campo]['Type'], "int")) { + $tipo_campo = "number"; + $modoEfectivo .= ' onkeypress = "if ( isNaN(this.value + String.fromCharCode(event.keyCode) )) return false;" '; + } //Si no es una clave foránea añade un campo de texto normal $salida.='

\n"; @@ -614,6 +679,58 @@ class Mantenimiento { $salida .= '
'; return $salida; } + + protected function creaCampoImagen($campo, $valor, $tipoAccion) + { + + if (file_exists($valor)) { + //El fichero existe. + $existe = true; + $tipo = "fileinput-exists"; + } else { + $tipo = "fileinput-new"; + $existe = false; + } + $mensaje = ' +
+
+
'; + + if ($existe) { + $mensaje .= ''; + } + $mensaje .= '
'; + if ($tipoAccion == ANADIR || $tipoAccion == EDICION) { + $mensaje .= '
+ AñadirCambiar + Eliminar'; + } + if ($existe) { + $mensaje .=''; + } + + $mensaje .='
'; + if ($tipoAccion == ANADIR || $tipoAccion == EDICION) { + $mensaje .= '
'; + } + $mensaje .= $this->creaModal($valor, 1); + return $mensaje; + + } + + private function creaModal($valor, $id) + { + $mensaje .= ' + '; + return $mensaje; + } protected function errorBD($comando, $texto = "", $tipo = "danger", $cabecera = "¡Atención!") { @@ -633,7 +750,8 @@ class Mantenimiento { $mensaje .= ''; $mensaje .= ''; return $mensaje; - } + } + } ?> \ No newline at end of file diff --git a/Zebra_Image.php b/Zebra_Image.php new file mode 100644 index 0000000..ba59a2a --- /dev/null +++ b/Zebra_Image.php @@ -0,0 +1,1707 @@ + + * @version 2.2.3 (last revision: July 14, 2013) + * @copyright (c) 2006 - 2013 Stefan Gabos + * @license http://www.gnu.org/licenses/lgpl-3.0.txt GNU LESSER GENERAL PUBLIC LICENSE + * @package Zebra_Image + */ +class Zebra_Image +{ + + /** + * Indicates the file system permissions to be set for newly created images. + * + * Better is to leave this setting as it is. + * + * If you know what you are doing, here is how you can calculate the permission levels: + * + * - 400 Owner Read + * - 200 Owner Write + * - 100 Owner Execute + * - 40 Group Read + * - 20 Group Write + * - 10 Group Execute + * - 4 Global Read + * - 2 Global Write + * - 1 Global Execute + * + * Default is 0755 + * + * @var integer + */ + var $chmod_value; + + /** + * If set to FALSE, images having both width and height smaller than the required width and height, will be left + * untouched ({@link jpeg_quality} and {@link png_compression} will still apply). + * + * Available only for the {@link resize()} method + * + * Default is TRUE + * + * @var boolean + */ + var $enlarge_smaller_images; + + /** + * In case of an error read this property's value to see the error's code. + * + * Possible error codes are: + * + * - 1: source file could not be found + * - 2: source file is not readable + * - 3: could not write target file + * - 4: unsupported source file format + * - 5: unsupported target file format + * - 6: GD library version does not support target file format + * - 7: GD library is not installed! + * - 8: "chmod" command is disabled via configuration + * + * Default is 0 (no error). + * + * @var integer + */ + var $error; + + /** + * Indicates the quality of the output image (better quality means bigger file size). + * + * Used only if the file at {@link target_path} is a JPG/JPEG image. + * + * Range is 0 - 100 + * + * Default is 85 + * + * @var integer + */ + var $jpeg_quality; + + /** + * Indicates the compression level of the output image (lower compression means bigger file size). + * + * Available only if PHP version is 5.1.2+, and only if the file at {@link target_path} is a PNG image. It will be + * ignored otherwise. + * + * Range is 0 - 9 + * + * Default is 9 + * + * @since 2.2 + * + * @var integer + */ + var $png_compression; + + /** + * Specifies whether, upon resizing, images should preserve their aspect ratio. + * + * Available only for the {@link resize()} method + * + * Default is TRUE + * + * @var boolean + */ + var $preserve_aspect_ratio; + + /** + * Indicates whether a target files should preserve the source file's date/time. + * + * Default is TRUE + * + * @since 1.0.4 + * + * @var boolean + */ + var $preserve_time; + + /** + * Indicates whether the target image should have a "sharpen" filter applied to it. + * + * Can be very useful when creating thumbnails and should be used only when creating thumbnails. + * + * The sharpen filter relies on the "imageconvolution" PHP function which is available only for PHP version + * 5.1.0+, and will leave the images unaltered for older versions! + * + * Default is FALSE + * + * @since 2.2 + * + * @var boolean + */ + var $sharpen_images; + + /** + * Path to an image file to apply the transformations to. + * + * Supported file types are GIF, PNG and JPEG. + * + * @var string + */ + var $source_path; + + /** + * Path (including file name) to where to save the transformed image. + * + * Can be a different than {@link source_path} - the type of the transformed image will be as indicated by the + * file's extension (supported file types are GIF, PNG and JPEG). + * + * @var string + */ + var $target_path; + + /** + * Constructor of the class. + * + * Initializes the class and the default properties + * + * @return void + */ + function Zebra_Image() + { + + // set default values for properties + $this->chmod_value = 0755; + + $this->error = 0; + + $this->jpeg_quality = 85; + + $this->png_compression = 9; + + $this->preserve_aspect_ratio = $this->preserve_time = $this->enlarge_smaller_images = true; + + $this->sharpen_images = false; + + $this->source_path = $this->target_path = ''; + + } + + /** + * Applies one or more filters to the image given as {@link source_path} and outputs it as the file specified as + * {@link target_path}. + * + * This method is available only if the {@link http://php.net/manual/en/function.imagefilter.php imagefilter} + * function is available (available from PHP 5+), and will leave images unaltered otherwise. + * + * + * // include the Zebra_Image library + * require 'path/to/Zebra_Image.php'; + * + * // instantiate the class + * $img = new Zebra_Image(); + * + * // a source image + * $img->source_path = 'path/to/source.ext'; + * + * // path to where should the resulting image be saved + * // note that by simply setting a different extension to the file will + * // instruct the script to create an image of that particular type + * $img->target_path = 'path/to/target.ext'; + * + * // apply the "grayscale" filter + * $img->apply_filter('grayscale'); + * + * // apply the "contrast" filter + * $img->apply_filter('contrast', -20); + * + * + * You can also apply multiple filters at once. In this case, the method requires a single argument, an array of + * arrays, containing the filters and associated arguments, where applicable: + * + * + * // create a sepia effect + * // note how we're applying multiple filters at once + * // each filter is in its own array + * $img->apply_filter(array( + * + * // first we apply the "grayscale" filter + * array('grayscale'), + * + * // then we apply the "colorize" filter with 90, 60, 40 as + * // the values for red, green and blue + * array('colorize', 90, 60, 40), + * + * )); + * + * + * @param string $filter The (case-insensitive) name of the filter to apply. Can be one of the following: + * + * - brightness - changes the brightness of the image; use arg1 + * to set the level of brightness; the range of brightness + * is -255 to 255; + * - colorize - adds (subtracts) specified RGB values to each pixel; + * use arg1, arg2 and arg3 in the + * form of red, green, blue and arg4 for the alpha + * channel. the range for each color is -255 to 255 and + * 0 to 127 for alpha; alpha support is available only + * for PHP 5.2.5+; + * - contrast - changes the contrast of the image; use arg1 + * to set the level of contrast; the range of contrast + * is -100 to 100; + * - gausian_blur - blurs the image using the Gaussian method; + * - grayscale - converts the image into grayscale; + * - edgedetect - uses edge detection to highlight the edges in the image; + * - emboss - embosses the image; + * - mean_removal - uses mean removal to achieve a "sketchy" effect; + * - negate - reverses all the colors of the image; + * - pixelate - applies pixelation effect to the image, use arg1 + * to set the block size and arg2 to set the + * pixelation effect mode; this filter is available + * only for PHP 5.3.0+; + * - selective_blur - blurs the image; + * - smooth - makes the image smoother. Use arg1 to set the + * level of smoothness. applies a 9-cell convolution matrix + * where center pixel has the weight of arg1 and + * others weight of 1.0. the result is normalized by dividing + * the sum with arg1 + 8.0 (sum of the matrix). + * any float is accepted; + * + * @param mixed $arg1 Used by the following filters: + * - brightness - sets the brightness level (-255 to 255) + * - contrast - sets the contrast level (-100 to 100) + * - colorize - sets the value of the red component (-255 to 255) + * - smooth - sets the smoothness level + * - pixelate - sets the block size, in pixels + * + * @param mixed $arg2 Used by the following filters: + * - colorize - sets the value of the green component (-255 to 255) + * - pixelate - whether to use advanced pixelation effect or not (defaults to FALSE). + * + * @param mixed $arg3 Used by the following filters: + * - colorize - sets the value of the blue component (-255 to 255) + * + * @param mixed $arg4 Used by the following filters: + * - colorize - alpha channel; a value between 0 and 127. 0 indicates + * completely opaque while 127 indicates completely + * transparent. + * + * @since 2.2.2 + * + * @return boolean Returns TRUE on success or FALSE on error. + * + * If {@link http://php.net/manual/en/function.imagefilter.php imagefilter} is not + * available the method will return FALSE without setting an {@link error} code. + * + * If the requested filter doesn't exist, or invalid arguments are passed, the method + * will trigger a warning. + * + * If FALSE is returned and you are sure that + * {@link http://php.net/manual/en/function.imagefilter.php imagefilter} exists and that + * the requested filter is valid, check the {@link error} property to see the error code. + */ + function apply_filter($filter, $arg1 = '', $arg2 = '', $arg3 = '', $arg4 = '') + { + + // if "imagefilter" function exists and the requested filter exists + if (function_exists('imagefilter')) + + // if image resource was successfully created + if ($this->_create_from_source()) { + + // prepare the target image + $target_identifier = $this->_prepare_image($this->source_width, $this->source_height, -1); + + // copy the original image + imagecopyresampled( + + $target_identifier, + $this->source_identifier, + 0, + 0, + 0, + 0, + $this->source_width, + $this->source_height, + $this->source_width, + $this->source_height + + ); + + // if multiple filters are to be applied at once + if (is_array($filter)) { + + // iterate through the filters + foreach ($filter as $arguments) + + // if filter exists + if (defined('IMG_FILTER_' . strtoupper($arguments[0]))) { + + // try to apply the filter... + if (!@call_user_func_array('imagefilter', array_merge(array($target_identifier, constant('IMG_FILTER_' . strtoupper($arguments[0]))), array_slice($arguments, 1)))) + + // ...and trigger an error if the filter could not be applied + trigger_error('Invalid arguments used for "' . strtoupper($arguments[0]) . '" filter', E_USER_WARNING); + + // if filter doesn't exists, trigger an error + } else trigger_error('Filter "' . strtoupper($arguments[0]) . '" is not available', E_USER_WARNING); + + // if a single filter is to be applied and it is available + } elseif (defined('IMG_FILTER_' . strtoupper($filter))) { + + // get all the arguments passed to the method + $arguments = func_get_args(); + + // try to apply the filter... + if (!@call_user_func_array('imagefilter', array_merge(array($target_identifier, constant('IMG_FILTER_' . strtoupper($filter))), array_slice($arguments, 1)))) + + // ...and trigger an error if the filter could not be applied + trigger_error('Invalid arguments used for "' . strtoupper($arguments[0]) . '" filter', E_USER_WARNING); + + // if filter doesn't exists, trigger an error + } else trigger_error('Filter "' . strtoupper($arguments[0]) . '" is not available', E_USER_WARNING); + + // write image + return $this->_write_image($target_identifier); + + } + + // if script gets this far, return false + // note that we do not set the error level as it has been already set + // by the _create_from_source() method earlier, if the case + return false; + + } + + /** + * Crops a portion of the image given as {@link source_path} and outputs it as the file specified as {@link target_path}. + * + * + * // include the Zebra_Image library + * require 'path/to/Zebra_Image.php'; + * + * // instantiate the class + * $img = new Zebra_Image(); + * + * // a source image + * $img->source_path = 'path/to/source.ext'; + * + * // path to where should the resulting image be saved + * // note that by simply setting a different extension to the file will + * // instruct the script to create an image of that particular type + * $img->target_path = 'path/to/target.ext'; + * + * // crop a rectangle of 100x100 pixels, starting from the top-left corner + * $img->crop(0, 0, 100, 100); + * + * + * @param integer $start_x x coordinate to start cropping from + * + * @param integer $start_y y coordinate to start cropping from + * + * @param integer $end_x x coordinate where to end the cropping + * + * @param integer $end_y y coordinate where to end the cropping + * + * @since 1.0.4 + * + * @return boolean Returns TRUE on success or FALSE on error. + * + * If FALSE is returned, check the {@link error} property to see the error code. + */ + function crop($start_x, $start_y, $end_x, $end_y) + { + + // this method might be also called internally + // in this case, there's a fifth argument that points to an already existing image identifier + $args = func_get_args(); + + // if fifth argument exists + if (isset($args[4]) && is_resource($args[4])) { + + // that it is the image identifier that we'll be using further on + $this->source_identifier = $args[4]; + + // set this to true so that the script will continue to execute at the next IF + $result = true; + + // if method is called as usually + // try to create an image resource from source path + } else $result = $this->_create_from_source(); + + // if image resource was successfully created + if ($result !== false) { + + // prepare the target image + $target_identifier = $this->_prepare_image($end_x - $start_x, $end_y - $start_y, -1); + + // crop the image + imagecopyresampled( + + $target_identifier, + $this->source_identifier, + 0, + 0, + $start_x, + $start_y, + $end_x - $start_x, + $end_y - $start_y, + $end_x - $start_x, + $end_y - $start_y + + ); + + // write image + return $this->_write_image($target_identifier); + + } + + // if script gets this far, return false + // note that we do not set the error level as it has been already set + // by the _create_from_source() method earlier + return false; + + } + + /** + * Flips both horizontally and vertically the image given as {@link source_path} and outputs the resulted image as + * {@link target_path} + * + * + * // include the Zebra_Image library + * require 'path/to/Zebra_Image.php'; + * + * // instantiate the class + * $img = new Zebra_Image(); + * + * // a source image + * $img->source_path = 'path/to/source.ext'; + * + * // path to where should the resulting image be saved + * // note that by simply setting a different extension to the file will + * // instruct the script to create an image of that particular type + * $img->target_path = 'path/to/target.ext'; + * + * // flip the image both horizontally and vertically + * $img->flip_both(); + * + * + * @since 2.1 + * + * @return boolean Returns TRUE on success or FALSE on error. + * + * If FALSE is returned, check the {@link error} property to see the error code. + */ + function flip_both() + { + + return $this->_flip('both'); + + } + + /** + * Flips horizontally the image given as {@link source_path} and outputs the resulted image as {@link target_path} + * + * + * // include the Zebra_Image library + * require 'path/to/Zebra_Image.php'; + * + * // instantiate the class + * $img = new Zebra_Image(); + * + * // a source image + * $img->source_path = 'path/to/source.ext'; + * + * // path to where should the resulting image be saved + * // note that by simply setting a different extension to the file will + * // instruct the script to create an image of that particular type + * $img->target_path = 'path/to/target.ext'; + * + * // flip the image horizontally + * $img->flip_horizontal(); + * + * + * @return boolean Returns TRUE on success or FALSE on error. + * + * If FALSE is returned, check the {@link error} property to see the error code. + */ + function flip_horizontal() + { + + return $this->_flip('horizontal'); + + } + + /** + * Flips vertically the image given as {@link source_path} and outputs the resulted image as {@link target_path} + * + * + * // include the Zebra_Image library + * require 'path/to/Zebra_Image.php'; + * + * // instantiate the class + * $img = new Zebra_Image(); + * + * // a source image + * $img->source_path = 'path/to/source.ext'; + * + * // path to where should the resulting image be saved + * // note that by simply setting a different extension to the file will + * // instruct the script to create an image of that particular type + * $img->target_path = 'path/to/target.ext'; + * + * // flip the image vertically + * $img->flip_vertical(); + * + * + * @return boolean Returns TRUE on success or FALSE on error. + * + * If FALSE is returned, check the {@link error} property to see the error code. + */ + function flip_vertical() + { + + return $this->_flip('vertical'); + + } + + /** + * Resizes the image given as {@link source_path} and outputs the resulted image as {@link target_path}. + * + * + * // include the Zebra_Image library + * require 'path/to/Zebra_Image.php'; + * + * // instantiate the class + * $img = new Zebra_Image(); + * + * // a source image + * $img->source_path = 'path/to/source.ext'; + * + * // path to where should the resulting image be saved + * // note that by simply setting a different extension to the file will + * // instruct the script to create an image of that particular type + * $img->target_path = 'path/to/target.ext'; + * + * // apply a "sharpen" filter to the resulting images + * $img->sharpen_images = true; + * + * // resize the image to exactly 150x150 pixels, without altering aspect ratio, by using the CROP_CENTER method + * $img->resize(150, 150, ZEBRA_IMAGE_CROP_CENTER); + * + * + * @param integer $width The width to resize the image to. + * + * If set to 0, the width will be automatically adjusted, depending + * on the value of the height argument so that the image preserves + * its aspect ratio. + * + * If {@link preserve_aspect_ratio} is set to TRUE and both this and the + * height arguments are values greater than 0, the image will + * be resized to the exact required width and height and the aspect ratio + * will be preserved - (also see the description for the method + * argument below on how can this be done). + * + * If {@link preserve_aspect_ratio} is set to FALSE, the image will be + * resized to the required width and the aspect ratio will be ignored. + * + * If both width and height are set to 0, a copy of + * the source image will be created ({@link jpeg_quality} and + * {@link png_compression} will still apply). + * + * If either width or height are set to 0, the script + * will consider the value of the {@link preserve_aspect_ratio} to bet set + * to TRUE regardless of its actual value! + * + * @param integer $height The height to resize the image to. + * + * If set to 0, the height will be automatically adjusted, depending + * on the value of the width argument so that the image preserves + * its aspect ratio. + * + * If {@link preserve_aspect_ratio} is set to TRUE and both this and the + * width arguments are values greater than 0, the image will + * be resized to the exact required width and height and the aspect ratio + * will be preserved - (also see the description for the method + * argument below on how can this be done). + * + * If {@link preserve_aspect_ratio} is set to FALSE, the image will be + * resized to the required height and the aspect ratio will be ignored. + * + * If both width and height are set to 0, a copy of + * the source image will be created ({@link jpeg_quality} and + * {@link png_compression} will still apply). + * + * If either height or width are set to 0, the script + * will consider the value of the {@link preserve_aspect_ratio} to bet set + * to TRUE regardless of its actual value! + * + * @param int $method (Optional) Method to use when resizing images to exact width and height + * while preserving aspect ratio. + * + * If the {@link preserve_aspect_ratio} property is set to TRUE and both the + * width and height arguments are values greater than 0, + * the image will be resized to the exact given width and height and the + * aspect ratio will be preserved by using on of the following methods: + * + * - ZEBRA_IMAGE_BOXED - the image will be scalled so that it will + * fit in a box with the given width and height (both width/height will + * be smaller or equal to the required width/height) and then it will + * be centered both horizontally and vertically. The blank area will be + * filled with the color specified by the bgcolor argument. (the + * blank area will be filled only if the image is not transparent!) + * + * - ZEBRA_IMAGE_NOT_BOXED - the image will be scalled so that it + * could fit in a box with the given width and height but will + * not be enclosed in a box with given width and height. The new width/ + * height will be both smaller or equal to the required width/height + * + * - ZEBRA_IMAGE_CROP_TOPLEFT + * - ZEBRA_IMAGE_CROP_TOPCENTER + * - ZEBRA_IMAGE_CROP_TOPRIGHT + * - ZEBRA_IMAGE_CROP_MIDDLELEFT + * - ZEBRA_IMAGE_CROP_CENTER + * - ZEBRA_IMAGE_CROP_MIDDLERIGHT + * - ZEBRA_IMAGE_CROP_BOTTOMLEFT + * - ZEBRA_IMAGE_CROP_BOTTOMCENTER + * - ZEBRA_IMAGE_CROP_BOTTOMRIGHT + * + * For the methods involving crop, first the image is scaled so that both + * its sides are equal or greater than the respective sizes of the bounding + * box; next, a region of required width and height will be cropped from + * indicated region of the resulted image. + * + * Default is ZEBRA_IMAGE_CROP_CENTER + * + * @param hexadecimal $background_color (Optional) The hexadecimal color (like "#FFFFFF" or "#FFF") of the + * blank area. See the method argument. + * + * When set to -1 the script will preserve transparency for transparent GIF + * and PNG images. For non-transparent images the background will be white + * in this case. + * + * Default is #FFFFFF. + * + * @return boolean Returns TRUE on success or FALSE on error. + * + * If FALSE is returned, check the {@link error} property to see what went + * wrong + */ + function resize($width = 0, $height = 0, $method = ZEBRA_IMAGE_CROP_CENTER, $background_color = '#FFFFFF') + { + + // if image resource was successfully created + if ($this->_create_from_source()) { + + // if either width or height is to be adjusted automatically + // set a flag telling the script that, even if $preserve_aspect_ratio is set to false + // treat everything as if it was set to true + if ($width == 0 || $height == 0) $auto_preserve_aspect_ratio = true; + + // if aspect ratio needs to be preserved + if ($this->preserve_aspect_ratio || isset($auto_preserve_aspect_ratio)) { + + // if height is given and width is to be computed accordingly + if ($width == 0 && $height > 0) { + + // get the original image's aspect ratio + $aspect_ratio = $this->source_width / $this->source_height; + + // the target image's height is as given as argument to the method + $target_height = $height; + + // compute the target image's width, preserving the aspect ratio + $target_width = round($height * $aspect_ratio); + + // if width is given and height is to be computed accordingly + } elseif ($width > 0 && $height == 0) { + + // get the original image's aspect ratio + $aspect_ratio = $this->source_height / $this->source_width; + + // the target image's width is as given as argument to the method + $target_width = $width; + + // compute the target image's height, preserving the aspect ratio + $target_height = round($width * $aspect_ratio); + + // if both width and height are given and ZEBRA_IMAGE_BOXED or ZEBRA_IMAGE_NOT_BOXED methods are to be used + } elseif ($width > 0 && $height > 0 && ($method == 0 || $method == 1)) { + + // compute the horizontal and vertical aspect ratios + $vertical_aspect_ratio = $height / $this->source_height; + $horizontal_aspect_ratio = $width / $this->source_width; + + // if the image's newly computed height would be inside the bounding box + if (round($horizontal_aspect_ratio * $this->source_height < $height)) { + + // the target image's width is as given as argument to the method + $target_width = $width; + + // compute the target image's height so that the image will stay inside the bounding box + $target_height = round($horizontal_aspect_ratio * $this->source_height); + + // otherwise + } else { + + // the target image's height is as given as argument to the method + $target_height = $height; + + // compute the target image's width so that the image will stay inside the bounding box + $target_width = round($vertical_aspect_ratio * $this->source_width); + + } + + // if both width and height are given and image is to be cropped in order to get to the required size + } elseif ($width > 0 && $height > 0 && $method > 1 && $method < 11) { + + // compute the horizontal and vertical aspect ratios + $vertical_aspect_ratio = $this->source_height / $height; + $horizontal_aspect_ratio = $this->source_width / $width; + + // we'll use one of the two + $aspect_ratio = + + $vertical_aspect_ratio < $horizontal_aspect_ratio ? + + $vertical_aspect_ratio : + + $horizontal_aspect_ratio; + + // compute the target image's width, preserving the aspect ratio + $target_width = round($this->source_width / $aspect_ratio); + + // compute the target image's height, preserving the aspect ratio + $target_height = round($this->source_height / $aspect_ratio); + + // for any other case + } else { + + // we will create a copy of the source image + $target_width = $this->source_width; + $target_height = $this->source_height; + + } + + // if aspect ratio does not need to be preserved + } else { + + // compute the target image's width + $target_width = ($width > 0 ? $width : $this->source_width); + + // compute the target image's height + $target_height = ($height > 0 ? $height : $this->source_height); + + } + + // if + if ( + + // all images are to be resized - including images that are smaller than the given width/height + $this->enlarge_smaller_images || + + // smaller images than the given width/height are to be left untouched + // but current image has at leas one side that is larger than the required width/height + ($width > 0 && $height > 0 ? + + ($this->source_width > $width || $this->source_height > $height) : + + ($this->source_width > $target_width || $this->source_height > $target_height) + + ) + + ) { + + // if + if ( + + // aspect ratio needs to be preserved AND + ($this->preserve_aspect_ratio || isset($auto_preserve_aspect_ratio)) && + + // both width and height are given + ($width > 0 && $height > 0) && + + // images are to be cropped + ($method > 1 && $method < 11) + + ) { + + // prepare the target image + $target_identifier = $this->_prepare_image($target_width, $target_height, $background_color); + + imagecopyresampled( + + $target_identifier, + $this->source_identifier, + 0, + 0, + 0, + 0, + $target_width, + $target_height, + $this->source_width, + $this->source_height + + ); + + // do the crop according to the required method + switch ($method) { + + // if image needs to be cropped from the top-left corner + case ZEBRA_IMAGE_CROP_TOPLEFT: + + // crop accordingly + return $this->crop( + 0, + 0, + $width, + $height, + $target_identifier // crop this resource instead + ); + + break; + + // if image needs to be cropped from the top-center + case ZEBRA_IMAGE_CROP_TOPCENTER: + + // crop accordingly + return $this->crop( + floor(($target_width - $width) / 2), + 0, + floor(($target_width - $width) / 2) + $width, + $height, + $target_identifier // crop this resource instead + ); + + break; + + // if image needs to be cropped from the top-right corner + case ZEBRA_IMAGE_CROP_TOPRIGHT: + + // crop accordingly + return $this->crop( + $target_width - $width, + 0, + $target_width, + $height, + $target_identifier // crop this resource instead + ); + + break; + + // if image needs to be cropped from the middle-left + case ZEBRA_IMAGE_CROP_MIDDLELEFT: + + // crop accordingly + return $this->crop( + + 0, + floor(($target_height - $height) / 2), + $width, + floor(($target_height - $height) / 2) + $height, + $target_identifier // crop this resource instead + + ); + + break; + + // if image needs to be cropped from the center of the image + case ZEBRA_IMAGE_CROP_CENTER: + + // crop accordingly + return $this->crop( + + floor(($target_width - $width) / 2), + floor(($target_height - $height) / 2), + floor(($target_width - $width) / 2) + $width, + floor(($target_height - $height) / 2) + $height, + $target_identifier // crop this resource instead + + ); + + break; + + // if image needs to be cropped from the middle-right + case ZEBRA_IMAGE_CROP_MIDDLERIGHT: + + // crop accordingly + return $this->crop( + + $target_width - $width, + floor(($target_height - $height) / 2), + $target_width, + floor(($target_height - $height) / 2) + $height, + $target_identifier // crop this resource instead + + ); + + break; + + // if image needs to be cropped from the bottom-left corner + case ZEBRA_IMAGE_CROP_BOTTOMLEFT: + + // crop accordingly + return $this->crop( + + 0, + $target_height - $height, + $width, + $target_height, + $target_identifier // crop this resource instead + + ); + + break; + + // if image needs to be cropped from the bottom-center + case ZEBRA_IMAGE_CROP_BOTTOMCENTER: + + // crop accordingly + return $this->crop( + + floor(($target_width - $width) / 2), + $target_height - $height, + floor(($target_width - $width) / 2) + $width, + $target_height, + $target_identifier // crop this resource instead + + ); + + break; + + // if image needs to be cropped from the bottom-right corner + case ZEBRA_IMAGE_CROP_BOTTOMRIGHT: + + // crop accordingly + return $this->crop( + + $target_width - $width, + $target_height - $height, + $target_width, + $target_height, + $target_identifier // crop this resource instead + + ); + + break; + + } + + // if aspect ratio doesn't need to be preserved or + // it needs to be preserved and method is ZEBRA_IMAGE_BOXED or ZEBRA_IMAGE_NOT_BOXED + } else { + + // prepare the target image + $target_identifier = $this->_prepare_image( + ($width > 0 && $height > 0 && $method != ZEBRA_IMAGE_NOT_BOXED ? $width : $target_width), + ($width > 0 && $height > 0 && $method != ZEBRA_IMAGE_NOT_BOXED ? $height : $target_height), + $background_color + ); + + imagecopyresampled( + + $target_identifier, + $this->source_identifier, + ($width > 0 && $height > 0 && $method != ZEBRA_IMAGE_NOT_BOXED ? ($width - $target_width) / 2 : 0), + ($width > 0 && $height > 0 && $method != ZEBRA_IMAGE_NOT_BOXED ? ($height - $target_height) / 2 : 0), + 0, + 0, + $target_width, + $target_height, + $this->source_width, + $this->source_height + + ); + + // if script gets this far, write the image to disk + return $this->_write_image($target_identifier); + + } + + // if we get here it means that + // smaller images than the given width/height are to be left untouched + // therefore, we save the image as it is + } else return $this->_write_image($this->source_identifier); + + } + + // if script gets this far return false + // note that we do not set the error level as it has been already set + // by the _create_from_source() method earlier + return false; + + } + + /** + * Rotates the image given as {@link source_path} and outputs the resulted image as {@link target_path}. + * + * + * // include the Zebra_Image library + * require 'path/to/Zebra_Image.php'; + * + * // instantiate the class + * $img = new Zebra_Image(); + * + * // a source image + * $img->source_path = 'path/to/source.ext'; + * + * // path to where should the resulting image be saved + * // note that by simply setting a different extension to the file will + * // instruct the script to create an image of that particular type + * $img->target_path = 'path/to/target.ext'; + * + * // rotate the image 45 degrees, clockwise + * $img->rotate(45); + * + * + * @param double $angle Angle by which to rotate the image clockwise. + * + * Between 0 and 360. + * + * @param mixed $background_color (Optional) The hexadecimal color (like "#FFFFFF" or "#FFF") of the + * uncovered zone after the rotation. + * + * When set to -1 the script will preserve transparency for transparent GIF + * and PNG images. For non-transparent images the background will be white + * in this case. + * + * Default is -1. + * + * @return boolean Returns TRUE on success or FALSE on error. + * + * If FALSE is returned, check the {@link error} property to see the error + * code. + */ + function rotate($angle, $background_color = -1) + { + + // if image resource was successfully created + if ($this->_create_from_source()) { + + // angles are given clockwise but imagerotate works counterclockwise so we need to negate our value + $angle = -$angle; + + // if source image is PNG + if ($this->source_type == IMAGETYPE_PNG && $background_color == -1) { + + // rotate the image + // but if using -1 as background color didn't work (as is the case for PNG8) + if (!($target_identifier = imagerotate($this->source_identifier, $angle, -1))) { + + // we will be using #FFF as the color to fill the uncovered zone after the rotation + $background_color = imagecolorallocate($this->source_identifier, 255, 255, 255); + + // rotate the image + $target_identifier = imagerotate($this->source_identifier, $angle, $background_color); + + } + + // if source image is a transparent GIF + } elseif ($this->source_type == IMAGETYPE_GIF && $this->source_transparent_color_index >= 0) { + + // convert the background color to RGB values + $background_color = $this->_hex2rgb($background_color); + + // allocate the color to the image identifier + $background_color = imagecolorallocate( + + $this->source_identifier, + $background_color['r'], + $background_color['g'], + $background_color['b'] + + ); + + // rotate the image + $this->source_identifier = imagerotate($this->source_identifier, $angle, $background_color); + + // get the width of rotated image + $width = imagesx($this->source_identifier); + + // get the height of rotated image + $height = imagesy($this->source_identifier); + + // create a blank image with the new width and height + // (this intermediary step is for preserving transparency) + $target_identifier = $this->_prepare_image($width, $height, -1); + + // copy the rotated image on to the new one + imagecopyresampled($target_identifier, $this->source_identifier, 0, 0, 0, 0, $width, $height, $width, $height); + + // for the other cases + } else { + + // convert the color to RGB values + $background_color = $this->_hex2rgb($background_color); + + // allocate the color to the image identifier + $background_color = imagecolorallocate( + + $this->source_identifier, + $background_color['r'], + $background_color['g'], + $background_color['b'] + + ); + + // rotate the image + $target_identifier = imagerotate($this->source_identifier, $angle, $background_color); + + } + + // write image + $this->_write_image($target_identifier); + + } + + // if script gets this far return false + // note that we do not set the error level as it has been already set + // by the _create_from_source() method earlier + return false; + + } + + /** + * Returns an array containing the image identifier representing the image obtained from {@link $source_path}, the + * image's width and height and the image's type + * + * @access private + */ + function _create_from_source() + { + + // perform some error checking first + // if the GD library is not installed + if (!function_exists('gd_info')) { + + // save the error level and stop the execution of the script + $this->error = 7; + + return false; + + // if source file does not exist + } elseif (!is_file($this->source_path)) { + + // save the error level and stop the execution of the script + $this->error = 1; + + return false; + + // if source file is not readable + } elseif (!is_readable($this->source_path)) { + + // save the error level and stop the execution of the script + $this->error = 2; + + return false; + + // if target file is same as source file and source file is not writable + } elseif ($this->target_path == $this->source_path && !is_writable($this->source_path)) { + + // save the error level and stop the execution of the script + $this->error = 3; + + return false; + + // try to get source file width, height and type + // and if it founds an unsupported file type + } elseif (!list($this->source_width, $this->source_height, $this->source_type) = @getimagesize($this->source_path)) { + + // save the error level and stop the execution of the script + $this->error = 4; + + return false; + + // if no errors so far + } else { + + // get target file's type based on the file extension + $this->target_type = strtolower(substr($this->target_path, strrpos($this->target_path, '.') + 1)); + + // create an image from file using extension dependant function + // checks for file extension + switch ($this->source_type) { + + // if GIF + case IMAGETYPE_GIF: + + // create an image from file + $identifier = imagecreatefromgif($this->source_path); + + // get the index of the transparent color (if any) + if (($this->source_transparent_color_index = imagecolortransparent($identifier)) >= 0) + + // get the transparent color's RGB values + // we have to mute errors because there are GIF images which *are* transparent and everything + // works as expected, but imagecolortransparent() returns a color that is outside the range of + // colors in the image's pallette... + $this->source_transparent_color = @imagecolorsforindex($identifier, $this->source_transparent_color_index); + + break; + + // if JPEG + case IMAGETYPE_JPEG: + + // create an image from file + $identifier = imagecreatefromjpeg($this->source_path); + + break; + + // if PNG + case IMAGETYPE_PNG: + + // create an image from file + $identifier = imagecreatefrompng($this->source_path); + + // disable blending + imagealphablending($identifier, false); + + break; + + default: + + // if unsupported file type + // note that we call this if the file is not GIF, JPG or PNG even though the getimagesize function + // handles more image types + $this->error = 4; + + return false; + + } + + } + + // if target file has to have the same timestamp as the source image + // save it as a global property of the class + if ($this->preserve_time) $this->source_image_time = filemtime($this->source_path); + + // make available the source image's identifier + $this->source_identifier = $identifier; + + return true; + + } + + /** + * Converts a hexadecimal representation of a color (i.e. #123456 or #AAA) to a RGB representation. + * + * The RGB values will be a value between 0 and 255 each. + * + * @param string $color Hexadecimal representation of a color (i.e. #123456 or #AAA). + * + * @param string $default_on_error Hexadecimal representation of a color to be used in case $color is not + * recognized as a hexadecimal color. + * + * @return array Returns an associative array with the values of (R)ed, (G)reen and (B)lue + * + * @access private + */ + function _hex2rgb($color, $default_on_error = '#FFFFFF') + { + + // if color is not formatted correctly + // use the default color + if (preg_match('/^#?([a-f]|[0-9]){3}(([a-f]|[0-9]){3})?$/i', $color) == 0) $color = $default_on_error; + + // trim off the "#" prefix from $background_color + $color = ltrim($color, '#'); + + // if color is given using the shorthand (i.e. "FFF" instead of "FFFFFF") + if (strlen($color) == 3) { + + $tmp = ''; + + // take each value + // and duplicate it + for ($i = 0; $i < 3; $i++) $tmp .= str_repeat($color[$i], 2); + + // the color in it's full, 6 characters length notation + $color = $tmp; + + } + + // decimal representation of the color + $int = hexdec($color); + + // extract and return the RGB values + return array( + + 'r' => 0xFF & ($int >> 0x10), + 'g' => 0xFF & ($int >> 0x8), + 'b' => 0xFF & $int + + ); + + } + + /** + * Flips horizontally or vertically or both ways the image given as {@link source_path}. + * + * @since 2.1 + * + * @access private + * + * @return boolean Returns TRUE on success or FALSE on error. + * + * If FALSE is returned, check the {@link error} property to see the error code. + */ + function _flip($orientation) + { + + // if image resource was successfully created + if ($this->_create_from_source()) { + + // prepare the target image + $target_identifier = $this->_prepare_image($this->source_width, $this->source_height, -1); + + // flip according to $orientation + switch ($orientation) { + + case 'horizontal': + + imagecopyresampled( + + $target_identifier, + $this->source_identifier, + 0, + 0, + ($this->source_width - 1), + 0, + $this->source_width, + $this->source_height, + -$this->source_width, + $this->source_height + + ); + + break; + + case 'vertical': + + imagecopyresampled( + + $target_identifier, + $this->source_identifier, + 0, + 0, + 0, + ($this->source_height - 1), + $this->source_width, + $this->source_height, + $this->source_width, + -$this->source_height + + ); + + break; + + case 'both': + + imagecopyresampled( + + $target_identifier, + $this->source_identifier, + 0, + 0, + ($this->source_width - 1), + ($this->source_height - 1), + $this->source_width, + $this->source_height, + -$this->source_width, + -$this->source_height + + ); + + break; + + } + + // write image + return $this->_write_image($target_identifier); + + } + + // if script gets this far, return false + // note that we do not set the error level as it has been already set + // by the _create_from_source() method earlier + return false; + + } + + /** + * Creates a blank image of given width, height and background color. + * + * @param integer $width Width of the new image. + * + * @param integer $height Height of the new image. + * + * @param string $background_color (Optional) The hexadecimal color of the background. + * + * Can also be -1 case in which the script will try to create a transparent + * image, if possible. + * + * Default is "#FFFFFF". + * + * @return Returns the identifier of the newly created image. + * + * @access private + */ + function _prepare_image($width, $height, $background_color = '#FFFFFF') + { + + // create a blank image + $identifier = imagecreatetruecolor((int)$width <= 0 ? 1 : (int)$width, (int)$height <= 0 ? 1 : (int)$height); + + // if we are creating a PNG image + if ($this->target_type == 'png' && $background_color == -1) { + + // disable blending + imagealphablending($identifier, false); + + // allocate a transparent color + $transparent_color = imagecolorallocatealpha($identifier, 0, 0, 0, 127); + + // fill the image with the transparent color + imagefill($identifier, 0, 0, $transparent_color); + + //save full alpha channel information + imagesavealpha($identifier, true); + + // if source image is a transparent GIF + } elseif ($this->target_type == 'gif' && $background_color == -1 && $this->source_transparent_color_index >= 0) { + + // allocate the source image's transparent color also to the new image resource + $transparent_color = imagecolorallocate( + $identifier, + $this->source_transparent_color['red'], + $this->source_transparent_color['green'], + $this->source_transparent_color['blue'] + ); + + // fill the background of the new image with transparent color + imagefill($identifier, 0, 0, $transparent_color); + + // from now on, every pixel having the same RGB as the transparent color will be transparent + imagecolortransparent($identifier, $transparent_color); + + // for other image types + } else { + + // if transparent background color specified, revert to white + if ($background_color == -1) $background_color = '#FFFFFF'; + + // convert hex color to rgb + $background_color = $this->_hex2rgb($background_color); + + // prepare the background color + $background_color = imagecolorallocate($identifier, $background_color['r'], $background_color['g'], $background_color['b']); + + // fill the image with the background color + imagefill($identifier, 0, 0, $background_color); + + } + + // return the image's identifier + return $identifier; + + } + + /** + * Sharpens images. Useful when creating thumbnails. + * + * Code taken from the comments at {@link http://docs.php.net/imageconvolution}. + * + * This function will yield a result only for PHP version 5.1.0+ and will leave the image unaltered for older + * versions! + * + * @param $identifier identifier An image identifier + * + * @access private + */ + function _sharpen_image($image) + { + + // if the "sharpen_images" is set to true and we're running an appropriate version of PHP + // (the "imageconvolution" is available only for PHP 5.1.0+) + if ($this->sharpen_images && version_compare(PHP_VERSION, '5.1.0') >= 0) { + + // the convolution matrix as an array of three arrays of three floats + $matrix = array( + array(-1.2, -1, -1.2), + array(-1, 20, -1), + array(-1.2, -1, -1.2), + ); + + // the divisor of the matrix + $divisor = array_sum(array_map('array_sum', $matrix)); + + // color offset + $offset = 0; + + // sharpen image + imageconvolution($image, $matrix, $divisor, $offset); + + } + + // return the image's identifier + return $image; + + } + + /** + * Creates a new image from given image identifier having the extension as specified by {@link target_path}. + * + * @param $identifier identifier An image identifier + * + * @return boolean Returns TRUE on success or FALSE on error. + * + * If FALSE is returned, check the {@link error} property to see the error code. + * + * @access private + */ + function _write_image($identifier) + { + + // sharpen image if it's required + $this->_sharpen_image($identifier); + + // image saving process goes according to required extension + switch ($this->target_type) { + + // if GIF + case 'gif': + + // if GD support for this file type is not available + // in version 1.6 of GD the support for GIF files was dropped see + // http://php.net/manual/en/function.imagegif.php#function.imagegif.notes + if (!function_exists('imagegif')) { + + // save the error level and stop the execution of the script + $this->error = 6; + + return false; + + // if, for some reason, file could not be created + } elseif (@!imagegif($identifier, $this->target_path)) { + + // save the error level and stop the execution of the script + $this->error = 3; + + return false; + + } + + break; + + // if JPEG + case 'jpg': + case 'jpeg': + + // if GD support for this file type is not available + if (!function_exists('imagejpeg')) { + + // save the error level and stop the execution of the script + $this->error = 6; + + return false; + + // if, for some reason, file could not be created + } elseif (@!imagejpeg($identifier, $this->target_path, $this->jpeg_quality)) { + + // save the error level and stop the execution of the script + $this->error = 3; + + return false; + + } + + break; + + // if PNG + case 'png': + + // save full alpha channel information + imagesavealpha($identifier, true); + + // if GD support for this file type is not available + if (!function_exists('imagepng')) { + + // save the error level and stop the execution of the script + $this->error = 6; + + return false; + + // if, for some reason, file could not be created + } elseif (@!imagepng($identifier, $this->target_path, $this->png_compression)) { + + // save the error level and stop the execution of the script + $this->error = 3; + + return false; + + } + + break; + + // if not a supported file extension + default: + + // save the error level and stop the execution of the script + $this->error = 5; + + return false; + + } + + // get a list of functions disabled via configuration + $disabled_functions = @ini_get('disable_functions'); + + // if the 'chmod' function is not disabled via configuration + if ($disabled_functions == '' || strpos('chmod', $disabled_functions) === false) { + + // chmod the file + chmod($this->target_path, intval($this->chmod_value, 8)); + + // save the error level + } else $this->error = 8; + + // if target file has to have the same timestamp as the source image + if ($this->preserve_time && isset($this->source_image_time)) { + + // touch the newly created file + @touch($this->target_path, $this->source_image_time); + + } + + // return true + return true; + + } + +} diff --git a/css/jasny-bootstrap.min.css b/css/jasny-bootstrap.min.css new file mode 100644 index 0000000..58d244f --- /dev/null +++ b/css/jasny-bootstrap.min.css @@ -0,0 +1,7 @@ +/*! + * Jasny Bootstrap v3.1.0 (http://jasny.github.io/bootstrap) + * Copyright 2012-2014 Arnold Daniels + * Licensed under Apache-2.0 (https://github.com/jasny/bootstrap/blob/master/LICENSE) + */ + +@media (min-width:1px){.container-smooth{max-width:1170px}}.btn-labeled{padding-top:0;padding-bottom:0}.btn-label{position:relative;background:0 0;background:rgba(0,0,0,.15);display:inline-block;padding:6px 12px;left:-12px;border-radius:3px 0 0 3px}.btn-label.btn-label-right{left:auto;right:-12px;border-radius:0 3px 3px 0}.btn-lg .btn-label{padding:10px 16px;left:-16px;border-radius:5px 0 0 5px}.btn-lg .btn-label.btn-label-right{left:auto;right:-16px;border-radius:0 5px 5px 0}.btn-sm .btn-label{padding:5px 10px;left:-10px;border-radius:2px 0 0 2px}.btn-sm .btn-label.btn-label-right{left:auto;right:-10px;border-radius:0 2px 2px 0}.btn-xs .btn-label{padding:1px 5px;left:-5px;border-radius:2px 0 0 2px}.btn-xs .btn-label.btn-label-right{left:auto;right:-5px;border-radius:0 2px 2px 0}.nav-tabs-bottom{border-bottom:0;border-top:1px solid #ddd}.nav-tabs-bottom>li{margin-bottom:0;margin-top:-1px}.nav-tabs-bottom>li>a{border-radius:0 0 4px 4px}.nav-tabs-bottom>li>a:hover,.nav-tabs-bottom>li>a:focus,.nav-tabs-bottom>li.active>a,.nav-tabs-bottom>li.active>a:hover,.nav-tabs-bottom>li.active>a:focus{border:1px solid #ddd;border-top-color:transparent}.nav-tabs-left{border-bottom:0;border-right:1px solid #ddd}.nav-tabs-left>li{margin-bottom:0;margin-right:-1px;float:none}.nav-tabs-left>li>a{border-radius:4px 0 0 4px;margin-right:0;margin-bottom:2px}.nav-tabs-left>li>a:hover,.nav-tabs-left>li>a:focus,.nav-tabs-left>li.active>a,.nav-tabs-left>li.active>a:hover,.nav-tabs-left>li.active>a:focus{border:1px solid #ddd;border-right-color:transparent}.row>.nav-tabs-left{padding-right:0;padding-left:15px;margin-right:-1px;position:relative;z-index:1}.row>.nav-tabs-left+.tab-content{border-left:1px solid #ddd}.nav-tabs-right{border-bottom:0;border-left:1px solid #ddd}.nav-tabs-right>li{margin-bottom:0;margin-left:-1px;float:none}.nav-tabs-right>li>a{border-radius:0 4px 4px 0;margin-left:0;margin-bottom:2px}.nav-tabs-right>li>a:hover,.nav-tabs-right>li>a:focus,.nav-tabs-right>li.active>a,.nav-tabs-right>li.active>a:hover,.nav-tabs-right>li.active>a:focus{border:1px solid #ddd;border-left-color:transparent}.row>.nav-tabs-right{padding-left:0;padding-right:15px}.navmenu,.navbar-offcanvas{width:300px;height:100%;border-width:1px;border-style:solid;border-radius:4px}.navmenu-fixed-left,.navmenu-fixed-right,.navbar-offcanvas{position:fixed;z-index:1030;top:0;border-radius:0}.navmenu-fixed-left,.navbar-offcanvas{left:0;border-width:0 1px 0 0}.navmenu-fixed-right{right:0;border-width:0 0 0 1px}.navmenu-nav{margin-bottom:10px}.navmenu-nav.dropdown-menu{position:static;margin:0;padding-top:0;float:none;border:0;-webkit-box-shadow:none;box-shadow:none;border-radius:0}.navbar-offcanvas .navbar-nav{margin:0}@media (min-width:768px){.navbar-offcanvas{width:auto;border-top:0;box-shadow:none}.navbar-offcanvas.offcanvas{position:static;display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-offcanvas .navbar-nav.navbar-left:first-child{margin-left:-15px}.navbar-offcanvas .navbar-nav.navbar-right:last-child{margin-right:-15px}.navbar-offcanvas .navmenu-brand{display:none}}.navmenu-brand{display:block;font-size:18px;line-height:20px;padding:10px 15px;margin:10px 0}.navmenu-brand:hover,.navmenu-brand:focus{text-decoration:none}.navmenu-default,.navbar-default .navbar-offcanvas{background-color:#f8f8f8;border-color:#e7e7e7}.navmenu-default .navmenu-brand,.navbar-default .navbar-offcanvas .navmenu-brand{color:#777}.navmenu-default .navmenu-brand:hover,.navbar-default .navbar-offcanvas .navmenu-brand:hover,.navmenu-default .navmenu-brand:focus,.navbar-default .navbar-offcanvas .navmenu-brand:focus{color:#5e5e5e;background-color:transparent}.navmenu-default .navmenu-text,.navbar-default .navbar-offcanvas .navmenu-text{color:#777}.navmenu-default .navmenu-nav>.dropdown>a:hover .caret,.navbar-default .navbar-offcanvas .navmenu-nav>.dropdown>a:hover .caret,.navmenu-default .navmenu-nav>.dropdown>a:focus .caret,.navbar-default .navbar-offcanvas .navmenu-nav>.dropdown>a:focus .caret{border-top-color:#333;border-bottom-color:#333}.navmenu-default .navmenu-nav>.open>a,.navbar-default .navbar-offcanvas .navmenu-nav>.open>a,.navmenu-default .navmenu-nav>.open>a:hover,.navbar-default .navbar-offcanvas .navmenu-nav>.open>a:hover,.navmenu-default .navmenu-nav>.open>a:focus,.navbar-default .navbar-offcanvas .navmenu-nav>.open>a:focus{background-color:#e7e7e7;color:#555}.navmenu-default .navmenu-nav>.open>a .caret,.navbar-default .navbar-offcanvas .navmenu-nav>.open>a .caret,.navmenu-default .navmenu-nav>.open>a:hover .caret,.navbar-default .navbar-offcanvas .navmenu-nav>.open>a:hover .caret,.navmenu-default .navmenu-nav>.open>a:focus .caret,.navbar-default .navbar-offcanvas .navmenu-nav>.open>a:focus .caret{border-top-color:#555;border-bottom-color:#555}.navmenu-default .navmenu-nav>.dropdown>a .caret,.navbar-default .navbar-offcanvas .navmenu-nav>.dropdown>a .caret{border-top-color:#777;border-bottom-color:#777}.navmenu-default .navmenu-nav.dropdown-menu,.navbar-default .navbar-offcanvas .navmenu-nav.dropdown-menu{background-color:#e7e7e7}.navmenu-default .navmenu-nav.dropdown-menu>.divider,.navbar-default .navbar-offcanvas .navmenu-nav.dropdown-menu>.divider{background-color:#f8f8f8}.navmenu-default .navmenu-nav.dropdown-menu>.active>a,.navbar-default .navbar-offcanvas .navmenu-nav.dropdown-menu>.active>a,.navmenu-default .navmenu-nav.dropdown-menu>.active>a:hover,.navbar-default .navbar-offcanvas .navmenu-nav.dropdown-menu>.active>a:hover,.navmenu-default .navmenu-nav.dropdown-menu>.active>a:focus,.navbar-default .navbar-offcanvas .navmenu-nav.dropdown-menu>.active>a:focus{background-color:#d7d7d7}.navmenu-default .navmenu-nav>li>a,.navbar-default .navbar-offcanvas .navmenu-nav>li>a{color:#777}.navmenu-default .navmenu-nav>li>a:hover,.navbar-default .navbar-offcanvas .navmenu-nav>li>a:hover,.navmenu-default .navmenu-nav>li>a:focus,.navbar-default .navbar-offcanvas .navmenu-nav>li>a:focus{color:#333;background-color:transparent}.navmenu-default .navmenu-nav>.active>a,.navbar-default .navbar-offcanvas .navmenu-nav>.active>a,.navmenu-default .navmenu-nav>.active>a:hover,.navbar-default .navbar-offcanvas .navmenu-nav>.active>a:hover,.navmenu-default .navmenu-nav>.active>a:focus,.navbar-default .navbar-offcanvas .navmenu-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.navmenu-default .navmenu-nav>.disabled>a,.navbar-default .navbar-offcanvas .navmenu-nav>.disabled>a,.navmenu-default .navmenu-nav>.disabled>a:hover,.navbar-default .navbar-offcanvas .navmenu-nav>.disabled>a:hover,.navmenu-default .navmenu-nav>.disabled>a:focus,.navbar-default .navbar-offcanvas .navmenu-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navmenu-inverse,.navbar-inverse .navbar-offcanvas{background-color:#222;border-color:#080808}.navmenu-inverse .navmenu-brand,.navbar-inverse .navbar-offcanvas .navmenu-brand{color:#999}.navmenu-inverse .navmenu-brand:hover,.navbar-inverse .navbar-offcanvas .navmenu-brand:hover,.navmenu-inverse .navmenu-brand:focus,.navbar-inverse .navbar-offcanvas .navmenu-brand:focus{color:#fff;background-color:transparent}.navmenu-inverse .navmenu-text,.navbar-inverse .navbar-offcanvas .navmenu-text{color:#999}.navmenu-inverse .navmenu-nav>.dropdown>a:hover .caret,.navbar-inverse .navbar-offcanvas .navmenu-nav>.dropdown>a:hover .caret,.navmenu-inverse .navmenu-nav>.dropdown>a:focus .caret,.navbar-inverse .navbar-offcanvas .navmenu-nav>.dropdown>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}.navmenu-inverse .navmenu-nav>.open>a,.navbar-inverse .navbar-offcanvas .navmenu-nav>.open>a,.navmenu-inverse .navmenu-nav>.open>a:hover,.navbar-inverse .navbar-offcanvas .navmenu-nav>.open>a:hover,.navmenu-inverse .navmenu-nav>.open>a:focus,.navbar-inverse .navbar-offcanvas .navmenu-nav>.open>a:focus{background-color:#080808;color:#fff}.navmenu-inverse .navmenu-nav>.open>a .caret,.navbar-inverse .navbar-offcanvas .navmenu-nav>.open>a .caret,.navmenu-inverse .navmenu-nav>.open>a:hover .caret,.navbar-inverse .navbar-offcanvas .navmenu-nav>.open>a:hover .caret,.navmenu-inverse .navmenu-nav>.open>a:focus .caret,.navbar-inverse .navbar-offcanvas .navmenu-nav>.open>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}.navmenu-inverse .navmenu-nav>.dropdown>a .caret,.navbar-inverse .navbar-offcanvas .navmenu-nav>.dropdown>a .caret{border-top-color:#999;border-bottom-color:#999}.navmenu-inverse .navmenu-nav.dropdown-menu,.navbar-inverse .navbar-offcanvas .navmenu-nav.dropdown-menu{background-color:#080808}.navmenu-inverse .navmenu-nav.dropdown-menu>.divider,.navbar-inverse .navbar-offcanvas .navmenu-nav.dropdown-menu>.divider{background-color:#222}.navmenu-inverse .navmenu-nav.dropdown-menu>.active>a,.navbar-inverse .navbar-offcanvas .navmenu-nav.dropdown-menu>.active>a,.navmenu-inverse .navmenu-nav.dropdown-menu>.active>a:hover,.navbar-inverse .navbar-offcanvas .navmenu-nav.dropdown-menu>.active>a:hover,.navmenu-inverse .navmenu-nav.dropdown-menu>.active>a:focus,.navbar-inverse .navbar-offcanvas .navmenu-nav.dropdown-menu>.active>a:focus{background-color:#000}.navmenu-inverse .navmenu-nav>li>a,.navbar-inverse .navbar-offcanvas .navmenu-nav>li>a{color:#999}.navmenu-inverse .navmenu-nav>li>a:hover,.navbar-inverse .navbar-offcanvas .navmenu-nav>li>a:hover,.navmenu-inverse .navmenu-nav>li>a:focus,.navbar-inverse .navbar-offcanvas .navmenu-nav>li>a:focus{color:#fff;background-color:transparent}.navmenu-inverse .navmenu-nav>.active>a,.navbar-inverse .navbar-offcanvas .navmenu-nav>.active>a,.navmenu-inverse .navmenu-nav>.active>a:hover,.navbar-inverse .navbar-offcanvas .navmenu-nav>.active>a:hover,.navmenu-inverse .navmenu-nav>.active>a:focus,.navbar-inverse .navbar-offcanvas .navmenu-nav>.active>a:focus{color:#fff;background-color:#080808}.navmenu-inverse .navmenu-nav>.disabled>a,.navbar-inverse .navbar-offcanvas .navmenu-nav>.disabled>a,.navmenu-inverse .navmenu-nav>.disabled>a:hover,.navbar-inverse .navbar-offcanvas .navmenu-nav>.disabled>a:hover,.navmenu-inverse .navmenu-nav>.disabled>a:focus,.navbar-inverse .navbar-offcanvas .navmenu-nav>.disabled>a:focus{color:#444;background-color:transparent}.alert-fixed-top,.alert-fixed-bottom{position:fixed;width:100%;z-index:1035;border-radius:0;margin:0;left:0}@media (min-width:992px){.alert-fixed-top,.alert-fixed-bottom{width:992px;left:50%;margin-left:-496px}}.alert-fixed-top{top:0;border-width:0 0 1px}@media (min-width:992px){.alert-fixed-top{border-bottom-right-radius:4px;border-bottom-left-radius:4px;border-width:0 1px 1px}}.alert-fixed-bottom{bottom:0;border-width:1px 0 0}@media (min-width:992px){.alert-fixed-bottom{border-top-right-radius:4px;border-top-left-radius:4px;border-width:1px 1px 0}}.offcanvas{display:none}.offcanvas.in{display:block}@media (max-width:767px){.offcanvas-xs{display:none}.offcanvas-xs.in{display:block}}@media (max-width:991px){.offcanvas-sm{display:none}.offcanvas-sm.in{display:block}}@media (max-width:1199px){.offcanvas-md{display:none}.offcanvas-md.in{display:block}}.offcanvas-lg{display:none}.offcanvas-lg.in{display:block}.canvas-sliding{-webkit-transition:top .35s,left .35s,bottom .35s,right .35s;transition:top .35s,left .35s,bottom .35s,right .35s}.offcanvas-clone{height:0!important;width:0!important;overflow:hidden!important;border:0!important;margin:0!important;padding:0!important;position:absolute!important;top:auto!important;left:auto!important;bottom:0!important;right:0!important;opacity:0!important}.table.rowlink td:not(.rowlink-skip),.table .rowlink td:not(.rowlink-skip){cursor:pointer}.table.rowlink td:not(.rowlink-skip) a,.table .rowlink td:not(.rowlink-skip) a{color:inherit;font:inherit;text-decoration:inherit}.table-hover.rowlink tr:hover td,.table-hover .rowlink tr:hover td{background-color:#cfcfcf}.btn-file{overflow:hidden;position:relative;vertical-align:middle}.btn-file>input{position:absolute;top:0;right:0;margin:0;opacity:0;filter:alpha(opacity=0);transform:translate(-300px,0) scale(4);font-size:23px;height:100%;direction:ltr;cursor:pointer}.fileinput{margin-bottom:9px;display:inline-block}.fileinput .form-control{padding-top:7px;padding-bottom:5px;display:inline-block;margin-bottom:0;vertical-align:middle;cursor:text}.fileinput .thumbnail{overflow:hidden;display:inline-block;margin-bottom:5px;vertical-align:middle;text-align:center}.fileinput .thumbnail>img{max-height:100%}.fileinput .btn{vertical-align:middle}.fileinput-exists .fileinput-new,.fileinput-new .fileinput-exists{display:none}.fileinput-inline .fileinput-controls{display:inline}.fileinput-filename{vertical-align:middle;display:inline-block;overflow:hidden}.form-control .fileinput-filename{vertical-align:bottom}.fileinput-new .input-group .btn-file{border-radius:0 4px 4px 0}.fileinput-new .input-group .btn-file.btn-xs,.fileinput-new .input-group .btn-file.btn-sm{border-radius:0 3px 3px 0}.fileinput-new .input-group .btn-file.btn-lg{border-radius:0 6px 6px 0}.form-group.has-warning .fileinput .fileinput-preview{color:#8a6d3b}.form-group.has-warning .fileinput .thumbnail{border-color:#faebcc}.form-group.has-error .fileinput .fileinput-preview{color:#a94442}.form-group.has-error .fileinput .thumbnail{border-color:#ebccd1}.form-group.has-success .fileinput .fileinput-preview{color:#3c763d}.form-group.has-success .fileinput .thumbnail{border-color:#d6e9c6}.input-group-addon:not(:first-child){border-left:0} \ No newline at end of file diff --git a/css/jasny-bootstrap.min.js b/css/jasny-bootstrap.min.js new file mode 100644 index 0000000..05b3b05 --- /dev/null +++ b/css/jasny-bootstrap.min.js @@ -0,0 +1,6 @@ +/*! + * Jasny Bootstrap v3.1.0 (http://jasny.github.io/bootstrap) + * Copyright 2012-2014 Arnold Daniels + * Licensed under Apache-2.0 (https://github.com/jasny/bootstrap/blob/master/LICENSE) + */ +if("undefined"==typeof jQuery)throw new Error("Jasny Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=function(c,d){this.$element=a(c),this.options=a.extend({},b.DEFAULTS,d),this.state=null,this.options.recalc&&(this.calcClone(),a(window).on("resize",a.proxy(this.recalc,this))),this.options.autohide&&a(document).on("click",a.proxy(this.autohide,this)),this.options.toggle&&this.toggle()};b.DEFAULTS={toggle:!0,placement:"left",autohide:!0,recalc:!0},b.prototype.offset=function(){switch(this.options.placement){case"left":case"right":return this.$element.outerWidth();case"top":case"bottom":return this.$element.outerHeight()}},b.prototype.calcPlacement=function(){function b(a,b){if("auto"===e.css(b))return a;if("auto"===e.css(a))return b;var c=parseInt(e.css(a),10),d=parseInt(e.css(b),10);return c>d?b:a}var c=a(window).width()/this.$element.width(),d=a(window).height()/this.$element.height();this.$element.hasClass("in")||this.$element.css("visiblity","hidden !important").addClass("in");var e=this.$element;this.options.placement=c>d?b("left","right"):b("top","bottom"),"hidden !important"===this.$element.css("visibility")&&this.$element.removeClass("in").css("visiblity","")},b.prototype.opposite=function(a){switch(a){case"top":return"bottom";case"left":return"right";case"bottom":return"top";case"right":return"left"}},b.prototype.getCanvasElements=function(){var b=this.options.canvas?a(this.options.canvas):this.$element,c=b.find("*").filter(function(){return"fixed"===a(this).css("position")}).not(this.options.exclude);return b.add(c)},b.prototype.slide=function(b,c,d){if(!a.support.transition){var e={};return e[this.options.placement]="+="+c,b.animate(e,350,d)}var f=this.options.placement,g=this.opposite(f);b.each(function(){"auto"!==a(this).css(f)&&a(this).css(f,(parseInt(a(this).css(f),10)||0)+c),"auto"!==a(this).css(g)&&a(this).css(g,(parseInt(a(this).css(g),10)||0)-c)}),this.$element.one(a.support.transition.end,d).emulateTransitionEnd(350)},b.prototype.disableScrolling=function(){var b=a("body").width(),c="padding-"+this.opposite(this.options.placement);if(void 0===a("body").data("offcanvas-style")&&a("body").data("offcanvas-style",a("body").attr("style")),a("body").css("overflow","hidden"),a("body").width()>b){var d=parseInt(a("body").css(c),10)+a("body").width()-b;setTimeout(function(){a("body").css(c,d)},1)}},b.prototype.show=function(){if(!this.state){var b=a.Event("show.bs.offcanvas");if(this.$element.trigger(b),!b.isDefaultPrevented()){"auto"===this.options.placement&&this.calcPlacement(),this.state="sliding";var c=this.getCanvasElements(),d=this.offset(),e=this.options.placement,f=this.opposite(e);c.addClass("canvas-sliding").each(function(){a(this).data("offcanvas-style",a(this).attr("style")||""),"static"===a(this).css("position")&&a(this).css("position","relative"),"auto"!==a(this).css(e)&&"0px"!==a(this).css(e)||"auto"!==a(this).css(f)&&"0px"!==a(this).css(f)||a(this).css(e,0)}),-1!==c.index(this.$element)&&this.$element.css(e,-1*d),this.disableScrolling();var g=function(){this.state="slid",c.removeClass("canvas-sliding").addClass("canvas-slid"),this.$element.trigger("shown.bs.offcanvas")};setTimeout(a.proxy(function(){this.$element.addClass("in"),this.slide(c,d,a.proxy(g,this))},this),1)}}},b.prototype.hide=function(){if("slid"===this.state){var b=a.Event("hide.bs.offcanvas");if(this.$element.trigger(b),!b.isDefaultPrevented()){this.state="sliding";var c=a(".canvas-slid"),d=-1*this.offset(),e=function(){this.state=null,this.$element.removeClass("in"),c.removeClass("canvas-sliding"),c.add("body").each(function(){a(this).attr("style",a(this).data("offcanvas-style")).removeData("offcanvas-style")}),this.$element.trigger("hidden.bs.offcanvas")};c.removeClass("canvas-slid").addClass("canvas-sliding"),setTimeout(a.proxy(function(){this.slide(c,d,a.proxy(e,this))},this),1)}}},b.prototype.toggle=function(){"sliding"!==this.state&&this["slid"===this.state?"hide":"show"]()},b.prototype.calcClone=function(){this.$calcClone=this.$element.clone().html("").addClass("offcanvas-clone").removeClass("in").appendTo(a("body"))},b.prototype.recalc=function(){if("slid"===this.state()&&"none"!==this.$calcClone.css("display")){var b=-1*this.offset(),c=this.options.placement;this.getCanvasElements().each(function(){a(this).css(c,(parseInt(a(this).css(c),10)||0)+b)}).removeClass("canvas-slid"),a("body").css("overflow",""),this.$element.css(c,"").removeClass("in canvas-slid")}},b.prototype.autohide=function(b){0===a(b.target).closest(this.$element).length&&this.hide()};var c=a.fn.offcanvas;a.fn.offcanvas=function(c){return this.each(function(){var d=a(this),e=d.data("bs.offcanvas"),f=a.extend({},b.DEFAULTS,d.data(),"object"==typeof c&&c);e||d.data("bs.offcanvas",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.offcanvas.Constructor=b,a.fn.offcanvas.noConflict=function(){return a.fn.offcanvas=c,this},a(document).on("click.bs.offcanvas.data-api","[data-toggle=offcanvas]",function(b){var c,d=a(this),e=d.attr("data-target")||b.preventDefault()||(c=d.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,""),f=a(e),g=f.data("bs.offcanvas"),h=g?"toggle":d.data();b.stopPropagation(),g?g.toggle():f.offcanvas(h)})}(window.jQuery),+function(a){"use strict";var b=function(c,d){this.$element=a(c),this.options=a.extend({},b.DEFAULTS,d),this.$element.on("click.bs.rowlink","td:not(.rowlink-skip)",a.proxy(this.click,this))};b.DEFAULTS={target:"a"},b.prototype.click=function(b){var c=a(b.currentTarget).closest("tr").find(this.options.target)[0];if(a(b.target)[0]!==c)if(b.preventDefault(),c.click)c.click();else if(document.createEvent){var d=document.createEvent("MouseEvents");d.initMouseEvent("click",!0,!0,window,0,0,0,0,0,!1,!1,!1,!1,0,null),c.dispatchEvent(d)}};var c=a.fn.rowlink;a.fn.rowlink=function(c){return this.each(function(){var d=a(this),e=d.data("rowlink");e||d.data("rowlink",e=new b(this,c))})},a.fn.rowlink.Constructor=b,a.fn.rowlink.noConflict=function(){return a.fn.rowlink=c,this},a(document).on("click.bs.rowlink.data-api",'[data-link="row"]',function(b){var c=a(this);c.data("rowlink")||(c.rowlink(c.data()),a(b.target).trigger("click.bs.rowlink"))})}(window.jQuery),+function(a){"use strict";var b=void 0!==window.orientation,c=navigator.userAgent.toLowerCase().indexOf("android")>-1,d="Microsoft Internet Explorer"==window.navigator.appName,e=function(b,d){c||(this.$element=a(b),this.options=a.extend({},e.DEFAULS,d),this.mask=String(this.options.mask),this.init(),this.listen(),this.checkVal())};e.DEFAULS={mask:"",placeholder:"_",definitions:{9:"[0-9]",a:"[A-Za-z]","?":"[A-Za-z0-9]","*":"."}},e.prototype.init=function(){var b=this.options.definitions,c=this.mask.length;this.tests=[],this.partialPosition=this.mask.length,this.firstNonMaskPos=null,a.each(this.mask.split(""),a.proxy(function(a,d){"?"==d?(c--,this.partialPosition=a):b[d]?(this.tests.push(new RegExp(b[d])),null===this.firstNonMaskPos&&(this.firstNonMaskPos=this.tests.length-1)):this.tests.push(null)},this)),this.buffer=a.map(this.mask.split(""),a.proxy(function(a){return"?"!=a?b[a]?this.options.placeholder:a:void 0},this)),this.focusText=this.$element.val(),this.$element.data("rawMaskFn",a.proxy(function(){return a.map(this.buffer,function(a,b){return this.tests[b]&&a!=this.options.placeholder?a:null}).join("")},this))},e.prototype.listen=function(){if(!this.$element.attr("readonly")){var b=(d?"paste":"input")+".mask";this.$element.on("unmask.bs.inputmask",a.proxy(this.unmask,this)).on("focus.bs.inputmask",a.proxy(this.focusEvent,this)).on("blur.bs.inputmask",a.proxy(this.blurEvent,this)).on("keydown.bs.inputmask",a.proxy(this.keydownEvent,this)).on("keypress.bs.inputmask",a.proxy(this.keypressEvent,this)).on(b,a.proxy(this.pasteEvent,this))}},e.prototype.caret=function(a,b){if(0!==this.$element.length){if("number"==typeof a)return b="number"==typeof b?b:a,this.$element.each(function(){if(this.setSelectionRange)this.setSelectionRange(a,b);else if(this.createTextRange){var c=this.createTextRange();c.collapse(!0),c.moveEnd("character",b),c.moveStart("character",a),c.select()}});if(this.$element[0].setSelectionRange)a=this.$element[0].selectionStart,b=this.$element[0].selectionEnd;else if(document.selection&&document.selection.createRange){var c=document.selection.createRange();a=0-c.duplicate().moveStart("character",-1e5),b=a+c.text.length}return{begin:a,end:b}}},e.prototype.seekNext=function(a){for(var b=this.mask.length;++a<=b&&!this.tests[a];);return a},e.prototype.seekPrev=function(a){for(;--a>=0&&!this.tests[a];);return a},e.prototype.shiftL=function(a,b){var c=this.mask.length;if(!(0>a)){for(var d=a,e=this.seekNext(b);c>d;d++)if(this.tests[d]){if(!(c>e&&this.tests[d].test(this.buffer[e])))break;this.buffer[d]=this.buffer[e],this.buffer[e]=this.options.placeholder,e=this.seekNext(e)}this.writeBuffer(),this.caret(Math.max(this.firstNonMaskPos,a))}},e.prototype.shiftR=function(a){for(var b=this.mask.length,c=a,d=this.options.placeholder;b>c;c++)if(this.tests[c]){var e=this.seekNext(c),f=this.buffer[c];if(this.buffer[c]=d,!(b>e&&this.tests[e].test(f)))break;d=f}},e.prototype.unmask=function(){this.$element.unbind(".mask").removeData("inputmask")},e.prototype.focusEvent=function(){this.focusText=this.$element.val();var a=this.mask.length,b=this.checkVal();this.writeBuffer();var c=this,d=function(){b==a?c.caret(0,b):c.caret(b)};d(),setTimeout(d,50)},e.prototype.blurEvent=function(){this.checkVal(),this.$element.val()!==this.focusText&&this.$element.trigger("change")},e.prototype.keydownEvent=function(a){var c=a.which;if(8==c||46==c||b&&127==c){var d=this.caret(),e=d.begin,f=d.end;return f-e===0&&(e=46!=c?this.seekPrev(e):f=this.seekNext(e-1),f=46==c?this.seekNext(f):f),this.clearBuffer(e,f),this.shiftL(e,f-1),!1}return 27==c?(this.$element.val(this.focusText),this.caret(0,this.checkVal()),!1):void 0},e.prototype.keypressEvent=function(a){var b=this.mask.length,c=a.which,d=this.caret();if(a.ctrlKey||a.altKey||a.metaKey||32>c)return!0;if(c){d.end-d.begin!==0&&(this.clearBuffer(d.begin,d.end),this.shiftL(d.begin,d.end-1));var e=this.seekNext(d.begin-1);if(b>e){var f=String.fromCharCode(c);if(this.tests[e].test(f)){this.shiftR(e),this.buffer[e]=f,this.writeBuffer();var g=this.seekNext(e);this.caret(g)}}return!1}},e.prototype.pasteEvent=function(){var a=this;setTimeout(function(){a.caret(a.checkVal(!0))},0)},e.prototype.clearBuffer=function(a,b){for(var c=this.mask.length,d=a;b>d&&c>d;d++)this.tests[d]&&(this.buffer[d]=this.options.placeholder)},e.prototype.writeBuffer=function(){return this.$element.val(this.buffer.join("")).val()},e.prototype.checkVal=function(a){for(var b=this.mask.length,c=this.$element.val(),d=-1,e=0,f=0;b>e;e++)if(this.tests[e]){for(this.buffer[e]=this.options.placeholder;f++c.length)break}else this.buffer[e]==c.charAt(f)&&e!=this.partialPosition&&(f++,d=e);return!a&&d+1=this.partialPosition)&&(this.writeBuffer(),a||this.$element.val(this.$element.val().substring(0,d+1))),this.partialPosition?e:this.firstNonMaskPos};var f=a.fn.inputmask;a.fn.inputmask=function(b){return this.each(function(){var c=a(this),d=c.data("inputmask");d||c.data("inputmask",d=new e(this,b))})},a.fn.inputmask.Constructor=e,a.fn.inputmask.noConflict=function(){return a.fn.inputmask=f,this},a(document).on("focus.bs.inputmask.data-api","[data-mask]",function(){var b=a(this);b.data("inputmask")||b.inputmask(b.data())})}(window.jQuery),+function(a){"use strict";var b="Microsoft Internet Explorer"==window.navigator.appName,c=function(b,c){if(this.$element=a(b),this.$input=this.$element.find(":file"),0!==this.$input.length){this.name=this.$input.attr("name")||c.name,this.$hidden=this.$element.find('input[type=hidden][name="'+this.name+'"]'),0===this.$hidden.length&&(this.$hidden=a(''),this.$element.prepend(this.$hidden)),this.$preview=this.$element.find(".fileinput-preview");var d=this.$preview.css("height");"inline"!=this.$preview.css("display")&&"0px"!=d&&"none"!=d&&this.$preview.css("line-height",d),this.original={exists:this.$element.hasClass("fileinput-exists"),preview:this.$preview.html(),hiddenVal:this.$hidden.val()},this.listen()}};c.prototype.listen=function(){this.$input.on("change.bs.fileinput",a.proxy(this.change,this)),a(this.$input[0].form).on("reset.bs.fileinput",a.proxy(this.reset,this)),this.$element.find('[data-trigger="fileinput"]').on("click.bs.fileinput",a.proxy(this.trigger,this)),this.$element.find('[data-dismiss="fileinput"]').on("click.bs.fileinput",a.proxy(this.clear,this))},c.prototype.change=function(b){if(void 0===b.target.files&&(b.target.files=b.target&&b.target.value?[{name:b.target.value.replace(/^.+\\/,"")}]:[]),0!==b.target.files.length){this.$hidden.val(""),this.$hidden.attr("name",""),this.$input.attr("name",this.name);var c=b.target.files[0];if(this.$preview.length>0&&("undefined"!=typeof c.type?c.type.match("image.*"):c.name.match(/\.(gif|png|jpe?g)$/i))&&"undefined"!=typeof FileReader){var d=new FileReader,e=this.$preview,f=this.$element;d.onload=function(d){var g=a("");g[0].src=d.target.result,b.target.files[0].result=d.target.result,f.find(".fileinput-filename").text(c.name),"none"!=e.css("max-height")&&g.css("max-height",parseInt(e.css("max-height"),10)-parseInt(e.css("padding-top"),10)-parseInt(e.css("padding-bottom"),10)-parseInt(e.css("border-top"),10)-parseInt(e.css("border-bottom"),10)),e.html(g),f.addClass("fileinput-exists").removeClass("fileinput-new"),f.trigger("change.bs.fileinput",b.target.files)},d.readAsDataURL(c)}else this.$element.find(".fileinput-filename").text(c.name),this.$preview.text(c.name),this.$element.addClass("fileinput-exists").removeClass("fileinput-new"),this.$element.trigger("change.bs.fileinput")}},c.prototype.clear=function(a){if(a&&a.preventDefault(),this.$hidden.val(""),this.$hidden.attr("name",this.name),this.$input.attr("name",""),b){var c=this.$input.clone(!0);this.$input.after(c),this.$input.remove(),this.$input=c}else this.$input.val("");this.$preview.html(""),this.$element.find(".fileinput-filename").text(""),this.$element.addClass("fileinput-new").removeClass("fileinput-exists"),a!==!1&&(this.$input.trigger("change"),this.$element.trigger("clear.bs.fileinput"))},c.prototype.reset=function(){this.clear(!1),this.$hidden.val(this.original.hiddenVal),this.$preview.html(this.original.preview),this.$element.find(".fileinput-filename").text(""),this.original.exists?this.$element.addClass("fileinput-exists").removeClass("fileinput-new"):this.$element.addClass("fileinput-new").removeClass("fileinput-exists"),this.$element.trigger("reset.bs.fileinput")},c.prototype.trigger=function(a){this.$input.trigger("click"),a.preventDefault()};var d=a.fn.fileinput;a.fn.fileinput=function(b){return this.each(function(){var d=a(this),e=d.data("fileinput");e||d.data("fileinput",e=new c(this,b)),"string"==typeof b&&e[b]()})},a.fn.fileinput.Constructor=c,a.fn.fileinput.noConflict=function(){return a.fn.fileinput=d,this},a(document).on("click.fileinput.data-api",'[data-provides="fileinput"]',function(b){var c=a(this);if(!c.data("fileinput")){c.fileinput(c.data());var d=a(b.target).closest('[data-dismiss="fileinput"],[data-trigger="fileinput"]');d.length>0&&(b.preventDefault(),d.trigger("click.bs.fileinput"))}})}(window.jQuery); \ No newline at end of file diff --git a/img.data/1424.jpg b/img.data/1424.jpg new file mode 100755 index 0000000..f4a0418 Binary files /dev/null and b/img.data/1424.jpg differ diff --git a/img/sinImagen.gif b/img/sinImagen.gif new file mode 100644 index 0000000..dafb559 Binary files /dev/null and b/img/sinImagen.gif differ diff --git a/inc/configuracion.inc b/inc/configuracion.inc index ee26619..767abfc 100644 --- a/inc/configuracion.inc +++ b/inc/configuracion.inc @@ -39,4 +39,5 @@ define('COLORLAT', '#46d6db'); //Color de la barra de menú lateral define('COLORFON', '#a4bdfc'); //Color del fondo de la pantalla define('MYSQLDUMP', '/usr/local/bin/mysqldump'); //camino a mysqldump define('GZIP', '/usr/bin/gzip'); //Camino a gzip +define('IMAGEDATA', 'img.data'); //Directorio donde se almacenarán las imágenes ?> diff --git a/inc/version.inc b/inc/version.inc index 43eba1c..c6d632c 100644 --- a/inc/version.inc +++ b/inc/version.inc @@ -23,5 +23,5 @@ */ define('AUTOR', 'Ricardo Montañana Gómez'); -define('VERSION', '1.04'); +define('VERSION', '1.05'); ?> diff --git a/plant/bootstrap.html b/plant/bootstrap.html index a8ec723..bc696ec 100644 --- a/plant/bootstrap.html +++ b/plant/bootstrap.html @@ -16,6 +16,7 @@ + @@ -88,6 +89,7 @@ - + + \ No newline at end of file diff --git a/sql/setup.sql b/sql/setup.sql index 4e412ec..e3bd21a 100644 --- a/sql/setup.sql +++ b/sql/setup.sql @@ -27,6 +27,7 @@ CREATE TABLE `Articulos` ( `marca` varchar(20) default NULL COMMENT 'ordenable', `modelo` varchar(20) default NULL COMMENT 'ordenable', `cantidad` int(11) default NULL COMMENT 'ordenable', + `imagen` varchar(45) default NULL COMMENT 'imagen', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=785 DEFAULT CHARSET=utf8; SET character_set_client = @saved_cs_client; @@ -46,6 +47,7 @@ CREATE TABLE `Elementos` ( `numserie` varchar(30) default NULL COMMENT 'ordenable', `cantidad` int(10) unsigned default NULL COMMENT 'ordenable', `fechaCompra` date NOT NULL COMMENT 'ordenable', + `imagen` varchar(45) default NULL COMMENT 'imagen', PRIMARY KEY (`id`), KEY `id` (`id`), KEY `id_Articulo` (`id_Articulo`), diff --git a/xml/mantenimientoElementos.xml b/xml/mantenimientoElementos.xml index d97ebd8..2ca88fa 100644 --- a/xml/mantenimientoElementos.xml +++ b/xml/mantenimientoElementos.xml @@ -3,7 +3,7 @@ Mantenimiento de Elementos SELECT SQL_CALC_FOUND_ROWS E.id as id,U.Descripcion as ubicacion,A.Descripcion as articulo,A.Marca as marca,A.Modelo as modelo,E.numserie as numserie, - DATE_FORMAT(E.fechacompra, '%d/%m/%Y') as fechaCompra,E.cantidad as cantidad + DATE_FORMAT(E.fechacompra, '%d/%m/%Y') as fechaCompra,E.cantidad as cantidad, E.imagen as imagen FROM Elementos E inner join Articulos A on E.id_articulo=A.id inner join Ubicaciones U on E.id_ubicacion=U.id {buscar} {orden} limit {inferior},{superior}; @@ -16,5 +16,6 @@ +