1416 lines
59 KiB
PHP
Executable File
1416 lines
59 KiB
PHP
Executable File
<?php
|
|
class CocoDB
|
|
{
|
|
public static $tableCache = [];
|
|
public static $uploadColumns = [];
|
|
public static $queryCaches = [];
|
|
public static $getCaches = [];
|
|
public static $storeDebugData = false;
|
|
public static $debugData = [];
|
|
public static $trackData = [];
|
|
public static $redis = null;
|
|
public static $redis_expireTime = 0;
|
|
public static $force_load_cache = false;
|
|
public static $force_redis = false;
|
|
public static $force_redis_module = false;
|
|
public static $force_redis_html = false;
|
|
public static $force_json_cache_uploads = false;
|
|
public static $pluginsConfig = [];
|
|
public static $backTracePoint = null;
|
|
public static $defaultRelationsDepth = 2;
|
|
public static $noCacheURIS = []; // Array de expresiones regulares que contengan las URLS
|
|
public static $noCacheTABLES = []; // Array de Tablas
|
|
public static $allowedTranslateFields = null; // Campos permitidos para la traducción
|
|
/**
|
|
* Inserta registros en una tabla
|
|
* @destacar
|
|
* @category DB
|
|
* @param table: Tabla de inserción
|
|
* @param records: Lista de registros a insertar
|
|
* @param functions: Array asociativo con funciones a aplicar a cada key
|
|
* @param options: Lista de opciones posibles que pasarle al método
|
|
* @return Número de registros insertados
|
|
*/
|
|
static function insertRecords($table, $records, $functions = [], $options = [])
|
|
{
|
|
|
|
if (!isset($records[0])) {
|
|
$records = [$records];
|
|
}
|
|
if (@$options["preSaveTempId"]) {
|
|
$preSave = true;
|
|
}
|
|
|
|
list($ignoreFields, $ignoreSchema, $prefix) = self::parse_options($options);
|
|
|
|
if (!$ignoreSchema) {
|
|
$schema = @loadSchema($table);
|
|
if (!@$schema) self::error(["error" => 'Error. Tabla no encontrada']);
|
|
}
|
|
|
|
|
|
$result = 0;
|
|
$lastSaved = 0;
|
|
|
|
foreach ($records as $record) :
|
|
$sqlBase = self::prepareBaseSQL($prefix, $table, @$schema, false, $ignoreFields, $record);
|
|
$record = self::unsetKeys($record, $ignoreFields);
|
|
if (!in_array("num", @$ignoreFields) && isset($record["num"])) {
|
|
$sqlBase = str_replace("num=NULL", "num=" . intval(@$record["num"]), $sqlBase);
|
|
$record = self::unsetKeys($record, ["num"]);
|
|
}
|
|
self::insertOrUpdate($record, $sqlBase, $result, null, $prefix . $table, $functions, $ignoreSchema, @$schema, $options);
|
|
$lastSaved = mysql_insert_id();
|
|
foreach (self::$uploadColumns as $keyColumn => $uploadColumn) {
|
|
foreach ($uploadColumn as $keyCol => $urlPath) {
|
|
if (!@$urlPath) continue;
|
|
self::insertRecords("uploads", [
|
|
"urlPath" => $urlPath,
|
|
"filePath" => realpath(__DIR__ . "/../../../" . $urlPath),
|
|
"fieldName" => $keyColumn,
|
|
"recordNum" => $lastSaved,
|
|
"tableName" => $table,
|
|
"createdTime" => date("Y-m-d H:i:s"),
|
|
"order" => time() + $keyCol,
|
|
"width" => 640,
|
|
"height" => 480
|
|
], [], ["ignoreSchema" => true]);
|
|
}
|
|
}
|
|
|
|
endforeach;
|
|
|
|
|
|
if (@$preSave) {
|
|
$query = "UPDATE {$prefix}uploads "
|
|
. " SET recordNum = LAST_INSERT_ID(), preSaveTempId = '' "
|
|
. " WHERE tableName = '" . mysql_real_escape_string($table) . "' AND "
|
|
. " preSaveTempId = '" . mysql_real_escape_string($options["preSaveTempId"]) . "'";
|
|
|
|
mysql_query($query) or self::error(["error" => "MySQL Error: " . htmlspecialchars(mysql_error()) . "\n"]);
|
|
|
|
$query = "UPDATE {$prefix}traducciones "
|
|
. " SET recordNum = LAST_INSERT_ID(), preSaveTempId = '' "
|
|
. " WHERE tableName = '" . mysql_real_escape_string($table) . "' AND "
|
|
. " preSaveTempId = '" . mysql_real_escape_string($options["preSaveTempId"]) . "'";
|
|
mysql_query($query) or self::error(["error" => "MySQL Error: " . htmlspecialchars(mysql_error()) . "\n"]);
|
|
}
|
|
|
|
if (@$options['generate_category_metadata']) {
|
|
self::updateCategoryMetadata($table);
|
|
}
|
|
|
|
if (@$options['return_last_id']) {
|
|
return $lastSaved;
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Elimina registros de una tabla
|
|
* @destacar
|
|
* @category DB
|
|
* @param table: Tabla de la que vamos a eliminar registros
|
|
* @param where: Array asociativo que recoge campo => valor, operador, or
|
|
* @return boolean que indica si se pudo ejecutar la consulta
|
|
*/
|
|
static function deleteRecords($table, $where, $options = [])
|
|
{
|
|
list($_, $_, $prefix) = self::parse_options($options);
|
|
|
|
$where = self::parse_where($where, $table, $prefix);
|
|
|
|
if (!@$where) return false;
|
|
|
|
$sql = "DELETE FROM $prefix$table WHERE $where";
|
|
|
|
if (@$options['dieBeforeQuery'] && $table == "uploads") {
|
|
self::error(["info" => $sql]);
|
|
}
|
|
|
|
$q = mysql_query($sql);
|
|
if (!$q) return false;
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Actualiza registros en una tabla
|
|
* @destacar
|
|
* @category DB
|
|
* @param table: Tabla de inserción
|
|
* @param records: Lista de registros a insertar
|
|
* @param functions: Array asociativo con funciones a aplicar a cada key
|
|
* @param options: Lista de opciones posibles que pasarle al método
|
|
* @return Número de registros insertados
|
|
*/
|
|
static function updateRecords($table, $records, $where, $functions = [], $options = [])
|
|
{
|
|
global $TABLE_PREFIX;
|
|
|
|
if (!isset($records[0])) {
|
|
$records = [$records];
|
|
}
|
|
|
|
list($ignoreFields, $ignoreSchema, $prefix) = self::parse_options($options);
|
|
|
|
if (!$ignoreSchema) {
|
|
$schema = @loadSchema($table);
|
|
if (!@$schema) self::error(["error" => 'Error. Tabla no encontrada']);
|
|
}
|
|
|
|
$result = 0;
|
|
foreach ($records as $record) :
|
|
$sqlBase = self::prepareBaseSQL($prefix, $table, @$schema, true, $ignoreFields, $record);
|
|
$lastNum = @$record['num'];
|
|
$record = self::unsetKeys($record, $ignoreFields);
|
|
// Está comentado, pero no se si hace falta, si se descomenta se rompe el guardar del Builder (Plugin)
|
|
// if (@$schema['menuType'] == 'category' && !isset($record['parentNum'])) {
|
|
// continue;
|
|
// }
|
|
|
|
self::insertOrUpdate($record, $sqlBase, $result, $where, $prefix . $table, $functions, $ignoreSchema, @$schema, $options);
|
|
|
|
if (@$lastNum && @$options['delete_upload_nums']) {
|
|
// El Prefix se añade "por la cara" porque el show_columns peta sin el
|
|
self::deleteRecords("uploads", [
|
|
["column" => "num", "value" => $options['delete_upload_nums'], "operator" => "IN"]
|
|
], ["prefix" => $TABLE_PREFIX]);
|
|
}
|
|
|
|
foreach (self::$uploadColumns as $keyColumn => $uploadColumn) {
|
|
// El Prefix se añade "por la cara" por lo mismo que el delete_upload_nums aunque este no está probado
|
|
if (@$lastNum && @$options['delete_old_uploads']) {
|
|
self::deleteRecords("uploads", [
|
|
"fieldName" => $keyColumn,
|
|
"recordNum" => $lastNum,
|
|
"tableName" => $table,
|
|
], ["prefix" => $TABLE_PREFIX]);
|
|
}
|
|
|
|
foreach ($uploadColumn as $keyCol => $urlPath) {
|
|
|
|
if (@$lastNum && @$options['insert_new_uploads']) {
|
|
self::insertRecords("uploads", [
|
|
"urlPath" => $urlPath,
|
|
"filePath" => realpath(__DIR__ . "/../../../" . $urlPath),
|
|
"fieldName" => $keyColumn,
|
|
"recordNum" => $lastNum,
|
|
"tableName" => $table,
|
|
"createdTime" => date("Y-m-d H:i:s"),
|
|
"order" => time() + $keyCol,
|
|
"width" => 640,
|
|
"height" => 480
|
|
], [], ["ignoreSchema" => true]);
|
|
}
|
|
}
|
|
}
|
|
endforeach;
|
|
|
|
if (@$options['generate_category_metadata']) {
|
|
self::updateCategoryMetadata($table);
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
|
|
/**
|
|
* Hace el insert o update de un único registro
|
|
* @param record: Registro con el que vamos a operar
|
|
* @param sqlBase: SQL Base
|
|
* @param result: Número de registros con los que hemos operado. In-out
|
|
* @param where: Where de la operación (solo si es un UPDATE)
|
|
* @param table: Tabla de la operación
|
|
* @param functions: Lista de funciones con las que podemos parsear un determinado valor
|
|
* @param ignoreSchema: Boolean que indica si vamos a ignorar el Schema o no
|
|
* @param schema: Schema de la tabla
|
|
*/
|
|
public static function insertOrUpdate($record, $sqlBase, &$result, $where = null, $table = null, $functions = null, $ignoreSchema = false, $schema = null, $options = [])
|
|
{
|
|
$sql = $sqlBase;
|
|
self::$uploadColumns = [];
|
|
foreach ($record as $key => $value) :
|
|
$column_exists = self::column_exists($key, @$schema, $table);
|
|
if (!$column_exists) continue;
|
|
if (is_array($column_exists) && $column_exists["type"] === "upload") {
|
|
if (!is_array($value)) $value = [$value];
|
|
if (!isset(self::$uploadColumns[$key])) self::$uploadColumns[$key] = [];
|
|
foreach ($value as $val) {
|
|
self::$uploadColumns[$key][] = $val;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (is_array($functions) && isset($functions[$key]) && is_callable($functions[$key])) {
|
|
$value = $functions[$key]($value);
|
|
} else if (!$ignoreSchema) {
|
|
$value = self::parse_value_schema($value, $schema, $key);
|
|
}
|
|
|
|
if ($value === null) {
|
|
continue;
|
|
// return false;
|
|
}
|
|
|
|
if (is_array($value)) {
|
|
$value = json_encode($value);
|
|
}
|
|
|
|
$sql .= ", `$key`='" . mysql_real_escape_string($value) . "'";
|
|
endforeach;
|
|
|
|
if (@$where) {
|
|
$where = self::parse_where($where, $table);
|
|
$sql .= " WHERE " . $where;
|
|
}
|
|
|
|
if (@$options['dieBeforeQuery'])
|
|
self::error(["info" => $sql]);
|
|
|
|
if (mysql_query($sql)) {
|
|
$result++;
|
|
} else {
|
|
self::error(["error" => mysql_error(), "sql" => $sql]);
|
|
}
|
|
}
|
|
|
|
public static function error($array = [])
|
|
{
|
|
if (class_exists('API') && class_exists('ApiError')) {
|
|
API::$die = true;
|
|
API::error(new ApiError(json_encode($array)));
|
|
} else {
|
|
die(json_encode($array));
|
|
}
|
|
}
|
|
/**
|
|
* Función que prepara el SQL base dependiendo del schema y de si es INSERT o UPDATE
|
|
* @param prefix: Prefijo de la tabla
|
|
* @param table: Tabla de la operación
|
|
* @param schema: Schema de la tabla
|
|
* @param update: Boolean que indica si vamos a actualizar o insertar
|
|
* @return sql
|
|
*/
|
|
public static function prepareBaseSQL($prefix, $table, $schema = null, $update = false, $ignoreFields = [], $record = [])
|
|
{
|
|
$operation = $update ? "UPDATE" : "INSERT INTO";
|
|
if (@$schema) {
|
|
$d = date('Y-m-d H:i:s');
|
|
$t = time();
|
|
|
|
$user = 1;
|
|
if(class_exists('API')) {
|
|
$user = @Api::$user["num"] ?: 1;
|
|
}
|
|
|
|
$keysBase = ["createdDate" => $d, "createdByUserNum" => $user];
|
|
|
|
|
|
$keys = [
|
|
"category" => ["globalOrder" => 0, "siblingOrder" => 0, "lineage" => '', "depth" => 0, "breadcrumb" => '', "parentNum" => 0],
|
|
"multi" => ["dragSortOrder" => $t]
|
|
];
|
|
|
|
$sqlBase = "$operation $prefix$table SET updatedDate='$d', updatedByUserNum='$user'";
|
|
|
|
if (!$update) {
|
|
$sqlBase .= ", num=NULL";
|
|
|
|
foreach ($keysBase as $keyBase => $valueBase) {
|
|
if (isset($record[$keyBase])) continue;
|
|
if (is_string($valueBase)) {
|
|
$sqlBase .= ", `" . $keyBase . "`='" . $valueBase . "'";
|
|
} else {
|
|
$sqlBase .= ", `" . $keyBase . "`=" . ($valueBase ?: 'NULL');
|
|
}
|
|
}
|
|
|
|
if (@$keys[$schema['menuType']]) {
|
|
foreach ($keys[$schema['menuType']] as $key => $value) {
|
|
if (isset($record[$key])) continue;
|
|
if (is_string($value)) {
|
|
$sqlBase .= ", `" . $key . "`='" . $value . "'";
|
|
} else {
|
|
$sqlBase .= ", `" . $key . "`=" . $value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
$sqlBase = "$operation $prefix$table SET num=" . ($update ? "num" : "NULL");
|
|
}
|
|
return $sqlBase;
|
|
}
|
|
|
|
/**
|
|
* Parsea las opciones de los métodos
|
|
* @return lista con las opciones ignoreFields, ignoreSchema y prefix
|
|
*/
|
|
public static function parse_options($options)
|
|
{
|
|
global $TABLE_PREFIX;
|
|
|
|
$ignoreFields = @$options["forceNum"] ? [] : ['num'];
|
|
|
|
if (@$options['ignoreFields']) {
|
|
$ignoreFields = array_merge($ignoreFields, $options['ignoreField']);
|
|
}
|
|
|
|
$ignoreSchema = @$options['ignoreSchema'] ?: false;
|
|
$prefix = isset($options["prefix"]) ? $options["prefix"] : $TABLE_PREFIX;
|
|
return [$ignoreFields, $ignoreSchema, $prefix];
|
|
}
|
|
|
|
/**
|
|
* Comprueba si una columna existe en una tabla
|
|
* @return boolean que indica si existe o no la columna
|
|
*/
|
|
public static function column_exists($key, $schema, $table, $prefix = "")
|
|
{
|
|
global $TABLE_PREFIX;
|
|
|
|
if (isset(self::$tableCache[$table]) && isset(self::$tableCache[$table][$key])) {
|
|
return self::$tableCache[$table][$key];
|
|
}
|
|
if ($schema && isset($schema[$key])) {
|
|
return $schema[$key];
|
|
}
|
|
|
|
$result = mysql_query("SHOW COLUMNS FROM `$prefix$table` LIKE '$key'");
|
|
|
|
$exists = mysql_num_rows($result) > 0;
|
|
self::cache_column($table, $key, $exists);
|
|
|
|
return $exists;
|
|
}
|
|
|
|
/**
|
|
* Cachea la comprobación de una columna en una tabla
|
|
*/
|
|
public static function cache_column($table, $column, $exists)
|
|
{
|
|
if (!isset(self::$tableCache[$table])) {
|
|
self::$tableCache[$table] = [];
|
|
}
|
|
if (!isset(self::$tableCache[$table][$column])) {
|
|
self::$tableCache[$table][$column] = $exists;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Parsea el valor dependiendo del tipo de campo
|
|
* @return valor parseado
|
|
*/
|
|
public static function parse_value_schema($value, $schema, $key)
|
|
{
|
|
if (isset($schema[$key]) && isset($schema[$key]['type'])) {
|
|
switch ($schema[$key]['type']) {
|
|
case 'list':
|
|
switch ($schema[$key]['listType']) {
|
|
case 'pulldownMulti':
|
|
if (is_array($value)) {
|
|
$value = "\t" . join("\t", $value) . "\t";
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case 'multitext':
|
|
if (is_array($value)) {
|
|
$value = json_encode($value);
|
|
}
|
|
break;
|
|
case 'checkbox':
|
|
$value = @$value ? 1 : 0;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return $value;
|
|
}
|
|
|
|
/**
|
|
* Parsea el where pasado por parámetro
|
|
* - or: Si se envía a true usa OR como enlace en lugar de AND
|
|
* - not: Si se envía a true se usa
|
|
* - operador: LIKE, IN, != o =
|
|
* - raw_key: evita que ponga la comillas en la key y que no compruebe si existe
|
|
*
|
|
* @param where: String o array
|
|
* @return where
|
|
*/
|
|
public static function parse_where($where, $table, $prefix = "")
|
|
{
|
|
$builtWhere = "";
|
|
$add_parenthesis = false;
|
|
if (is_array($where)) {
|
|
|
|
foreach ($where as $key => $w) :
|
|
if (is_array($w)) {
|
|
if (!isset($w["value"]) || !isset($w["column"])) return false;
|
|
if (!isset($w["operator"])) $w["operator"] = '=';
|
|
$key = $w["column"];
|
|
|
|
if ($table && !@$w["raw_key"] && !self::column_exists($key, null, $table, $prefix)) return false;
|
|
|
|
$value = $w["value"];
|
|
$enlace = @$w["or"] ? ") OR (" : "AND";
|
|
if (@$w["or"]) $add_parenthesis = true;
|
|
$not = @$w["not"] ? "NOT " : "";
|
|
|
|
switch (strtoupper(@$w["operator"])) {
|
|
case "LIKE":
|
|
// Cambiado para DAXAuto... aunque no recuerdo el motivo exacto.
|
|
// $value = "'".mysql_real_escape_string($value)."'";
|
|
$value = "'" . str_replace('\\\\t', '\\t', mysql_real_escape_string($value)) . "'";
|
|
$operador = "LIKE";
|
|
break;
|
|
case "IS NULL":
|
|
$value = "NULL";
|
|
if ($not == '') {
|
|
$operador = "IS";
|
|
} else {
|
|
$operador = "IS NOT";
|
|
$not = '';
|
|
}
|
|
break;
|
|
case "IN":
|
|
if (is_array($value)) {
|
|
$value = join(", ", array_map(function ($a) {
|
|
if (is_int($a)) return intval($a);
|
|
if (is_numeric($a)) return floatval($a);
|
|
return "'" . mysql_real_escape_string($a) . "'";
|
|
}, $value));
|
|
}
|
|
$value = "(" . $value . ")";
|
|
$operador = "IN";
|
|
break;
|
|
case "!=":
|
|
$value = "'" . mysql_real_escape_string($value) . "'";
|
|
$operador = "!=";
|
|
break;
|
|
default:
|
|
$value = "'" . mysql_real_escape_string($value) . "'";
|
|
if (in_array(strtoupper($w["operator"]), ['<', '>', '<=', '>=', '='])) {
|
|
$operador = $w["operator"];
|
|
} else {
|
|
$operador = "=";
|
|
}
|
|
}
|
|
|
|
if (@$builtWhere) $builtWhere .= " $enlace ";
|
|
if(!@$w["raw_key"]) {
|
|
$builtWhere .= "$key $not$operador $value";
|
|
} else {
|
|
$builtWhere .= "`$key` $not$operador $value";
|
|
}
|
|
} else {
|
|
if (@$builtWhere) $builtWhere .= " AND ";
|
|
$builtWhere .= "`$key`='" . mysql_real_escape_string($w) . "'";
|
|
}
|
|
endforeach;
|
|
} else {
|
|
$builtWhere = $where;
|
|
}
|
|
if ($add_parenthesis) return "(" . $builtWhere . ")";
|
|
return $builtWhere;
|
|
}
|
|
|
|
/**
|
|
* Elimina del primer array las claves pasadas en el segundo parámetro
|
|
* @param array: Array del que vamos a eliminar las keys
|
|
* @param keys: Array que contiene las keys que queremos eliminar
|
|
* @return nuevo array
|
|
*/
|
|
public static function unsetKeys($array, $keys)
|
|
{
|
|
$c = $array;
|
|
foreach ($keys as $removeKey) {
|
|
unset($c[$removeKey]);
|
|
}
|
|
return $c;
|
|
}
|
|
|
|
/**
|
|
* Setea un punto de BackTrace
|
|
* @param string: string informativo
|
|
*/
|
|
static function setBacktracePoint($string)
|
|
{
|
|
self::$backTracePoint = $string;
|
|
}
|
|
/**
|
|
* Devuelve la información de TrackData ( uso en acai code )
|
|
* @return trackData
|
|
*/
|
|
static function getTrackData()
|
|
{
|
|
return self::$trackData;
|
|
}
|
|
/**
|
|
* Setea información de track para saber por donde va toda la web ( uso en acai code )
|
|
* @return pushed data
|
|
*/
|
|
static function setTrackData($init = false, $type = null, $id = null, $data = [])
|
|
{
|
|
if ($init) {
|
|
|
|
|
|
$pushedData = [
|
|
"ip" => $_SERVER["REMOTE_ADDR"],
|
|
"timestamp" => round(floatval(microtime(true) * 1000), 4),
|
|
"totalTime" => 0,
|
|
"host" => $_SERVER["HTTP_HOST"],
|
|
"url" => $_SERVER["REQUEST_URI"],
|
|
"trackData" => []
|
|
];
|
|
self::$trackData[] = $pushedData;
|
|
} else {
|
|
// if (count(self::$trackData[count(self::$trackData)-1]["trackData"])){
|
|
// $prevTimestamp = self::$trackData[count(self::$trackData)-1]["trackData"][count(self::$trackData[count(self::$trackData)-1]["trackData"])-1]["timestamp"];
|
|
// }else{
|
|
//
|
|
// }
|
|
$prevTimestamp = self::$trackData[count(self::$trackData) - 1]["timestamp"];
|
|
$pushedData = [
|
|
"timestamp" => round((floatval(microtime(true) * 1000) - $prevTimestamp), 4),
|
|
"type" => $type,
|
|
"id" => $id,
|
|
"transferKeys" => !isset($data[0]) ? array_keys($data) : (is_array($data[0]) ? array_keys($data[0]) : ["undefined" => $data[0]])
|
|
// "data" => $data
|
|
];
|
|
self::$trackData[count(self::$trackData) - 1]["trackData"][] = $pushedData;
|
|
self::$trackData[count(self::$trackData) - 1]["totalTime"] = $pushedData["timestamp"];
|
|
$prevPercent = 0;
|
|
foreach (self::$trackData[count(self::$trackData) - 1]["trackData"] as $cont => $trackData) {
|
|
$percent = ($trackData["timestamp"] * 100) / self::$trackData[count(self::$trackData) - 1]["totalTime"];
|
|
self::$trackData[count(self::$trackData) - 1]["trackData"][$cont]["percent"] = round($percent, 2);
|
|
self::$trackData[count(self::$trackData) - 1]["trackData"][$cont]["initPercent"] = $prevPercent;
|
|
self::$trackData[count(self::$trackData) - 1]["trackData"][$cont]["widthPercent"] = $percent - $prevPercent;
|
|
$prevPercent = $percent;
|
|
}
|
|
|
|
/*self::$trackData[count(self::$trackData)-1]["totalTime"] += $pushedData["timestamp"];
|
|
self::$trackData[count(self::$trackData)-1]["totalTime"] = round(self::$trackData[count(self::$trackData)-1]["totalTime"],4);
|
|
|
|
self::$trackData[count(self::$trackData)-1]["trackData"][] = $pushedData;
|
|
|
|
$sum = 0;
|
|
foreach( self::$trackData[count(self::$trackData)-1]["trackData"] as $cont => $trackData){
|
|
$percent = ($trackData["timestamp"] * 100)/self::$trackData[count(self::$trackData)-1]["totalTime"];
|
|
|
|
self::$trackData[count(self::$trackData)-1]["trackData"][$cont]["percent"] = $sum;
|
|
$sum+=$percent;
|
|
$sum = round($sum,2);
|
|
}*/
|
|
}
|
|
return $pushedData;
|
|
}
|
|
|
|
/**
|
|
* Muestra la variable debug
|
|
* @return html content
|
|
*/
|
|
static function showDebug($formated = false, $index = -1)
|
|
{
|
|
if (!$formated) return json_encode(self::$debugData, JSON_PRETTY_PRINT);
|
|
if (!self::$debugData) return "";
|
|
$result = '
|
|
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet">
|
|
<div class="container mx-auto border p-4 flex flex-col pb-2">
|
|
';
|
|
foreach (self::$debugData as $cont => $debugQuery) {
|
|
if ($index > -1 && $cont != $index) continue;
|
|
$result .= '<div class="w-full ">';
|
|
$result .= '<div class="border p-2 bg-green-200 text-green-800 text-xs border-green-400 mb-2 break-word block overflow-auto whitespace-normal">';
|
|
$result .= $debugQuery["hora"] . "<br>";
|
|
if (self::$backTracePoint) $result .= self::$backTracePoint . "<br>";
|
|
$result .= $debugQuery["query"] . "<br>" . $debugQuery["time"] . " microsegundos<br>";
|
|
$result .= "<button onclick='this.parentNode.parentNode.querySelector(\".info\").classList.toggle(\"hidden\")' class='text-white py-1 px-2 mt-2 mr-1 bg-green-500 hover:bg-green-400 focus:outline-none inline-block'>Ver resultado</button>";
|
|
$result .= "<button onclick='this.parentNode.parentNode.querySelector(\".back\").classList.toggle(\"hidden\")' class='text-white py-1 px-2 mt-2 bg-blue-500 hover:bg-blue-400 focus:outline-none inline-block'>Ver backtrace</button>";
|
|
$result .= '</div>';
|
|
$result .= '<pre class="info hidden bg-gray-200 p-4 text-gray-600 whitespace-normal text-xs">';
|
|
$result .= str_replace(" ", " ", nl2br(json_encode($debugQuery["records"], JSON_PRETTY_PRINT)));
|
|
$result .= '</pre>';
|
|
$result .= '<pre class="back hidden bg-blue-200 p-4 text-blue-800 whitespace-normal text-xs">';
|
|
$result .= str_replace(" ", " ", nl2br(json_encode(debug_backtrace(), JSON_PRETTY_PRINT)));
|
|
$result .= '</pre>';
|
|
$result .= '</div>';
|
|
}
|
|
$result .= '</div>';
|
|
return $result;
|
|
}
|
|
/**
|
|
* Parsea un record dado de un resultado de busqueda en la base de datos añadiendo información extra de valor
|
|
*/
|
|
static function parseGetRecord(&$record, $firstTable, $schema, $options = [], $uploadsResult = [])
|
|
{
|
|
global $TABLE_PREFIX;
|
|
$record["tableName"] = $firstTable;
|
|
|
|
if (@$uploadsResult) {
|
|
foreach ($schema as $fieldName => $fieldValue) {
|
|
if (!is_array($fieldValue)) continue;
|
|
if (@$fieldValue["type"] != "upload") continue;
|
|
|
|
if (@$uploadsResult[$firstTable][$fieldName][$record['num']]) {
|
|
$record[$fieldName] = $uploadsResult[$firstTable][$fieldName][$record['num']];
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach ($record as $recordKey => $recordValue) {
|
|
$schemaField = @$schema[$recordKey];
|
|
if (!@$schemaField || !is_array($schemaField)) continue;
|
|
if (@$options["relations"] && is_array($options["relations"]) && !in_array($recordKey, $options["relations"])) continue;
|
|
switch (@$schemaField["type"]) {
|
|
case "list":
|
|
switch ($schemaField["optionsType"]) {
|
|
case "query":
|
|
$query = getEvalOutput($schemaField['optionsQuery']);
|
|
if (!isset(self::$queryCaches[md5($query)])) {
|
|
self::$queryCaches[md5($query)] = mysql_query_fetch_all_assoc($query);
|
|
}
|
|
preg_match('/FROM\s+(.*)\s+/', $query . " ", $matches);
|
|
$tableQuery = null;
|
|
if (@$matches[1]) $tableQuery = str_replace($TABLE_PREFIX, "", trim($matches[1]));
|
|
|
|
$result = array_filter(self::$queryCaches[md5($query)], function ($rec) use ($recordValue) {
|
|
return $recordValue == $rec[array_keys($rec)[0]];
|
|
});
|
|
$result = array_merge(array_map(function ($rec) use ($tableQuery) {
|
|
if ($tableQuery) $rec["tableName"] = $tableQuery;
|
|
return $rec;
|
|
}, $result));
|
|
$record[$recordKey . "_bd"] = $result;
|
|
break;
|
|
case "text":
|
|
$optionsText = array_filter(explode("\n", $schemaField["optionsText"]));
|
|
$optionsList = [];
|
|
foreach ($optionsText as $option) {
|
|
$sepOption = explode("|", $option);
|
|
if (!isset($sepOption[1])) $sepOption[1] = $sepOption[0];
|
|
$optionsList[$sepOption[0]] = $sepOption[1];
|
|
}
|
|
// Anael: evitamos que se haga un explode de los valores null (casos extraños como el blog).
|
|
$resultDatas = [];
|
|
if(@$recordValue) $resultDatas = explode("\t", $recordValue);
|
|
$record[$recordKey . "_bd"] = [];
|
|
foreach ($resultDatas as $resultData) {
|
|
if (isset($optionsList[$resultData])) {
|
|
$record[$recordKey . "_bd"][] = ["key" => $resultData, "value" => t_var($optionsList[$resultData])];
|
|
} else {
|
|
$record[$recordKey . "_bd"][] = ["key" => $resultData, "value" => t_var($resultData)];
|
|
}
|
|
}
|
|
break;
|
|
case "table":
|
|
|
|
$nums = array_filter(explode("\t", mysql_real_escape_string($recordValue ?? '')));
|
|
if (@$nums && @$options["relationsDepth"]) {
|
|
/*$hash_query_caches = 'query_all_'.$schemaField["optionsTablename"] . '_' . $options["relationsDepth"];
|
|
if(!isset(self::$queryCaches[$hash_query_caches])) {
|
|
self::$queryCaches[$hash_query_caches] = self::get($schemaField["optionsTablename"], null, null, null, [
|
|
"relationsDepth" => intval(@$options["relationsDepth"])-1,
|
|
"debug" => @$options["debug"],
|
|
"translates" => @$options["translates"],
|
|
"uploads" => @$options["uploads"]
|
|
]);
|
|
}
|
|
$cache_filter_by_key = $schemaField["optionsValueField"];
|
|
$cache_filter_by_values = $nums;
|
|
$record[$recordKey."_bd"] = array_values(array_filter(self::$queryCaches[$hash_query_caches], function($each) use($cache_filter_by_key, $cache_filter_by_values) {
|
|
return in_array($each[$cache_filter_by_key], $cache_filter_by_values);
|
|
}));*/
|
|
// SE HA ELIMINADO ESTE SCRIPT PORQUE DUPLICABA EL TIEMPO DE RESPUESTA EN BANANA
|
|
//$record[$recordKey."_bd"] = self::get($schemaField["optionsTablename"], $schemaField["optionsValueField"]." IN ('".join("','", $nums)."')", null, null, ["relationsDepth" => intval(@$options["relationsDepth"])-1,"debug" => @$options["debug"]]);
|
|
$record[$recordKey . "_bd"] = self::get($schemaField["optionsTablename"], $schemaField["optionsValueField"] . " IN ('" . join("','", $nums) . "')", null, null, [
|
|
"relationsDepth" => intval(@$options["relationsDepth"]) - 1,
|
|
"debug" => @$options["debug"],
|
|
"translates" => @$options["translates"],
|
|
"uploads" => @$options["uploads"]
|
|
]);
|
|
}
|
|
break;
|
|
default:
|
|
}
|
|
break;
|
|
case "multitext":
|
|
$record[$recordKey . "_bd"] = json_decode($recordValue ?? '', true);
|
|
break;
|
|
default:
|
|
}
|
|
}
|
|
// Translates
|
|
if (@$options["translates"]) {
|
|
$idiomaActual = @$_REQUEST["idioma"];
|
|
$_REQUEST["idioma"] = @$options["translates"];
|
|
if (@$_REQUEST["idioma"]) {
|
|
$record = self::t_recursivo($record, null);
|
|
}
|
|
$_REQUEST["idioma"] = $idiomaActual;
|
|
}
|
|
|
|
$record["breadcrumbField"] = @$schema["breadcrumbField"];
|
|
// Si es parentNum ponemos valores por defecto
|
|
if (@$record["breadcrumbField"] == "parentNum") {
|
|
$record["optionsTablename"] = $record["tableName"];
|
|
$record["optionsValueField"] = "num";
|
|
} else if (@$record["breadcrumbField"]) {
|
|
// Si no es parentNum, ponemos los que dicte el schema
|
|
$record["optionsTablename"] = @$schema[$schema["breadcrumbField"]]["optionsTablename"];
|
|
$record["optionsValueField"] = @$schema[$schema["breadcrumbField"]]["optionsValueField"];
|
|
}
|
|
|
|
// Para el campo principal (para la generación de enlaces y el breadcrumb)
|
|
if (@$record["name"]) {
|
|
$record["mainFieldBreadcrumb"] = $record["name"];
|
|
} else if (@$record["title"]) {
|
|
$record["mainFieldBreadcrumb"] = $record["title"];
|
|
} else if (@$record["titulo"]) {
|
|
$record["mainFieldBreadcrumb"] = $record["titulo"];
|
|
} else if (@$record["nombre"]) {
|
|
$record["mainFieldBreadcrumb"] = $record["nombre"];
|
|
} else {
|
|
foreach ($schema as $key => $value) :
|
|
if (!is_array($value)) continue;
|
|
if (@$value["type"] == "textfield" && $key != "enlace") {
|
|
$record["mainFieldBreadcrumb"] = $record[$key];
|
|
break;
|
|
}
|
|
endforeach;
|
|
}
|
|
}
|
|
/**
|
|
* Obtiene los uploads de una tabla y los cachea
|
|
* @return un array con todos los uploads
|
|
*/
|
|
static function getUploadsResults($options)
|
|
{
|
|
global $TABLE_PREFIX;
|
|
$pathCacheUploads = __DIR__ . "/../../../cache/";
|
|
if (!file_exists($pathCacheUploads)) {
|
|
mkdir($pathCacheUploads);
|
|
}
|
|
$fileName = $pathCacheUploads . "uploads-" . date("Y-m-d", time()) . "-" . $_SERVER['HTTP_HOST'] . ".json";
|
|
if (!file_exists($fileName)) {
|
|
$fields_to_select = "num, `order`, tableName, fieldName, recordNum, filePath, urlPath, info1, info2, info3, info4, info5, alt";
|
|
$uploads = mysql_query_fetch_all_assoc("SELECT $fields_to_select FROM " . $TABLE_PREFIX . "uploads ORDER BY `order` ASC");
|
|
$uploadsResult = [];
|
|
foreach ($uploads as $upload) {
|
|
$table = $upload['tableName'];
|
|
$field = $upload['fieldName'];
|
|
$num = $upload['recordNum'];
|
|
if (!isset($uploadsResult[$table])) $uploadsResult[$table] = [];
|
|
if (!isset($uploadsResult[$table][$field])) $uploadsResult[$table][$field] = [];
|
|
if (!isset($uploadsResult[$table][$field][$num])) $uploadsResult[$table][$field][$num] = [];
|
|
$uploadsResult[$table][$field][$num][] = $upload;
|
|
}
|
|
file_put_contents($fileName, json_encode($uploadsResult));
|
|
} else {
|
|
if ($options['useAbsoluteUrls']) {
|
|
$uploadsResult = json_decode(str_replace('"urlPath":"\/cms', '"urlPath":"https:\/\/' . $_SERVER['HTTP_HOST'] . '\/cms', file_get_contents($fileName)), true);
|
|
} else {
|
|
$uploadsResult = json_decode(file_get_contents($fileName), true);
|
|
}
|
|
// $uploadsResult = isset($uploadsResult[$tableName]) ? $uploadsResult[$tableName] : [];
|
|
}
|
|
return $uploadsResult;
|
|
}
|
|
/**
|
|
* Obtiene los uploads consultándolos a base de datos registro por registro
|
|
* @return void
|
|
*/
|
|
static function getUploadsResultsFromRecord(&$record, $firstTable, $schema, $options)
|
|
{
|
|
global $TABLE_PREFIX;
|
|
if (!is_array($schema)) return;
|
|
$record["tableName"] = $firstTable;
|
|
$fields_to_select = "num, `order`, tableName, fieldName, recordNum, filePath, urlPath, info1, info2, info3, info4, info5, alt";
|
|
foreach ($schema as $schemaKey => $schemaField) {
|
|
if (!is_array($schemaField)) continue;
|
|
switch (@$schemaField["type"]) {
|
|
case "upload":
|
|
$uploads = mysql_query_fetch_all_assoc("SELECT " . $fields_to_select . " FROM " . $TABLE_PREFIX . "uploads WHERE tableName = '" . $firstTable . "' and fieldName = '" . $schemaKey . "' and recordNum = " . $record["num"] . " ORDER BY `order` ASC");
|
|
if (@$options['useAbsoluteUrls'] && is_array($uploads)) {
|
|
$uploads = array_map(function ($each) {
|
|
if (strpos($each['urlPath'], '/cms') === 0) {
|
|
$each['urlPath'] = str_replace('/cms', 'https://' . $_SERVER['HTTP_HOST'] . '/cms', $each['urlPath']);
|
|
}
|
|
return $each;
|
|
}, $uploads);
|
|
}
|
|
$record[$schemaKey] = @$uploads;
|
|
break;
|
|
default:
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Recupera todas las configuraciones de los plugins en una sola consulta y devuelve el resultado si existe el plugin buscado en un array general
|
|
*/
|
|
|
|
static function getPluginsConfig($table,$where){
|
|
if (!self::$pluginsConfig){
|
|
$pluginsConfig = mysql_query_fetch_all_assoc("SELECT * FROM aux_plg_config ORDER BY num DESC");
|
|
|
|
self::$pluginsConfig = [];
|
|
foreach($pluginsConfig as $pluginConfig){
|
|
if (!@self::$pluginsConfig[$pluginConfig["plugin"]]) self::$pluginsConfig[$pluginConfig["plugin"]] = $pluginConfig;
|
|
}
|
|
}
|
|
|
|
$auxWhere = str_replace(" ","",strtolower(trim($where)));
|
|
$auxWhere = str_replace("plugin=","",$auxWhere);
|
|
$auxWhere = str_replace("'","",$auxWhere);
|
|
$auxWhere = str_replace('"','',$auxWhere);
|
|
|
|
return @self::$pluginsConfig[$auxWhere] ?: [];
|
|
}
|
|
|
|
/**
|
|
* Obtiene registros de una tabla
|
|
* @param table: Tabla de la que vamos a eliminar registros
|
|
* @param where: string con el where o array de condiciones ( condicion ["field" => num,"operator" => "=","value" => 1] )
|
|
* @param order: string
|
|
* @param limit: string con el limit o array de limite y offset ( ["limit" => 10,"offset" => 20] )
|
|
* @param options: Array asociativo que recoge opciones
|
|
@option : debug => Boolean
|
|
@option : translates => string con el idioma
|
|
@option : uploads => Boolean
|
|
@option : groupBy => string
|
|
@option : aggregates => array de aggregates
|
|
@option : relations => Boolean o array de campos en los que emitir las relaciones ( ['islas'] )
|
|
@option : relationsDepth => Int
|
|
|
|
* @return todos los registros
|
|
*/
|
|
static function get($table, $where, $order = null, $limit = null, $options = [])
|
|
{
|
|
global $TABLE_PREFIX;
|
|
|
|
/*if ($table == "aux_plg_config"){
|
|
// Evitar demasiadas consultas a aux_plg_config
|
|
$resultPlugin = self::getPluginsConfig($table,$where);
|
|
return $resultPlugin;
|
|
Desactivado temporalmente porque se pierden los márgenes
|
|
}*/
|
|
|
|
$microtime = microtime(true);
|
|
$optionsDefault = [
|
|
"debug" => false,
|
|
"translates" => @$_REQUEST["idioma"],
|
|
"uploads" => true,
|
|
"useAbsoluteUrls" => false,
|
|
"groupBy" => null,
|
|
"ignoreSchema" => false,
|
|
"aggregates" => [],
|
|
"relations" => true,
|
|
"redis" => null,
|
|
"onlyFields" => null,
|
|
"redis_expire" => 60,
|
|
"relationsDepth" => self::$defaultRelationsDepth,
|
|
"dieBeforeQuery" => false,
|
|
"prefix" => $TABLE_PREFIX
|
|
];
|
|
|
|
// ALIAS PARA JORDAN
|
|
if (@$options["ignoreSchemas"]) $options["ignoreSchema"] = $options["ignoreSchemas"];
|
|
|
|
foreach ($optionsDefault as $key => $value) {
|
|
if (!isset($options[$key])) $options[$key] = $value;
|
|
}
|
|
|
|
|
|
if (self::$force_redis) {
|
|
$options["redis"] = is_null($options["redis"]) ? true : $options["redis"];
|
|
if (self::$redis_expireTime) $options["redis_expire"] = self::$redis_expireTime;
|
|
}
|
|
|
|
|
|
// EN CASO DE PEDIR CACHE REDIS INSTANCIAMOS Y CONECTAMOS
|
|
if (@$options["redis"]) {
|
|
self::initCache();
|
|
}
|
|
|
|
if (intval(@$options["relationsDepth"]) < 0) return [];
|
|
// Definición de tablas y schemas
|
|
$tables = array_filter(explode(",", $table));
|
|
$tables = array_map("trim", $tables);
|
|
$schemas = [];
|
|
$fullSchemas = [];
|
|
|
|
if (!@$options["ignoreSchema"]) {
|
|
foreach ($tables as $index => $table) {
|
|
$tableName = explode(" ", $table)[0];
|
|
$schemaLoaded = loadSchema($tableName);
|
|
if (empty($schemaLoaded)) {
|
|
unset($tables[$index]);
|
|
continue;
|
|
}
|
|
if (!$order) $order = $schemaLoaded["listPageOrder"];
|
|
$fullSchemas[$tableName] = $schemaLoaded;
|
|
|
|
$schemas[$tableName] = array_filter($schemaLoaded, function ($rec) use ($options) {
|
|
// Creo que esto es innecesario pero por si acaso se necesite el squema sin uploads si no se pide
|
|
if (@$options["uploads"]) {
|
|
return !empty($rec) && is_array($rec) && isset($rec["type"]) && $rec["type"] != "separator";
|
|
} else {
|
|
return !empty($rec) && is_array($rec) && isset($rec["type"]) && $rec["type"] != "separator" && $rec["type"] != "upload";
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
$select = @$options["onlyFields"] ?: ["*"];
|
|
|
|
if (count($tables) > 1) {
|
|
$select = [];
|
|
foreach ($tables as $index => $table) {
|
|
$referencia = @explode(" ", $table)[1];
|
|
$tableName = @explode(" ", $table)[0];
|
|
if (!isset($schemas[$tableName])) continue;
|
|
|
|
if (!isset($referencia)) $referencia = $options["prefix"] . $tableName;
|
|
if ($index === 0) {
|
|
$select[] = $referencia . ".*";
|
|
} else {
|
|
$selectResult = $referencia . "." . join("," . $referencia . ".", array_map(function ($key) use ($referencia) {
|
|
return $key . " AS '" . $referencia . "." . $key . "'";
|
|
}, array_keys($schemas[$tableName])));
|
|
$select[] = $selectResult;
|
|
}
|
|
}
|
|
}
|
|
if (isset($options["aggregates"]) && is_array($options["aggregates"])) {
|
|
foreach ($options["aggregates"] as $aggregate) {
|
|
$select[] = $aggregate;
|
|
}
|
|
}
|
|
|
|
// Definición de los FROM
|
|
$from = join(",", array_map(function ($table) use ($options) {
|
|
return $options["prefix"] . $table;
|
|
}, $tables));
|
|
|
|
// Definición del Where
|
|
$where = self::parse_where($where, null);
|
|
$meta_limit = 1000000;
|
|
|
|
// Definición del Limit
|
|
if ($limit && is_array($limit)) {
|
|
if (isset($limit["perPage"])) $limit["limit"] = $limit["perPage"];
|
|
if (!isset($limit["limit"])) self::error(["error" => "No se puede poner limit sin limit"]);
|
|
if (isset($limit["page"]) && !isset($limit["offset"])) $limit["offset"] = (max(1, intval($limit["page"])) - 1) * (intval($limit["limit"]));
|
|
$meta_limit = intval($limit["limit"]);
|
|
if (isset($limit["offset"])) {
|
|
$limit = intval($limit["offset"]) . "," . intval($limit["limit"]);
|
|
} else {
|
|
$limit = intval($limit["limit"]);
|
|
}
|
|
} else if ($limit) {
|
|
if(strpos($limit, ',') !== false) {
|
|
$meta_limit = intval(explode(',', $limit)[1]);
|
|
} else {
|
|
$meta_limit = intval($limit);
|
|
}
|
|
}
|
|
|
|
|
|
$select = join(', ', $select);
|
|
$sql = "SELECT " . $select;
|
|
$sql .= " FROM " . $from;
|
|
$sql .= $where ? " WHERE " . $where : "";
|
|
$sql .= @$options["groupBy"] ? " GROUP BY " . $options["groupBy"] : "";
|
|
$sql .= $order ? " ORDER BY " . $order : "";
|
|
|
|
$query_without_limit = $sql;
|
|
|
|
$sql .= $limit ? " LIMIT " . $limit : "";
|
|
|
|
if (@$options['dieBeforeQuery']) {
|
|
self::error(["info" => $sql]);
|
|
}
|
|
|
|
$hashSql = self::cacheGenerateHash(md5($sql . json_encode($options)));
|
|
|
|
if (!self::$noCacheTABLES || (self::$noCacheTABLES && !in_array($TABLE_PREFIX . str_replace($TABLE_PREFIX, "", $table), self::$noCacheTABLES))) {
|
|
if (@$options["redis"]) {
|
|
$resultQueryRedis = self::cacheGet($hashSql);
|
|
if (@$resultQueryRedis) {
|
|
return json_decode($resultQueryRedis, true);
|
|
}
|
|
} else if (self::$force_load_cache) {
|
|
if (!empty(self::$getCaches[$hashSql])) {
|
|
return json_decode(self::$getCaches[$hashSql], true);
|
|
}
|
|
}
|
|
}
|
|
|
|
$num_rows = null;
|
|
if (@$options["withMetas"]) {
|
|
$countSql = "SELECT COUNT(*) AS totalRecords FROM " . $from;
|
|
$countSql .= $where ? " WHERE " . $where : "";
|
|
|
|
// Cuando hay GROUP BY, totalRecords debe contar grupos y no filas crudas.
|
|
if (@$options["groupBy"]) {
|
|
$countSql = "SELECT COUNT(*) AS totalRecords FROM (SELECT 1 FROM " . $from;
|
|
$countSql .= $where ? " WHERE " . $where : "";
|
|
$countSql .= " GROUP BY " . $options["groupBy"] . ") __count_groups";
|
|
}
|
|
|
|
$countResult = @mysql_query($countSql);
|
|
if ($countResult) {
|
|
$countRow = mysql_fetch_assoc($countResult);
|
|
if (isset($countRow["totalRecords"])) $num_rows = intval($countRow["totalRecords"]);
|
|
}
|
|
|
|
// Fallback para no alterar comportamiento si el COUNT optimizado falla.
|
|
if (is_null($num_rows)) {
|
|
$num_rows = mysql_num_rows(mysql_query($query_without_limit));
|
|
}
|
|
}
|
|
|
|
$resultQuery = mysql_query($sql) or self::error(["error" => "Error en la consulta SQL " . mysql_error()]);
|
|
$records = [];
|
|
|
|
$firstTable = explode(" ", $tables[0])[0];
|
|
|
|
// Uploads cacheados
|
|
if (@$options["uploads"] && self::$force_json_cache_uploads) {
|
|
$uploadsResult = self::getUploadsResults($options);
|
|
$uploadsResult[$firstTable] = isset($uploadsResult[$firstTable]) ? $uploadsResult[$firstTable] : [];
|
|
$possible_keys_of_uploads = array_filter(array_keys(@$uploadsResult[$firstTable]));
|
|
}
|
|
|
|
// Records
|
|
while ($record = mysql_fetch_assoc($resultQuery)) {
|
|
// Uploads sin cache
|
|
if (@$options["uploads"] && !self::$force_json_cache_uploads) {
|
|
self::getUploadsResultsFromRecord($record, $firstTable, @$fullSchemas[$firstTable], $options);
|
|
}
|
|
if (!@$options["ignoreSchema"]) self::parseGetRecord($record, $firstTable, @$fullSchemas[$firstTable], $options, @$uploadsResult);
|
|
|
|
|
|
if (@$options["returnDataByKey"]) {
|
|
|
|
$records[$record[$options["returnDataByKey"]]] = $record;
|
|
} else {
|
|
|
|
$records[] = $record;
|
|
}
|
|
}
|
|
|
|
if (self::$storeDebugData) {
|
|
$debugData = [
|
|
"hora" => date("Y-m-d H:i:s", time()) . " " . microtime(),
|
|
"query" => $sql,
|
|
"records" => $records,
|
|
"time" => microtime(true) - $microtime
|
|
];
|
|
|
|
if (self::$backTracePoint) {
|
|
$debugData["backTracePoint"] = self::$backTracePoint;
|
|
}
|
|
|
|
self::$debugData[] = $debugData;
|
|
}
|
|
|
|
if (@$options["debug"]) {
|
|
echo self::showDebug(true, count(self::$debugData) - 1);
|
|
}
|
|
|
|
if (@$options["withMetas"]) {
|
|
$listDetails = [
|
|
"totalRecords" => $num_rows,
|
|
//"totalMatches" => count($records),
|
|
"perPage" => $meta_limit,
|
|
//"keyword" => "",
|
|
"totalPages" => ceil($num_rows / max(1, $meta_limit)),
|
|
//"page" => 1,
|
|
//"prevPage" => 1,
|
|
//"nextPage" => 1
|
|
];
|
|
if (@$options["redis"] && @$hashSql) {
|
|
if (!self::$noCacheTABLES || (self::$noCacheTABLES && !in_array($TABLE_PREFIX . str_replace($TABLE_PREFIX, "", $table), self::$noCacheTABLES))) {
|
|
self::cacheSet($hashSql, json_encode([$listDetails, $records]), $options["redis_expire"]);
|
|
}
|
|
} else if (self::$force_load_cache) {
|
|
self::$getCaches[$hashSql] = json_encode([$listDetails, $records]);
|
|
}
|
|
return [$listDetails, $records];
|
|
}
|
|
if (@$options["redis"] && @$hashSql) {
|
|
if (!self::$noCacheTABLES || (self::$noCacheTABLES && !in_array($TABLE_PREFIX . str_replace($TABLE_PREFIX, "", $table), self::$noCacheTABLES))) {
|
|
self::cacheSet($hashSql, json_encode($records), $options["redis_expire"]);
|
|
}
|
|
} else if (self::$force_load_cache) {
|
|
self::$getCaches[$hashSql] = json_encode($records);
|
|
}
|
|
return $records;
|
|
}
|
|
|
|
/**
|
|
* Fuerza que todas las consulta se ejecuten con caché redis
|
|
*/
|
|
static function localCache()
|
|
{
|
|
self::$force_load_cache = true;
|
|
}
|
|
|
|
/**
|
|
* Inicializa la caché
|
|
* TO DO : Falta comprobar si no se puede conectar
|
|
*/
|
|
static function initCache()
|
|
{
|
|
$redisHost = '127.0.0.1';
|
|
$redisPort = 6379;
|
|
|
|
if (!self::$redis) {
|
|
self::$redis = new Redis();
|
|
self::$redis->connect($redisHost, $redisPort);
|
|
} else if (!self::$redis->isConnected()) {
|
|
self::$redis->connect($redisHost, $redisPort);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fuerza que todas las consulta se ejecuten con caché redis
|
|
*/
|
|
static function fullCache($expireTime = 60)
|
|
{
|
|
self::$force_redis = true;
|
|
self::$redis_expireTime = $expireTime;
|
|
|
|
self::initCache();
|
|
}
|
|
/**
|
|
* Genera un hash para esta web
|
|
*/
|
|
static function cacheGenerateHash($string)
|
|
{
|
|
return $_SERVER["HTTP_HOST"] . "_" . $string . "_" . self::$redis_expireTime;
|
|
}
|
|
|
|
/**
|
|
* Setea datos en el caché a través de un hash
|
|
*/
|
|
static function cacheSet($hash, $data, $expireTime = null)
|
|
{
|
|
if (!self::$redis) return;
|
|
if (!self::$redis->isConnected()) return;
|
|
if (!$expireTime && self::$redis_expireTime) $expireTime = self::$redis_expireTime;
|
|
if (!$expireTime) $expireTime = 60;
|
|
self::$redis->set($hash, $data);
|
|
self::$redis->expire($hash, $expireTime);
|
|
}
|
|
|
|
/**
|
|
* Obtiene datos de el caché a través de un hash
|
|
*/
|
|
static function cacheGet($hash)
|
|
{
|
|
if (!self::$redis) return;
|
|
if (!self::$redis->isConnected()) return;
|
|
// SE HA MODIFICADO ESTE SCRIPT PORQUE CONSUMIA MAS RECURSOS EL GET
|
|
return self::$redis->exists($hash) ? self::$redis->get($hash) : null;
|
|
}
|
|
|
|
/**
|
|
* Reajusta las variables de activación de cache según la url
|
|
*/
|
|
static function bloquedCacheByURL($url)
|
|
{
|
|
if (!self::$noCacheURIS) return false;
|
|
if (in_array($url, self::$noCacheURIS)) return true;
|
|
foreach (self::$noCacheURIS as $noCacheURI) {
|
|
if (preg_match('/' . $noCacheURI . '/i', $url, $matches, PREG_OFFSET_CAPTURE)) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Reemplaza el hook token en el html resultante para que la seguridad no bloquee las peticiones
|
|
*/
|
|
static function replaceHooksToken($html)
|
|
{
|
|
session_start();
|
|
$html = preg_replace_callback(
|
|
"/var hooksToken(\s)?=(\s)?[\'\"]([a-zA-Z0-9]+)[\'\"]\;/i",
|
|
function ($matches) {
|
|
$token = sha1(session_id() . $_SERVER["HTTP_HOST"]);
|
|
return "var hooksToken = '" . $token . "'; console.log('⚡️⚡️⚡️ Render cached HTML ⚡️⚡️⚡️');";
|
|
},
|
|
$html
|
|
);
|
|
return $html;
|
|
}
|
|
/**
|
|
* Realiza una traducción recursiva de un array de valores
|
|
*/
|
|
static function t_recursivo($record, $idx = null)
|
|
{
|
|
global $TABLE_PREFIX;
|
|
if (is_null(self::$allowedTranslateFields)) {
|
|
self::$allowedTranslateFields = array_flip(array_map(function ($field) {
|
|
return $field['fieldName'];
|
|
}, mysql_query_fetch_all_assoc("SELECT DISTINCT fieldName FROM {$TABLE_PREFIX}traducciones")));
|
|
}
|
|
$it = $idx ? $record[$idx] : $record;
|
|
if (is_array($it)) {
|
|
foreach ($it as $key => $value) {
|
|
if (is_array($it[$key])) {
|
|
$it[$key] = self::t_recursivo($it[$key], null);
|
|
} else {
|
|
if (isset(self::$allowedTranslateFields[$key])) {
|
|
$it[$key] = t($it, $key);
|
|
if (isset($it[$key . '_bd']) && strpos($it[$key], '[') === 0 && strpos($it[$key], ']') === (strlen($it[$key]) - 1)) {
|
|
$it[$key . '_bd'] = json_decode($it[$key], true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ($idx) {
|
|
$record[$idx] = $it;
|
|
} else {
|
|
$record = $it;
|
|
}
|
|
} else {
|
|
if ($idx && isset(self::$allowedTranslateFields[$idx])) {
|
|
$record[$idx] = t($record, $idx);
|
|
if (isset($record[$idx . '_bd']) && strpos($record[$idx], '[') === 0 && strpos($record[$idx], ']') === (strlen($record[$idx]) - 1)) {
|
|
$record[$idx . '_bd'] = json_decode($record[$idx], true);
|
|
}
|
|
}
|
|
}
|
|
return $record;
|
|
}
|
|
/*
|
|
* Función traida del CMS lib/menus/default/common.php
|
|
*/
|
|
static function updateCategoryMetadata($tableName = null, $where = '')
|
|
{
|
|
global $escapedTableName, $schema, $TABLE_PREFIX;
|
|
|
|
if (!$tableName) {
|
|
$newEscapedTableName = $escapedTableName;
|
|
$newSchema = $schema;
|
|
} else {
|
|
$newEscapedTableName = $TABLE_PREFIX . str_replace($TABLE_PREFIX, "", $tableName);
|
|
$newSchema = loadSchema($newEscapedTableName);
|
|
}
|
|
if ($newSchema['menuType'] != 'category') {
|
|
return;
|
|
}
|
|
|
|
// load categoriesByNum
|
|
$categoriesByNum = array();
|
|
|
|
if ($where) $where = " WHERE $where";
|
|
|
|
$query = "SELECT * FROM $newEscapedTableName $where ORDER BY globalOrder";
|
|
$result = mysql_query($query) or die("MySQL Error: " . mysql_error() . "\n");
|
|
while ($row = mysql_fetch_assoc($result)) {
|
|
$categoriesByNum[$row['num']] = $row;
|
|
}
|
|
if (is_resource($result)) {
|
|
mysql_free_result($result);
|
|
}
|
|
|
|
// get childNums for each parentNum
|
|
$childNumsOfParentNum = array();
|
|
foreach (array_keys($categoriesByNum) as $num) {
|
|
$parentNum = (int) $categoriesByNum[$num]['parentNum'];
|
|
$childNumsOfParentNum[$parentNum][] = $num;
|
|
}
|
|
|
|
// reset order
|
|
self::_updateCategoryBranch(array(
|
|
'branchParent' => 0,
|
|
'records' => &$categoriesByNum,
|
|
'childNodes' => $childNumsOfParentNum,
|
|
));
|
|
|
|
|
|
// save new order
|
|
foreach ($categoriesByNum as $num => $category) {
|
|
$query = "UPDATE `$newEscapedTableName` SET ";
|
|
$query .= "`globalOrder` = '" . mysql_real_escape_string($category['globalOrder']) . "', ";
|
|
$query .= "`siblingOrder` = '" . mysql_real_escape_string($category['siblingOrder']) . "', ";
|
|
$query .= "`depth` = '" . mysql_real_escape_string($category['depth']) . "', ";
|
|
$query .= "`lineage` = '" . mysql_real_escape_string($category['lineage']) . "', ";
|
|
$query .= "`breadcrumb` = '" . mysql_real_escape_string($category['breadcrumb']) . "' ";
|
|
$query .= "WHERE num = '{$category['num']}'";
|
|
|
|
mysql_query($query) or die("There was an error updating the category metadata:\n\n" . htmlspecialchars(mysql_error()) . "\n");
|
|
}
|
|
}
|
|
/*
|
|
* Función traida del CMS lib/menus/default/common.php
|
|
*/
|
|
static function _updateCategoryBranch($args)
|
|
{
|
|
|
|
## set defaults
|
|
if (!@$args['globalOrder']) {
|
|
$args['globalOrder'] = 0;
|
|
}
|
|
if (!@$args['depth']) {
|
|
$args['depth'] = 0;
|
|
}
|
|
if (!@$args['lineage']) {
|
|
$args['lineage'] = ":";
|
|
}
|
|
|
|
# sort branch children
|
|
$sortedChildren = array();
|
|
foreach ($args['childNodes'][$args['branchParent']] as $childNum) {
|
|
$sortedChildren[$childNum] = &$args['records'][$childNum];
|
|
}
|
|
uasort($sortedChildren, 'self::_sortCategoriesBySiblingOrder');
|
|
|
|
# loop over branch children
|
|
$siblingOrder = 0;
|
|
foreach (array_keys($sortedChildren) as $childNum) {
|
|
$childRecord = &$args['records'][$childNum];
|
|
|
|
$childRecord['globalOrder'] = ++$args['globalOrder'];
|
|
$childRecord['siblingOrder'] = ++$siblingOrder;
|
|
$childRecord['depth'] = $args['depth'];
|
|
$childRecord['lineage'] = $args['lineage'] . "$childNum:";
|
|
$childRecord['breadcrumb'] = @$args['breadcrumb'] ? "{$args['breadcrumb']} : {$childRecord['name']}" : $childRecord['name'];
|
|
|
|
# if child has children, loop over them
|
|
if (@$args['childNodes'][$childNum]) {
|
|
self::_updateCategoryBranch(array(
|
|
'branchParent' => $childNum,
|
|
'globalOrder' => &$args['globalOrder'],
|
|
'records' => &$args['records'],
|
|
'childNodes' => $args['childNodes'],
|
|
'depth' => ($args['depth'] + 1),
|
|
'lineage' => $childRecord['lineage'],
|
|
'breadcrumb' => $childRecord['breadcrumb'],
|
|
));
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* Función traida del CMS lib/menus/default/common.php
|
|
*/
|
|
static function _sortCategoriesBySiblingOrder($arrayA, $arrayB)
|
|
{
|
|
if ($arrayA['siblingOrder'] < $arrayB['siblingOrder']) {
|
|
return -1;
|
|
}
|
|
if ($arrayA['siblingOrder'] > $arrayB['siblingOrder']) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|