function get_packages() { $files = array(); $handler = opendir(ASSET_FOLDER); while ($file = readdir($handler)) { if ($file != "." && $file != ".." && pathinfo($file, PATHINFO_EXTENSION) == 'json') { $files[] = ASSET_FOLDER . '/' . $file; } } closedir($handler); ksort($files); $packages = array(); foreach ($files as $file) { $data = file_get_contents($file); $data = json_decode($data); if (is_a($data, 'StdClass')) { $package = object2array($data); $packages = array_merge_unique($packages, $package); } } return $packages; }
function action_update($i, $action) { global $db, $where_types, $where_connect_types; // Cache the tables for table checks $tables = cache_tables(); // Check for the 'table' paramater if (!array_key_exists('table', $action)) { return param_error("update action", "table", "action {$i}"); } // To make life easier $table = $action['table']; if (!in_array($table, $tables)) { return herror("update action", "table '{$table}' for " . "action {$i} does not exist"); } $status = cache_table_status($table); // Check the table supports transactions if ($status['Engine'] != 'InnoDB') { return herror("update action", "table '{$table}' for " . "action {$i} does not support transactions"); } // Check for the 'rows' paramater if (!array_key_exists('rows', $action)) { return param_error("update action", "rows", "action {$i}"); } // Check for the 'rows' paramater if (!count($action['rows'])) { return herror("update action", "no rows to update for action {$i}"); } $column_cache[$table] = cache_columns($table); $relation_aliases = array(); if (array_key_exists('relations', $action)) { if (!count($action['relations'])) { return herror("update action", "paramater 'relations' for action {$i} " . "exists but contains no relations"); } foreach ($action['relations'] as $foreign_table => $relation) { if (!in_array($foreign_table, $tables)) { return herror("update action", "table '{$foreign_table}' for " . "relation '{$foreign_table}' in action {$i} does not exist"); } if (!array_key_exists('id', $relation)) { return param_error("update action", "id", "relation " . "'{$foreign_table}' in action {$i}"); } if (!in_array($relation['id'], $column_cache[$table])) { return herror("update action", "column '{$relation['id']}' " . "on table '{$table}' for relation '{$foreign_table}' in " . "action {$i} does not exist"); } if (!array_key_exists('foreign_id', $relation)) { return param_error("update action", "foreign_id", "relation " . "'{$foreign_table}' in action {$i}"); } $column_cache[$foreign_table] = cache_columns($foreign_table); if (!in_array($relation['foreign_id'], $column_cache[$foreign_table])) { return herror("update action", "column '{$relation['foreign_id']}' " . "on table '{$foreign_table}' for relation '{$foreign_table}' in " . "action {$i} does not exist"); } foreach ($relation['columns'] as $relation_column => $alias) { if (in_array($alias, $column_cache[$table]) || array_key_exists($alias, $relation_aliases)) { return herror("update action", "alias '{$alias}' of column" . "'{$relation_column}' for relation '{$foreign_table}' in " . "action {$i} conflicts with an existing column or alias"); } $relation_aliases[] = $alias; } } } $columns = array(); foreach ($action['rows'] as $row) { $columns = array_merge_unique($columns, array_keys($row)); } // Strip all columns that are for aliases $columns = array_values(array_diff($columns, $relation_aliases)); // Check all columns foreach ($columns as $column) { if (!in_array($column, $column_cache[$table])) { return herror("update action", "column '{$column}' for " . "action {$i} does not exist"); } } $rows = $action['rows']; $row_count = count($rows); // Check all the columns are there for ($j = 0; $j < $row_count; $j++) { $row_columns = array_keys($rows[$j]); $missing = array_values(array_diff($relation_aliases, $row_columns)); if (count($missing)) { return herror("update action", "column '{$missing[0]}' for row {$j} in " . "action {$i} does not exist"); } $missing = array_values(array_diff($columns, $row_columns)); if (count($missing)) { return herror("update action", "column '{$missing[0]}' for row {$j} in " . "action {$i} does not exist"); } } if (!auth_validate_request($_POST['email'], $action)) { return herror("update action", "authentication error for action {$i}"); } // Only commit the changes if there are no errors if (!$db->beginTransaction()) { herror_sql("update action", "failed to start transaction for action {$i}"); } if (array_key_exists('relations', $action)) { foreach ($action['relations'] as $foreign_table => $relation) { $where_columns = array(); // Prepare the bind names foreach ($relation['columns'] as $relation_column => $alias) { $where_columns[] = "{$relation_column} = :{$alias}"; } $where_columns_expr = implode(' AND ', $where_columns); $sql = "SELECT {$relation['foreign_id']} FROM {$foreign_table} WHERE " . "{$where_columns_expr} LIMIT 1"; $stmt = $db->prepare($sql); if (!$stmt) { return herror_stmt($stmt, "update action", "MySQL error for " . "relation '{$foreign_table}' in action {$i}"); } for ($j = 0; $j < $row_count; $j++) { $where_values = array(); foreach ($relation['columns'] as $relation_column => $alias) { $where_values[$alias] = $rows[$j][$alias]; } if (!$stmt->execute($where_values)) { return herror_stmt($stmt, "update action", "MySQL error for " . "relation '{$foreign_table}' in action {$i}"); } if ($id = $stmt->fetchColumn()) { $stmt->closeCursor(); $rows[$j][$relation['id']] = $id; } else { $stmt->closeCursor(); // If we are allowed to insert the relations, do so if (array_key_exists('insert', $relation) && mb_strtolower($relation['insert']) == 'true') { $where_columns_set = implode(', ', $where_columns); $sql = "INSERT INTO {$foreign_table} SET {$where_columns_set}"; $stmt = $db->prepare($sql); if (!$stmt) { return herror_stmt($stmt, "update action", "MySQL " . "error for relation '{$foreign_table}' in action {$i}"); } if (!$stmt->execute($where_values)) { return herror_stmt($stmt, "update action", "MySQL " . "error for relation '{$foreign_table}' in action {$i}"); } $rows[$j][$relation['id']] = $db->lastInsertId(); } else { return herror("update action", "unable to get id for relation" . "'{$foreign_table}' in action {$i}"); } } // Remove all the relation rows foreach ($relation['columns'] as $relation_column => $alias) { unset($rows[$j][$alias]); } } } } $columns = array_keys($rows[0]); // WHERE, ORDER BY, LIMIT $where = array(); $where_values = array(); $where_type = ' AND '; if (array_key_exists('where_type', $action)) { if (!array_key_exists($action['where_type'], $where_connect_types)) { return herror("update action", "invalid where type " . "'{$action['where_type']}' for action {$i}"); } $where_type = $where_connect_types[$action['where_type']]; } if (array_key_exists('where', $action)) { if (!is_array($action['where'])) { return herror("update action", "paramater 'where' for action {$i} " . "exists but is not an object"); } if (!count($action['where'])) { return herror("update action", "paramater 'where' for action {$i} " . "exists but contains no where expressions"); } $j = 0; foreach ($action['where'] as $expr) { if (!array_key_exists('type', $expr)) { return param_error("update action", "type", "where " . "expression {$j} in action {$i}"); } if (!array_key_exists($expr['type'], $where_types)) { return herror("update action", "where expression type {$expr['type']}" . " does not exists for where expression {$j} in action {$i}"); } if (!array_key_exists('column', $expr)) { return param_error("update action", "column", "where " . "expression {$j} in action {$i}"); } $column = $expr['column']; // Check all tables, including relation tables if (!check_column($column, $table, $column_cache)) { return herror("update action", "invalid column " . "'{$column}' for where expression {$j} in action {$i}"); } if (!array_key_exists('value', $expr)) { return param_error("update action", "value", "where " . "expression {$j} in action {$i}"); } $where[] = "{$column} {$where_types[$expr['type']]} :where_{$column}"; $where_values[":where_{$column}"] = $expr['value']; $j++; } $where = " WHERE " . implode($where_type, $where); } else { $where = ''; } $order_by = array(); if (array_key_exists('order_by', $action)) { if (!count($action['order_by'])) { return herror("update action", "paramater 'order_by' for action {$i} " . "exists but contains no order expressions"); } $j = 0; foreach ($action['order_by'] as $order) { if (!array_key_exists('column', $order)) { return param_error("update action", "column", "order " . "expression {$j} in action {$i}"); } $column = $order['column']; // Check all tables, including relation tables if (!check_column($column, $table, $column_cache)) { return herror("update action", "invalid column " . "'{$column}' for order expression {$j} in action {$i}"); } $direction = 'ASC'; if (array_key_exists('direction', $order)) { $direction = mb_strtoupper($order['direction']); if ($direction != 'ASC' && $direction != 'DESC') { return herror("update action", "invalid direction " . "'{$direction}' for order expression {$j} in action {$i}"); } } $order_by[] = "{$column} {$direction}"; $j++; } $order_by = " ORDER BY " . implode(', ', $order_by); } else { $order_by = ''; } $limit = ''; if (array_key_exists('limit', $action)) { if (!is_int($action['limit']) || $action['limit'] < 0) { return herror("update action", "limit for in action {$i} must be a " . "positive integer"); } $limit = " LIMIT {$action['limit']}"; } $value_holders = array(); foreach ($columns as $alias) { $value_holders[] = "{$alias} = :{$alias}"; } $value_holders = implode(', ', $value_holders); $sql = "UPDATE {$table} SET {$value_holders}{$where}{$order_by}{$limit}"; $stmt = $db->prepare($sql); if (!$stmt) { return herror_sql("insert action", "MySQL error for row action {$i}"); } for ($j = 0; $j < $row_count; $j++) { if (!$stmt->execute(array_merge($rows[$j], $where_values))) { $err = $stmt->errorInfo(); return herror_stmt($stmt, "insert action", "MySQL error for row " . "{$j} in action {$i}: " . $err[2]); } $stmt->closeCursor(); } $db->commit(); }
function GetFlistIds($flistString, $allowPages = false, $allowMultipleMatches = true, $failOnEmpty = true) { global $fbcmdPrefs; global $flistMatchArray; global $flistMatchIdString; $unknownNames = array(); $flistMatchArray = array(); $flistFQL = array('FriendId', 'FriendBaseInfo'); $flistItems = explode(',', $flistString); // Pre-process to see if Friend Lists or Pages or Groups are required foreach ($flistItems as $item) { if (substr($item, 0, 1) == $fbcmdPrefs['prefix_friendlist']) { array_push_unique($flistFQL, 'FriendListNames'); array_push_unique($flistFQL, 'FriendListMembers'); } if (substr($item, 0, 1) == $fbcmdPrefs['prefix_page'] || strtoupper($item) == '=PAGES') { array_push_unique($flistFQL, 'PageId'); array_push_unique($flistFQL, 'PageNames'); } if (substr($item, 0, 1) == $fbcmdPrefs['prefix_group']) { array_push_unique($flistFQL, 'GroupNames'); } if (substr($item, 0, 1) == $fbcmdPrefs['prefix_tag']) { array_push_unique($flistFQL, 'PageId'); array_push_unique($flistFQL, 'PageNames'); array_push_unique($flistFQL, 'GroupNames'); } } MultiFQL($flistFQL); global $dataFriendId; global $dataFriendBaseInfo; global $indexFriendBaseInfo; global $fbUser; global $flistChunkCounter; $flistChunkCounter = 0; foreach ($flistItems as $item) { $itemUC = strtoupper($item); // =KEYWORDS ///////////////////////////////////////////////////////////// if (substr($item, 0, 1) == '=') { if ($itemUC == '=ME') { array_push_unique($flistMatchArray, $fbUser); continue; } if ($itemUC == '=ALL') { foreach ($dataFriendId as $fid) { array_push_unique($flistMatchArray, $fid['uid2']); } continue; } if (substr($itemUC, 0, 5) == '=BDAY') { $matchTime = time(); if (preg_match("/=BDAY\\+(\\d+)?\$/", $itemUC, $matches)) { if (isset($matches[1])) { $matchTime += 24 * 60 * 60 * $matches[1]; } else { $matchTime += 24 * 60 * 60; } } if (preg_match("/=BDAY-(\\d+)?\$/", $itemUC, $matches)) { if (isset($matches[1])) { $matchTime -= 24 * 60 * 60 * $matches[1]; } else { $matchTime -= 24 * 60 * 60; } } if (preg_match("/=BDAY=(.+)\$/", $itemUC, $matches)) { $matchTime = strtotime($matches[1]); if (!$matchTime) { FbcmdWarning("Bad BDAY Syntax: [{$item}] using today"); $matchTime = time(); } } $matchDate = date('m/d', $matchTime); foreach ($dataFriendBaseInfo as $fbi) { if (substr($fbi['birthday_date'], 0, 5) == $matchDate) { array_push_unique($flistMatchArray, $fbi['uid']); } } continue; } if ($itemUC == '=ONLINE') { foreach ($dataFriendBaseInfo as $fbi) { if ($fbi['online_presence'] == 'active' || $fbi['online_presence'] == 'idle' && $fbcmdPrefs['online_idle']) { array_push_unique($flistMatchArray, $fbi['uid']); } } continue; } if ($itemUC == '=PAGES') { if (!$allowPages) { global $fbcmdCommand; FbcmdWarning("{$fbcmdCommand} does not support pages: {$item} ignored"); } else { global $dataPageId; foreach ($dataPageId as $page_id) { array_push_unique($flistMatchArray, $page_id['page_id']); } } continue; } FbcmdWarning("Unknown flist entry: {$item}"); continue; } // _FRIEND LIST ////////////////////////////////////////////////////////// if (substr($item, 0, 1) == $fbcmdPrefs['prefix_friendlist']) { global $dataFriendListNames; global $dataFriendListMembers; $flidMatches = FlistMatch($item, true, $dataFriendListNames, 'flid', 'name', $allowMultipleMatches); if (count($flidMatches)) { foreach ($dataFriendListMembers as $flm) { // http://bugs.developers.facebook.com/show_bug.cgi?id=5977 // if (in_array($flm[0],$flidMatches)) { // array_push_unique($flistMatchArray,$flm[1]); // } if (in_array($flm['flid'], $flidMatches)) { array_push_unique($flistMatchArray, $flm['uid']); } } } continue; } // !USERNAME ///////////////////////////////////////////////////////////// if (substr($item, 0, 1) == $fbcmdPrefs['prefix_username']) { $uidMatches = FlistMatch($item, true, $dataFriendBaseInfo, 'uid', 'username', $allowMultipleMatches); array_merge_unique($flistMatchArray, $uidMatches); continue; } // +PAGES //////////////////////////////////////////////////////////////// if (substr($item, 0, 1) == $fbcmdPrefs['prefix_page']) { if (!$allowPages) { global $fbcmdCommand; FbcmdWarning("{$fbcmdCommand} does not support pages: {$item} ignored"); } else { global $dataPageNames; $pidMatches = FlistMatch($item, true, $dataPageNames, 'page_id', 'name', $allowMultipleMatches); array_merge_unique($flistMatchArray, $pidMatches); } continue; } // ~GROUPS /////////////////////////////////////////////////////////////// if (substr($item, 0, 1) == $fbcmdPrefs['prefix_group']) { global $dataGroupNames; global $fbObject; $gidMatches = FlistMatch($item, true, $dataGroupNames, 'gid', 'name', false); if (isset($gidMatches[0])) { $fql = "SELECT uid FROM group_member WHERE gid={$gidMatches[0]}"; try { $fbReturn = $fbObject->api_client->fql_query($fql); TraceReturn($fbReturn); } catch (Exception $e) { FbcmdException($e); } if (!empty($fbReturn)) { foreach ($fbReturn as $u) { $flistMatchArray[] = $u['uid']; } } else { FbcmdWarning("Could Not get Group Members for GROUP {$gidMatches[0]}"); } } continue; } // @TAG FORMAT /////////////////////////////////////////////////////////// if (substr($item, 0, 1) == $fbcmdPrefs['prefix_tag']) { $tagList = MatchTag(substr($item, 1), $allowPages, false); if ($tagList) { array_merge_unique($flistMatchArray, array($tagList[0][0])); } continue; } // REGULAR NAMES ///////////////////////////////////////////////////////// $uidMatches = FlistMatch($item, false, $dataFriendBaseInfo, 'uid', 'name', $allowMultipleMatches); array_merge_unique($flistMatchArray, $uidMatches); } if (count($flistMatchArray) == 0) { if ($failOnEmpty) { if (substr(strtoupper($flistString), 0, 5) == '=BDAY') { print "No Friends With Birthday Matches\n"; exit; } else { FbcmdFatalError("Empty flist: {$flistString}"); } } else { $flistMatchIdString = ''; } } else { $flistMatchIdString = implode(',', $flistMatchArray); } foreach ($flistMatchArray as $id) { if (ProfileName($id) == 'unknown') { $unknownNames[] = $id; } } if (count($unknownNames) > 0) { global $fqlFlistNames; global $keyFlistNames; $fqlFlistNames = 'SELECT id,name FROM profile WHERE id IN (' . implode(',', $unknownNames) . ')'; $keyFlistNames = 'id'; MultiFQL(array('FlistNames')); } return; }
/** * put your comment there... * * @param mixed $system * @param mixed $params * * FOR RULES * rules - rules queries - to search related records on server side * getrelrecs (=1) - search relationship records (along with related) on server side * topids - list of records ids, it is used to compose 'parentquery' parameter to use in rules (@todo - replace with new rules algorithm) * * INTERNAL/recursive * parentquery - sql expression to substiture in rule query * sql - sql expression to execute (used as recursive parameters to search relationship records) * * SEARCH parameters that are used to compose sql expression * q - query string (old mode) or json array (new mode) * w (=all|bookmark a|b) - search among all or bookmarked records * limit - limit for sql query is set explicitely on client side * offset - offset parameter value for sql query * s - sort order * * OUTPUT parameters * vo (=h3) - output format in h3 for backward capability (for detail=ids only) * needall (=1) - by default it returns only first 3000, to return all set it to 1, * it is set to 1 for server-side rules searches * publiconly (=1) - ignore current user and returns only public records * * detail (former 'f') - ids - only record ids * header - record header * timemap - record header + timemap details * detail - record header + all details * structure - record header + all details + record type structure (for editing) - NOT USED * * CLIENT SIDE * id - unque id to sync with client side * source - id of html element that is originator of this search * qname - original name of saved search (for messaging) */ function recordSearch($system, $params) { //for error message $savedSearchName = @$params['qname'] ? "Saved search: " . $params['qname'] . "<br>" : ""; if (!@$params['detail']) { $params['detail'] = @$params['f']; //backward capability } $istimemap_request = @$params['detail'] == 'timemap'; $istimemap_counter = 0; //total records with timemap data $fieldtypes_ids = null; if ($istimemap_request) { //get date,year and geo fields from structure $fieldtypes_ids = dbs_GetDetailTypes($system, array('date', 'year', 'geo'), 3); if ($fieldtypes_ids == null || count($fieldtypes_ids) == 0) { $fieldtypes_ids = array(DT_GEO_OBJECT, DT_DATE, DT_START_DATE, DT_END_DATE); //9,10,11,28'; } $fieldtypes_ids = implode(',', $fieldtypes_ids); } else { if (!in_array(@$params['detail'], array('header', 'timemap', 'detail', 'structure'))) { //specific set of detail fields if (is_array($params['detail'])) { $fieldtypes_ids = $params['detail']; } else { $fieldtypes_ids = explode(',', $params['detail']); } if (is_array($fieldtypes_ids) && (count($fieldtypes_ids) > 1 || is_numeric($fieldtypes_ids[0]))) { $fieldtypes_ids = implode(',', $fieldtypes_ids); $params['detail'] = 'detail'; } else { $fieldtypes_ids = null; $params['detail'] = 'ids'; } } } $is_ids_only = 'ids' == $params['detail']; $return_h3_format = @$params['vo'] == 'h3' && $is_ids_only; if (null == $system) { $system = new System(); if (!$system->init(@$_REQUEST['db'])) { $response = $system->getError(); if ($return_h3_format) { $response['error'] = $response['message']; } return $response; } } $mysqli = $system->get_mysqli(); $currentUser = $system->getCurrentUser(); if ($system->get_user_id() < 1) { $params['w'] = 'all'; //does not allow to search bookmarks if not logged in } if ($is_ids_only) { $select_clause = 'select SQL_CALC_FOUND_ROWS DISTINCT rec_ID '; } else { $select_clause = 'select SQL_CALC_FOUND_ROWS DISTINCT ' . 'bkm_ID,' . 'bkm_UGrpID,' . 'rec_ID,' . 'rec_URL,' . 'rec_RecTypeID,' . 'rec_Title,' . 'rec_OwnerUGrpID,' . 'rec_NonOwnerVisibility,' . 'bkm_PwdReminder '; /*.'rec_URLLastVerified,' .'rec_URLErrorMessage,' .'bkm_PwdReminder ';*/ } if ($currentUser && @$currentUser['ugr_ID'] > 0) { $currUserID = $currentUser['ugr_ID']; } else { $currUserID = 0; $params['w'] = 'all'; } if (@$params['topids']) { //if topids are defined we use them as starting point for following rule query // it is used for incremental client side only //@todo - implement it in different way - substitute topids to query json as predicate ids: $query_top = array(); if (strcasecmp(@$params['w'], 'B') == 0 || strcasecmp(@$params['w'], 'bookmark') == 0) { $query_top['from'] = 'FROM usrBookmarks TOPBKMK LEFT JOIN Records TOPBIBLIO ON bkm_recID=rec_ID '; } else { $query_top['from'] = 'FROM Records TOPBIBLIO LEFT JOIN usrBookmarks TOPBKMK ON bkm_recID=rec_ID and bkm_UGrpID=' . $currUserID . ' '; } $query_top['where'] = "(TOPBIBLIO.rec_ID in (" . $params['topids'] . "))"; $query_top['sort'] = ''; $query_top['limit'] = ''; $query_top['offset'] = ''; $params['parentquery'] = $query_top; //parentquery parameter is used in get_sql_query_clauses } else { if (@$params['rules']) { //special case - server side operation // rules - JSON array the same as stored in saved searches table if (is_array(@$params['rules'])) { $rules_tree = $params['rules']; } else { $rules_tree = json_decode($params['rules'], true); } $flat_rules = array(); $flat_rules[0] = array(); //create flat rule array $rules = _createFlatRule($flat_rules, $rules_tree, 0); //find result for main query unset($params['rules']); if (@$params['limit']) { unset($params['limit']); } if (@$params['offset']) { unset($params['offset']); } if (@$params['vo']) { unset($params['vo']); } $params['needall'] = 1; //return all records $resSearch = recordSearch($system, $params); $keepMainSet = true; if ($keepMainSet) { //find main query results $fin_result = $resSearch; //main result set $flat_rules[0]['results'] = $is_ids_only ? $fin_result['data']['records'] : array_keys($fin_result['data']['records']); //get ids } else { //empty main result set //remove from $fin_result! but keep in $flat_rules[0]['results']? } $is_get_relation_records = @$params['getrelrecs'] == 1; //get all related and relationship records foreach ($flat_rules as $idx => $rule) { if ($idx == 0) { continue; } $is_last = @$rule['islast'] == 1; //create request $params['q'] = $rule['query']; $parent_ids = $flat_rules[$rule['parent']]['results']; //list of record ids of parent resultset $rule['results'] = array(); //reset //split by 3000 - search based on parent ids (max 3000) $k = 0; while ($k < count($parent_ids)) { //$need_details2 = $need_details && ($is_get_relation_records || $is_last); $params3 = $params; $params3['topids'] = implode(",", array_slice($parent_ids, $k, 3000)); if (!$is_last) { //($is_get_relation_records || //$params3['detail'] = 'ids'; //no need in details for preliminary results ??????? } $response = recordSearch($system, $params3); if ($response['status'] == HEURIST_OK) { //merge with final results if ($is_ids_only) { $fin_result['data']['records'] = array_merge_unique($fin_result['data']['records'], $response['data']['records']); } else { $fin_result['data']['records'] = mergeRecordSets($fin_result['data']['records'], $response['data']['records']); $fin_result['data']['order'] = array_merge($fin_result['data']['order'], array_keys($response['data']['records'])); foreach (array_keys($response['data']['records']) as $rt) { $rectype_id = @$rt['4']; if ($rectype_id) { /*if(@$fin_result['data']['rectypes'][$rectype_id]){ $fin_result['data']['rectypes'][$rectype_id]++; }else{ $fin_result['data']['rectypes'][$rectype_id]=1; }*/ if (!array_key_exists($rectype_id, $fin_result['data']['rectypes'])) { $fin_result['data']['rectypes'][$rectype_id] = 1; } } } } if (!$is_last) { //add top ids for next level $flat_rules[$idx]['results'] = array_merge_unique($flat_rules[$idx]['results'], $is_ids_only ? $response['data']['records'] : array_keys($response['data']['records'])); } if ($is_get_relation_records && (strpos($params3['q'], "related_to") > 0 || strpos($params3['q'], "relatedfrom") > 0)) { //find relation records (recType=1) //create query to search related records if (strcasecmp(@$params3['w'], 'B') == 0 || strcasecmp(@$params3['w'], 'bookmark') == 0) { $from = 'FROM usrBookmarks TOPBKMK LEFT JOIN Records TOPBIBLIO ON bkm_recID=rec_ID '; } else { $from = 'FROM Records TOPBIBLIO LEFT JOIN usrBookmarks TOPBKMK ON bkm_recID=rec_ID and bkm_UGrpID=' . $currUserID . ' '; } if (strpos($params3['q'], "related_to") > 0) { $fld2 = "rl_SourceID"; $fld1 = "rl_TargetID"; } else { $fld1 = "rl_SourceID"; $fld2 = "rl_TargetID"; } $where = "WHERE (TOPBIBLIO.rec_ID in (select rl_RelationID from recLinks where (rl_RelationID is not null) and {$fld1} in (" . $params3['topids'] . ") and {$fld2} in (" . implode(",", $is_ids_only ? $response['data']['records'] : array_keys($response['data']['records'])) . ")))"; $params2 = $params3; unset($params2['topids']); unset($params2['q']); $params2['sql'] = $select_clause . $from . $where; $response = recordSearch($system, $params2); //search for relationship records if ($response['status'] == HEURIST_OK) { if (!@$fin_result['data']['relationship']) { $fin_result['data']['relationship'] = array(); } if ($is_ids_only) { $fin_result['data']['relationship'] = array_merge_unique($fin_result['data']['relationship'], $response['data']['records']); } else { $fin_result['data']['relationship'] = mergeRecordSets($fin_result['data']['relationship'], $response['data']['records']); } /*merge with final results if($is_ids_only){ $fin_result['data']['records'] = array_merge($fin_result['data']['records'], $response['data']['records']); }else{ $fin_result['data']['records'] = mergeRecordSets($fin_result['data']['records'], $response['data']['records']); $fin_result['data']['order'] = array_merge($fin_result['data']['order'], array_keys($response['data']['records'])); $fin_result['data']['rectypes'][1] = 1; } */ } } //$is_get_relation_records } else { //@todo terminate execution and return error } $k = $k + 3000; } //while chunks } //for rules if ($is_ids_only) { //$fin_result['data']['records'] = array_unique($fin_result['data']['records']); } $fin_result['data']['count'] = count($fin_result['data']['records']); if ($return_h3_format) { $fin_result = array("resultCount" => $fin_result['data']['count'], "recordCount" => $fin_result['data']['count'], "recIDs" => implode(",", $fin_result['data']['records'])); } //@todo - assign if size less than 3000? only $fin_result['data']['mainset'] = $flat_rules[0]['results']; return $fin_result; } } //END RULES $chunk_size = PHP_INT_MAX; if (@$params['sql']) { $query = $params['sql']; } else { $is_mode_json = false; if (@$params['q']) { if (is_array(@$params['q'])) { $query_json = $params['q']; //DEBUG error_log('Q='.print_r($params['q'],true)); } else { $query_json = json_decode(@$params['q'], true); } if (is_array($query_json) && count($query_json) > 0) { $params['q'] = $query_json; $is_mode_json = true; } } else { return $system->addError(HEURIST_INVALID_REQUEST, $savedSearchName . "Invalid search request. Missed query parameter 'q'"); } if ($is_mode_json) { $aquery = get_sql_query_clauses_NEW($mysqli, $params, $currentUser); } else { $aquery = get_sql_query_clauses($mysqli, $params, $currentUser); //!!!! IMPORTANT CALL OR compose_sql_query at once } if ($is_ids_only && @$params['needall']) { $chunk_size = PHP_INT_MAX; $aquery["limit"] = ''; } else { $chunk_size = $system->user_GetPreference('search_detail_limit'); //limit for map/timemap output } if (!isset($aquery["where"]) || trim($aquery["where"]) === '') { return $system->addError(HEURIST_DB_ERROR, "Invalid search request; unable to construct valid SQL query", null); } $query = $select_clause . $aquery["from"] . " WHERE " . $aquery["where"] . $aquery["sort"] . $aquery["limit"] . $aquery["offset"]; //error_log($is_mode_json.' '.$query); /* DEBUG if($params['q']=='doerror'){ //force error $query ='abracadabra'; } */ } $res = $mysqli->query($query); if (!$res) { $response = $system->addError(HEURIST_DB_ERROR, $savedSearchName . 'Search query error', $mysqli->error); } else { $fres = $mysqli->query('select found_rows()'); if (!$fres) { $response = $system->addError(HEURIST_DB_ERROR, $savedSearchName . 'Search query error (retrieving number of records)', $mysqli->error); } else { $total_count_rows = $fres->fetch_row(); $total_count_rows = $total_count_rows[0]; $fres->close(); if ($is_ids_only) { //------------------------ LOAD and RETURN only IDS $records = array(); while ($row = $res->fetch_row()) { array_push($records, (int) $row[0]); } $res->close(); if (@$params['vo'] == 'h3') { //output version $response = array('resultCount' => $total_count_rows, 'recordCount' => count($records), 'recIDs' => implode(',', $records)); } else { $response = array('status' => HEURIST_OK, 'data' => array('queryid' => @$params['id'], 'count' => $total_count_rows, 'offset' => get_offset($params), 'reccount' => count($records), 'records' => $records)); } } else { //---------------------------------- // read all field names $_flds = $res->fetch_fields(); $fields = array(); foreach ($_flds as $fld) { array_push($fields, $fld->name); } array_push($fields, 'rec_ThumbnailURL'); //array_push($fields, 'rec_Icon'); //last one -icon ID $rectype_structures = array(); $rectypes = array(); $records = array(); $order = array(); // load all records while ($row = $res->fetch_row()) { //3000 maximal allowed chunk array_push($row, $fieldtypes_ids ? '' : fileGetThumbnailURL($system, $row[2])); //array_push( $row, $row[4] ); //by default icon if record type ID $records[$row[2]] = $row; array_push($order, $row[2]); if (!@$rectypes[$row[4]]) { $rectypes[$row[4]] = 1; } } $res->close(); if (($istimemap_request || $params['detail'] == 'detail' || $params['detail'] == 'structure') && count($records) > 0) { //search for specific details if (!$fieldtypes_ids && $fieldtypes_ids != '') { $detail_query = 'select dtl_RecID,' . 'dtl_DetailTypeID,' . 'dtl_Value,' . 'AsWKT(dtl_Geo), 0, 0, 0 ' . 'from recDetails where dtl_RecID in (' . join(',', array_keys($records)) . ') ' . ' and dtl_DetailTypeID in (' . $fieldtypes_ids . ')'; } else { $detail_query = 'select dtl_RecID,' . 'dtl_DetailTypeID,' . 'dtl_Value,' . 'AsWKT(dtl_Geo),' . 'dtl_UploadedFileID,' . 'recUploadedFiles.ulf_ObfuscatedFileID,' . 'recUploadedFiles.ulf_Parameters ' . 'from recDetails left join recUploadedFiles on ulf_ID = dtl_UploadedFileID where dtl_RecID in (' . join(',', array_keys($records)) . ')'; } // @todo - we may use getAllRecordDetails $res_det = $mysqli->query($detail_query); if (!$res_det) { $response = $system->addError(HEURIST_DB_ERROR, $savedSearchName . 'Search query error (retrieving details)', $mysqli->error); return $response; } else { while ($row = $res_det->fetch_row()) { $recID = array_shift($row); if (!array_key_exists('d', $records[$recID])) { $records[$recID]['d'] = array(); } $dtyID = $row[0]; $val = null; if ($row[2]) { $val = $row[1] . ' ' . $row[2]; //dtl_Geo @todo convert to JSON } else { if ($row[3]) { $val = array($row[4], $row[5]); //obfuscated value for fileid } else { if (@$row[1]) { $val = $row[1]; } } } if ($val) { if (!array_key_exists($dtyID, $records[$recID]['d'])) { $records[$recID]['d'][$dtyID] = array(); } array_push($records[$recID]['d'][$dtyID], $val); } } //while $res_det->close(); ///@todo // 1. optimize loop - include into main detail loop // 2. exit loop if more than 5000 geo enabled // 3. return geojson and timeline items //additional loop for timemap request //1. exclude records without timemap data //2. limit to $chunk_size if ($istimemap_request) { $tm_records = array(); $order = array(); $rectypes = array(); foreach ($records as $recID => $record) { if (is_array(@$record['d']) && count($record['d']) > 0) { //this record is time enabled if ($istimemap_counter < $chunk_size) { $tm_records[$recID] = $record; array_push($order, $recID); $rectypes[$record[4]] = 1; } $istimemap_counter++; } } $records = $tm_records; $total_count_rows = $istimemap_counter; } //$istimemap_request } } //$need_details $rectypes = array_keys($rectypes); if ($params['detail'] == 'structure' && count($rectypes) > 0) { //rarely used in editing.js //description of recordtype and used detail types $rectype_structures = dbs_GetRectypeStructures($system, $rectypes, 1); //no groups } //"query"=>$query, $response = array('status' => HEURIST_OK, 'data' => array('queryid' => @$params['id'], 'count' => $total_count_rows, 'offset' => get_offset($params), 'reccount' => count($records), 'fields' => $fields, 'records' => $records, 'order' => $order, 'rectypes' => $rectypes, 'structures' => $rectype_structures)); if ($fieldtypes_ids) { $response['data']['fields_detail'] = explode(',', $fieldtypes_ids); } } //$is_ids_only } } return $response; }