function doDetailInsertion($recordID, $details, $recordType, $wg, &$nonces, &$retitleRecs, $modeImport) { /* $nonces : nonce-to-bibID mapping, makes it possible to resolve recDetails values of reference variety */ /* $retitleRecs : set of records whos titles could be out of date and need recalc */ /* * $details is the form * $details = array("t:1" => array("bd:234463" => "7th Ave"), * ,,, * "t:11" => array("0" => "p POINT(-73.951172 40.805661)")); * where t:id means detail type id and bd:id means detail record id * new details are array values without a preceeding detail ID as in the last line of this example */ $dtyIDs = array(); // do a double-pass to grab the expected varieties for each bib-detail-type we encounter, along with other constraints foreach ($details as $dtyID => $pairs) { if (substr($dtyID, 0, 2) != "t:") { continue; } if (!($bdtID = intval(substr($dtyID, 2)))) { continue; } array_push($dtyIDs, $bdtID); } $dtyVarieties = mysql__select_assoc("defDetailTypes", "dty_ID", "dty_Type", "dty_ID in (" . join($dtyIDs, ",") . ")"); if ($modeImport != 2) { //import without check of record type structure //TODO saw: need to change this to include min value or perhaps we let it go and allow saving the min across multiple saves. $repeats = mysql__select_assoc("defRecStructure", "rst_DetailTypeID", "rst_MaxValues", "rst_RecTypeID=" . $recordType); // $repeats = mysql__select_assoc("defRecStructure", "rst_DetailTypeID", "rst_MaxValues", "rst_DetailTypeID in (" . join($dtyIDs, ",") . ") and rst_RecTypeID=" . $recordType); } /*****DEBUG****/ //error_log("repeats = ".print_r($repeats,true)); /*****DEBUG****/ //error_log("details = ".print_r($details,true)); $updateIDs = array(); $updateQueries = array(); $insertQueryValues = array(); $badIdInsertQueryValues = array(); $deleteIDs = array(); $ignoreIDs = array(); $translated = array(); $translatedIDs = array(); // second pass to divide the work up in to inserts, updates, deletes, translates and ignores foreach ($details as $dtyID => $pairs) { if (substr($dtyID, 0, 2) != "t:") { continue; } // skip any non t: or non type designators if (!($bdtID = intval(substr($dtyID, 2)))) { continue; } // invalid (non integer) type id so skip it $firstDetail = true; foreach ($pairs as $bdID => $val) { if (substr($bdID, 0, 3) == "bd:") { // this detail corresponds to an existing recDetails: remember its existing dtl_ID if (!($bdID = intval(substr($bdID, 3)))) { continue; } // invalid (non integer) id so skip it // check detail exist for the given record $resDtl = mysql_query("select dtl_DetailTypeID from recDetails where dtl_RecID = {$recordID} and dtl_ID = {$bdID}"); if (mysql_num_rows($resDtl) == 1) { $dtlTypeID = mysql_fetch_row($resDtl); if ($dtlTypeID[0] != $bdtID) { // invalid type supplied so skip and give warning warnSaveRec("invalid detail type supplied {$bdtID} for existing detail, did not update detail id {$bdID} ignoring"); array_push($ignoreIDs, $bdID); continue; } } else { // no existing dtl id for the given record so change this to insert and give warning. warnSaveRec("detail id {$bdID} is not part of record {$recordID}, inserting new detail instead"); $oldBdID = $bdID; $bdID = false; // fail test differently to signal translate } } else { // simple case: this is a new detail (no existing dtl_ID) it assumes an array index number if ($bdID != intval($bdID)) { continue; } //bd155 is not equal to 155 while if this is an array index $bdID is numeric $bdID = ""; //signal insert } $val = trim($val); $bdVal = $bdFileID = $bdGeo = "NULL"; if ($modeImport != 2) { //import without check of record type structure //check max limit constraints if (!array_key_exists($bdtID, $repeats)) { //if no entry in repeats then extra detail /*****DEBUG****/ //error_log("non rectype detail type $bdtID found"); warnSaveRec("non rectype detail type {$bdtID} found"); } else { if (is_numeric($repeats[$bdtID])) { if ($repeats[$bdtID] >= 1) { $repeats[$bdtID] = $repeats[$bdtID] - 1; // decrement to reduce limit count NOTE: assumes that all details are given to save } else { if ($firstDetail && $repeats[$bdtID] == 0) { // case of not allowed warnSaveRec("detail type supplied {$bdtID} is not allowed, marking detail id {$bdID} for delete"); continue; } else { warnSaveRec("hit max for detail type supplied {$bdtID} , ignoring update detail id {$bdID}"); array_push($ignoreIDs, $bdID); } } } } } switch ($dtyVarieties[$bdtID]) { case "integer": // these should no logner exist, retained for backward compatibility // bug: non-integer values are not saved if (intval($val) || $val == "0") { $bdVal = intval($val); } else { if ($bdID) { //not integer so ignore array_push($ignoreIDs, $bdID); continue; } } break; case "float": if (floatval($val) || preg_match('/^0(?:[.]0*)?$/', $val)) { $bdVal = floatval($val); } else { if ($bdID) { //not a float so ignore array_push($ignoreIDs, $bdID); continue; } } break; case "freetext": case "blocktext": case "date": case "year": case "urlinclude": // these (year and urlinclude) should no logner exist, retained for backward compatibility if (!$val) { //TODO: SAW check if this includes setting a string to "". if so perhaps this is a second pass delete if ($bdID) { array_push($ignoreIDs, $bdID); } continue; } $bdVal = "'" . addslashes($val) . "'"; break; case "boolean": // these should no logner exist, retained for backward compatibility $bdVal = $val && $val != "0" ? "'true'" : "'false'"; break; case "enum": case "relationtype": //saw TODO: change this to call validateEnumTerm(RectypeID, DetailTypeID) also Term limits // also may need to separate enum from relationtype // validate that the id is for the given detail type. /*if (mysql_num_rows(mysql_query("select trm_ID from defTerms left join defDetailTypes on dty_NativeVocabID = trm_VocabID where dty_ID=$bdtID and trm_ID='".$val."'")) <= 0) { jsonError("invalid enumeration value \"$val\""); } */ $bdVal = "'" . $val . "'"; break; case "resource": // check that the given resource exists and is fit to point to if ($val[0] == "#") { // a nonce value -- find the appropriate bibID if ($nonces && $nonces[$val]) { $val = $nonces[$val]; if (is_array($retitleRecs)) { array_push($retitleRecs, $val); } } else { errSaveRec("invalid resource reference '" . $val . "' for detail type '" . $bdtID); return array("error" => "recordID = {$recordID} rectype = {$recordType} detailtype = {$bdtID}" . ($bdID ? " detailID = {$bdID}" : "")); } } //FIXME :saw change this to check for superuser and valid recID or valid and viewable record for current user. if (mysql_num_rows(mysql_query("select rec_ID from Records where (! rec_OwnerUGrpID or rec_OwnerUGrpID={$wg}) and rec_ID=" . intval($val))) <= 0) { // jsonError("invalid resource #".intval($val)); } $bdVal = intval($val); break; case "file": if (is_numeric($val)) { //this is ulf_ID $ulf_ID = intval($val); } else { // new way - URL or JSON string with file data array (structure similar get_uploaded_file_info) $ulf_ID = register_external($val); //this is URL } if ($ulf_ID == null || mysql_num_rows(mysql_query("select ulf_ID from recUploadedFiles where ulf_ID=" . $ulf_ID)) <= 0) { errSaveRec("invalid file pointer '" . $val . "' for detail type '" . $bdtID); return array("error" => "recordID = {$recordID} rectype = {$recordType} detailtype = {$bdtID}" . ($bdID ? " detailID = {$bdID}" : "")); } $bdFileID = intval($ulf_ID); break; case "geo": $geoType = trim(substr($val, 0, 2)); $geoVal = trim(substr($val, 2)); $res = mysql_query("select geomfromtext('" . addslashes($geoVal) . "') = 'Bad object'"); $row = mysql_fetch_row($res); if ($row[0]) { // bad object! Go stand in the corner. errSaveRec("invalid geographic value '" . $val . "' for detail type '" . $bdtID); return array("error" => "recordID = {$recordID} rectype = {$recordType} detailtype = {$bdtID}" . ($bdID ? " detailID = {$bdID}" : "")); } $bdVal = '"' . addslashes($geoType) . '"'; $bdGeo = "geomfromtext('" . addslashes($geoVal) . "')"; case "separator": case "relmarker": continue; //noop since separators and relmarker have no detail values // saw Decide - should we do a relationConstraints check here //noop since separators and relmarker have no detail values // saw Decide - should we do a relationConstraints check here default: // ??? if ($bdID) { array_push($ignoreIDs, $bdID); } continue; } if ($bdID) { //danger the following update must restrict to a single detail id. //TODO: saw perhaps we should check value the same? array_push($updateQueries, "update recDetails set dtl_Value={$bdVal}, dtl_UploadedFileID={$bdFileID}, dtl_Geo={$bdGeo} where dtl_ID={$bdID} and dtl_DetailTypeID={$bdtID} and dtl_RecID={$recordID}"); array_push($updateIDs, $bdID); } else { if ($bdID === false) { //bad bdID passed insert detail array_push($badIdInsertQueryValues, "({$recordID}, {$bdtID}, {$bdVal}, {$bdFileID}, {$bdGeo}," . ($modeImport > 0 ? 1 : 0) . ")"); $translated[$oldBdID] = array('val' => $val, 'dtType' => $bdtID); array_push($translatedIDs, $oldBdID); } else { array_push($insertQueryValues, "({$recordID}, {$bdtID}, {$bdVal}, {$bdFileID}, {$bdGeo}," . ($modeImport > 0 ? 1 : 0) . ")"); } } $firstDetail = false; } //end details values loop for dty } //end dty loop //delete all details except the one that are being updated $deleteDetailIDsQuery = "select dtl_ID from recDetails where dtl_RecID={$recordID}"; if (count($updateIDs)) { $deleteDetailIDsQuery .= " and dtl_ID not in (" . join(",", $updateIDs) . ")"; } if (count($ignoreIDs)) { $deleteDetailIDsQuery .= " and dtl_ID not in (" . join(",", $ignoreIDs) . ")"; } $resDel = mysql_query($deleteDetailIDsQuery); if (mysql_error()) { errSaveRec("db error while finding details to be deleted for record ID " . $recordID . " error : " . mysql_error()); return array("error" => "recordID = {$recordID} rectype = {$recordType} "); } // find details to be deleted if (mysql_num_rows($resDel)) { while ($row = mysql_fetch_row($resDel)) { array_push($deleteIDs, $row[0]); } } /*****DEBUG****/ //error_log("ignore detail IDs = ".print_r($ignoreIDs,true)); /*****DEBUG****/ //error_log("update detail IDs = ".print_r($updateIDs,true)); /*****DEBUG****/ //error_log("delete detail IDs = ".print_r($deleteIDs,true)); /* $retval is an array of arrays of detail ids * with an array for deletes, updates and inserts * if they occurred */ $retval = array(); if (count($ignoreIDs)) { $retval["ignored"] = $ignoreIDs; } //update all details to be kept if (count($deleteIDs)) { $deleteDetailsQuery = "delete from recDetails where dtl_ID in (" . join(",", $deleteIDs) . ")"; // mysql_query($deleteDetailsQuery); if (mysql_error()) { errSaveRec("db error while deleteing details (" . join(",", $deleteIDs) . ") for record ID " . $recordID . " error : " . mysql_error()); return array("error" => "recordID = {$recordID} rectype = {$recordType} "); } // $retval["deleted"] = $deleteIDs; } //update all details to be kept if (count($updateQueries)) { /*****DEBUG****/ //error_log("in DoInserts updating details ".print_r($updateQueries,true)); foreach ($updateQueries as $update) { mysql_query($update); if (mysql_error()) { errSaveRec("db error while running '" . $update . "' for record ID " . $recordID . " error : " . mysql_error()); return array("error" => "recordID = {$recordID} rectype = {$recordType} "); } } $retval["updated"] = $updateIDs; } if (count($insertQueryValues)) { //insert all new details /*****DEBUG****/ //error_log("in DoInserts inserting details ".print_r($inserts,true)); mysql_query("insert into recDetails (dtl_RecID, dtl_DetailTypeID, dtl_Value, dtl_UploadedFileID, dtl_Geo, dtl_AddedByImport) values " . join(",", $insertQueryValues)); $first_bd_id = mysql_insert_id(); if (mysql_error()) { errSaveRec("db error while inserting '" . $insertQueryValues . "' for record ID " . $recordID . " error : " . mysql_error()); return array("error" => "recordID = {$recordID} rectype = {$recordType} "); } $retval["inserted"] = range($first_bd_id, $first_bd_id + count($insertQueryValues) - 1); } if (count($badIdInsertQueryValues)) { //insert all new details /*****DEBUG****/ //error_log("in DoInserts inserting Bad ID details ".print_r($badIdInsertQueryValues,true)); $j = 0; foreach ($badIdInsertQueryValues as $valueSet) { mysql_query("insert into recDetails (dtl_RecID, dtl_DetailTypeID, dtl_Value, dtl_UploadedFileID, dtl_Geo, dtl_AddedByImport) values " . $valueSet); if (mysql_error()) { errSaveRec("db error while inserting '" . $valueSet . "' for record ID " . $recordID . " error : " . mysql_error()); return array("error" => "recordID = {$recordID} rectype = {$recordType} "); } $new_bdID = mysql_insert_id(); $translated[$translatedIDs[$j]]['new_bdID'] = $new_bdID; } $retval["translated"] = $translated; $retval["translatedIDs"] = $translatedIDs; } return $retval; }
/** * copy file from another h3 instance and register it * * @param mixed $src_fileid - file id in source db * @return int - file id in destionation db, null - if copy and registration are failed */ function copyRemoteFile($src_fileid) { global $sourcedbname, $dbPrefix, $db_prefix; $sourcedb = $db_prefix . $sourcedbname; $_src_HEURIST_UPLOAD_DIR = HEURIST_UPLOAD_ROOT . $sourcedbname . '/'; $res = mysql_query("select * from {$sourcedb}.`recUploadedFiles` where ulf_ID=" . $src_fileid); if (mysql_num_rows($res) != 1) { print "<div style='color:red;'>no entry for file id#" . $src_fileid . "</div>"; return null; // nothing returned if parameter does not match one and only one row } $file = mysql_fetch_assoc($res); $need_copy = false; $externalFile = false; if ($file['ulf_FileName']) { $filename = $file['ulf_FilePath'] . $file['ulf_FileName']; // post 18/11/11 proper file path and name $need_copy = $file['ulf_FilePath'] == $_src_HEURIST_UPLOAD_DIR; } else { if ($file['ulf_ExternalFileReference']) { $filename = $file['ulf_ExternalFileReference']; // post 18/11/11 proper file path and name $need_copy = false; $externalFile = true; } else { $filename = $_src_HEURIST_UPLOAD_DIR . $file['ulf_ID']; // pre 18/11/11 - bare numbers as names, just use file ID $need_copy = true; } } if (!$externalFile && !file_exists($filename)) { //check if this file is remote print "<div style='color:red;'>File {$filename} not found. Can't register file</div>"; ob_flush(); flush(); // flush to screen return null; } if (false && $externalFile) { //@todo - copy external file and save $data = loadRemoteURLContent($filename); if (!$data) { print "<div style='color:red;'>Error. Can't download {$filename}. Can't register URL</div>"; ob_flush(); flush(); // flush to screen return null; } } if ($need_copy) { $newfilename = HEURIST_UPLOAD_DIR . $file['ulf_OrigFileName']; //if file in source upload dirtectiry copy it to destionation upload directory if (!copy($filename, $newfilename)) { print "<div style='color:red;'>Can't copy file {$fielname} to " . HEURIST_UPLOAD_DIR . "</div>"; ob_flush(); flush(); // flush to screen return null; } $filename = $newfilename; } //returns new file id in dest database if ($externalFile) { $jsonData = json_encode(array('remoteURL' => $filename, 'ext' => $file['ulf_MimeExt'], 'params' => $file['ulf_Parameters'] ? $file['ulf_Parameters'] : null)); $ret = register_external($jsonData, null, false); } else { $ret = register_file($filename, null, false); } if (intval($ret) > 0) { return $ret; } else { print "<div style='color:red;'>Can't register file " . $filename . "</div>"; ob_flush(); flush(); // flush to screen return null; } }
function convertPostToMysql($postVal) { //artem if (is_numeric($postVal)) { //this is old way - ulf_ID return array("dtl_UploadedFileID" => $postVal); } else { // new way - $postVal - json string with file data array - structure similar get_uploaded_file_info $ulf_ID = register_external($postVal); //in uploadFile.php return $ulf_ID == null ? null : array("dtl_UploadedFileID" => $ulf_ID); } }
/** * copy file from another vsn 3 instance and register it * * @param mixed $src_fileid - file id in source db * @return int - file id in destionation db, null - if copy and registration are failed */ function copyRemoteFile($src_fileid) { global $sourcedbname, $dbPrefix, $db_prefix; $sourcedb = $db_prefix . $sourcedbname; $_src_HEURIST_FILESTORE_DIR = HEURIST_UPLOAD_ROOT . $sourcedbname . '/'; $_src_HEURIST_FILES_DIR = HEURIST_UPLOAD_ROOT . $sourcedbname . '/file_uploads/'; $res = mysql_query("select * from {$sourcedb}.`recUploadedFiles` where ulf_ID=" . $src_fileid); if (mysql_num_rows($res) != 1) { print "<div style='color:red;'>no entry (or multiple entries)for file id#" . $src_fileid . "</div>"; return null; // nothing returned if parameter does not match one and only one row } $file = mysql_fetch_assoc($res); $need_copy = false; $externalFile = false; if (@$file['ulf_FilePath'] || @$file['ulf_FileName']) { $path = @$file['ulf_FilePath'] . @$file['ulf_FileName']; //add database media storage folder for relative paths //$filename = resolveFilePath($filename); //the same as in resolveFilePath($filename); however instead of consts uses source db folders if ($path && !file_exists($path)) { chdir($_src_HEURIST_FILESTORE_DIR); // relatively db root HEURIST_FILESTORE_DIR $fpath = realpath($path); if (file_exists($fpath)) { $filename = $fpath; } else { chdir($_src_HEURIST_FILES_DIR); // relatively file_uploads $fpath = realpath($path); if (file_exists($fpath)) { $filename = $fpath; } else { //special case to support absolute path on file server if (strpos($path, '/srv/HEURIST_FILESTORE/') === 0) { $fpath = str_replace('/srv/HEURIST_FILESTORE/', HEURIST_UPLOAD_ROOT, $path); if (file_exists($fpath)) { $filename = $fpath; } } } } } else { $filename = $path; } $need_copy = true; } else { if ($file['ulf_ExternalFileReference']) { $filename = $file['ulf_ExternalFileReference']; // post 18/11/11 proper file path and name $need_copy = false; $externalFile = true; } else { $filename = $_src_HEURIST_FILESTORE_DIR . $file['ulf_ID']; // pre 18/11/11 - bare numbers as names, just use file ID $need_copy = true; } } if (!$externalFile && !file_exists($filename)) { //check if this file is remote print "<div style='color:red;'>File {$filename} not found. Can't register file</div>"; ob_flush(); flush(); // flush to screen return null; } if (false && $externalFile) { //@todo - copy external file and save $data = loadRemoteURLContent($filename); if (!$data) { print "<div style='color:red;'>Error. Can't download {$filename}. Can't register URL</div>"; ob_flush(); flush(); // flush to screen return null; } } if ($need_copy) { $newfilename = HEURIST_FILES_DIR . $file['ulf_OrigFileName']; //if file in source upload dirtectiry copy it to destionation upload directory if (!copy($filename, $newfilename)) { print "<div style='color:red;'>Can't copy file {$fielname} to " . HEURIST_FILES_DIR . "</div>"; ob_flush(); flush(); // flush to screen return null; } $filename = $newfilename; } //returns new file id in dest database if ($externalFile) { $jsonData = json_encode(array('remoteURL' => $filename, 'ext' => $file['ulf_MimeExt'], 'params' => $file['ulf_Parameters'] ? $file['ulf_Parameters'] : null)); $ret = register_external($jsonData, null, false); } else { $ret = register_file($filename, null, false); } if (intval($ret) > 0) { return $ret; } else { print "<div style='color:red;'>Can't register file " . $filename . "</div>"; ob_flush(); flush(); // flush to screen return null; } }