3 # FILE: FormUI_Base.php 5 # Part of the Collection Workflow Integration System (CWIS) 6 # Copyright 2016 Edward Almasy and Internet Scout Research Group 7 # http://scout.wisc.edu/cwis/ 16 # ---- PUBLIC INTERFACE -------------------------------------------------- 48 # make sure parameters are legal and complete 49 $BooleanParams = array(
57 if (!isset($Params[
"Type"]))
59 $ErrMsgs[] =
"Type missing for form field ".$FieldName.
".";
61 elseif (($Params[
"Type"] == self::FTYPE_OPTION)
62 && !isset($Params[
"Options"]))
64 $ErrMsgs[] =
"Option values missing for form field ".$FieldName.
".";
66 if (!isset($Params[
"Label"]))
68 $ErrMsgs[] =
"Label missing for form field ".$FieldName.
".";
70 if (isset($Params[
"ValidateFunction"])
71 && !is_callable($Params[
"ValidateFunction"]))
73 $ErrMsgs[] =
"Uncallable validation function for form field " 76 if (isset($Params[
"InsertIntoField"])
79 $ErrMsgs[] =
"Unknown insertion field (".$Params[
"InsertIntoField"]
80 .
") found for form field ".$FieldName.
".";
82 foreach ($BooleanParams as $ParamName)
84 if (!isset($Params[$ParamName]))
92 $ErrMsgString = implode(
" ", $ErrMsgs);
93 throw new InvalidArgumentException($ErrMsgString);
96 # save form parameters and values 99 $this->UniqueKey = $UniqueKey;
107 abstract public function DisplayFormTable($TableId = NULL, $TableStyle = NULL);
115 public static function LogError($Msg, $Field = NULL)
117 self::$ErrorMessages[$Field][] = $Msg;
128 return self::$ErrorMessages;
139 if ($Field === FALSE)
141 return count(self::$ErrorMessages) ? TRUE : FALSE;
145 return isset(self::$ErrorMessages[$Field]) ? TRUE : FALSE;
155 if ($Field === FALSE)
157 self::$ErrorMessages = array();
161 unset(self::$ErrorMessages[$Field]);
174 # retrieve field values 179 foreach ($this->FieldParams as $Name => $Params)
182 if ($Params[
"Type"] == self::FTYPE_HEADING) {
continue; }
184 # determine if field has a value set 185 switch ($Params[
"Type"])
187 case self::FTYPE_SEARCHPARAMS:
188 $IsEmpty = !$Values[$Name]->ParameterCount();
191 case self::FTYPE_PRIVILEGES:
192 $IsEmpty = !$Values[$Name]->ComparisonCount();
196 if (is_array($Values[$Name]))
198 $IsEmpty = !count($Values[$Name]);
202 $IsEmpty = !strlen(trim($Values[$Name]));
207 # if field has validation function 208 if (isset($Params[
"ValidateFunction"]))
210 # swap in our object if this is one of our methods 211 $VFunc = $Params[
"ValidateFunction"];
212 if (is_array($VFunc) && ($VFunc[0] ==
"FormUI"))
217 # call validation function for value 218 $Args = array_merge(array($Name, $Values[$Name], $Values),
219 $this->ExtraValidationParams);
220 $ErrMsg = call_user_func_array($VFunc, $Args);
221 if ($ErrMsg === FALSE)
223 throw new Exception(
"Calling validation function for" 224 .
" parameter \"".$Name.
"\" failed.");
227 # log any resulting error 228 if ($ErrMsg !== NULL)
230 self::LogError($ErrMsg, $Name);
235 # if field is required and empty 236 if ($IsEmpty && isset($Params[
"Required"]) && $Params[
"Required"])
238 # log error to indicate required value is missing 239 self::LogError(
"<i>".$Params[
"Label"].
"</i> is required.", $Name);
242 # else validate based on field type 245 switch ($Params[
"Type"])
247 case self::FTYPE_NUMBER:
248 # make sure value is within any specified range 249 if ((isset($Params[
"MinVal"])
250 && ($Values[$Name] < $Params[
"MinVal"]))
251 || (isset($Params[
"MaxVal"])
252 && ($Values[$Name] > $Params[
"MaxVal"])))
254 if (!isset($Params[
"MaxVal"]))
256 self::LogError(
"<i>".$Params[
"Label"].
"</i> must be " 257 .$Params[
"MinVal"].
" or greater.", $Name);
259 elseif (!isset($Params[
"MinVal"]))
261 self::LogError(
"<i>".$Params[
"Label"].
"</i> must be " 262 .$Params[
"MaxVal"].
" or less.", $Name);
266 self::LogError(
"<i>".$Params[
"Label"].
"</i> must be" 267 .
" in the range ".$Params[
"MinVal"]
268 .
" to ".$Params[
"MaxVal"].
".", $Name);
274 case self::FTYPE_URL:
275 # make sure URL entered looks valid 276 if (!$IsEmpty && (filter_var(
277 $Values[$Name], FILTER_VALIDATE_URL) === FALSE))
279 self::LogError(
"Value \"".$Values[$Name]
280 .
"\" does not appear to be a valid URL for <i>" 281 .$Params[
"Label"].
"</i>.", $Name);
286 case self::FTYPE_USER:
287 # make sure user name entered is valid 289 if (!$UFactory->UserNameExists($Values[$Name]))
291 self::LogError(
"User name \"".$Values[$Name]
292 .
"\" not found for <i>" 293 .$Params[
"Label"].
"</i>.", $Name);
301 # report number of fields with invalid values found to caller 312 $this->ExtraValidationParams = func_get_args();
322 # for each form field 323 $NewSettings = array();
324 foreach ($this->FieldParams as $Name => $Params)
327 if ($Params[
"Type"] == self::FTYPE_HEADING) {
continue; }
329 # determine form field name (matches mechanism in HTML) 331 ($Params[
"Type"] != self::FTYPE_PRIVILEGES));
333 # assume the value will not change 334 $DidValueChange = FALSE;
335 $OldValue = isset($this->FieldValues[$Name])
336 ? $this->FieldValues[$Name]
337 : (isset($Params[
"Value"]) ? $Params[
"Value"] : NULL);
338 $NewSettings[$Name] = $OldValue;
340 # retrieve value based on configuration parameter type 341 switch ($Params[
"Type"])
343 case self::FTYPE_FLAG:
344 # if radio buttons were used 345 if (array_key_exists(
"OnLabel", $Params)
346 && array_key_exists(
"OffLabel", $Params))
348 if (isset($_POST[$FieldName]))
350 $NewValue = ($_POST[$FieldName] ==
"1") ? TRUE : FALSE;
352 # flag that the values changed if they did 353 $DidValueChange = self::DidValueChange(
354 $OldValue, $NewValue);
356 $NewSettings[$Name] = $NewValue;
359 # else checkbox was used 362 $NewValue = isset($_POST[$FieldName]) ? TRUE : FALSE;
364 # flag that the values changed if they did 365 $DidValueChange = self::DidValueChange($OldValue, $NewValue);
367 $NewSettings[$Name] = $NewValue;
371 case self::FTYPE_OPTION:
372 $NewValue = GetArrayValue($_POST, $FieldName, array());
374 # flag that the values changed if they did 375 $DidValueChange = self::DidValueChange($OldValue, $NewValue);
377 $NewSettings[$Name] = $NewValue;
380 case self::FTYPE_METADATAFIELD:
381 $NewValue = GetArrayValue($_POST, $FieldName, array());
382 if ($NewValue ==
"-1") { $NewValue = array(); }
384 # flag that the values changed if they did 385 $DidValueChange = self::DidValueChange($OldValue, $NewValue);
387 $NewSettings[$Name] = $NewValue;
390 case self::FTYPE_PRIVILEGES:
391 $Schemas = GetArrayValue($Params,
"Schemas");
392 $MFields = GetArrayValue($Params,
"MetadataFields", array());
394 $NewValues = $PEditor->GetPrivilegeSetsFromForm();
395 $NewValue = $NewValues[$FieldName];
396 $DidValueChange = self::DidValueChange($OldValue, $NewValue);
397 $NewSettings[$Name] = $NewValue;
400 case self::FTYPE_SEARCHPARAMS:
402 $NewValue = $SPEditor->GetValuesFromFormData();
403 $DidValueChange = self::DidValueChange($OldValue, $NewValue);
404 $NewSettings[$Name] = $NewValue;
407 case self::FTYPE_FILE:
408 $NewSettings[$Name] = GetArrayValue(
409 $_POST, $FieldName.
"_ID", array());
410 foreach ($NewSettings[$Name] as $Index => $FileId)
412 if ($FileId == self::NO_VALUE_FOR_FIELD)
414 unset($NewSettings[$Name][$Index]);
419 case self::FTYPE_IMAGE:
420 $NewSettings[$Name] = GetArrayValue(
421 $_POST, $FieldName.
"_ID", array());
422 foreach ($NewSettings[$Name] as $Index => $ImageId)
424 if ($ImageId == self::NO_VALUE_FOR_FIELD)
426 unset($NewSettings[$Name][$Index]);
428 if (isset($_POST[$FieldName.
"_AltText_".$ImageId]))
431 $Image->AltText($_POST[$FieldName.
"_AltText_".$ImageId]);
437 if (isset($_POST[$FieldName]))
439 $NewValue = $_POST[$FieldName];
441 # flag that the values changed if they did 442 $DidValueChange = self::DidValueChange($OldValue, $NewValue);
444 $NewSettings[$Name] = $NewValue;
449 # if value changed and there is an event to signal for changes 450 if ($DidValueChange && $this->SettingChangeEventName)
452 # set info about changed value in event parameters if appropriate 454 foreach ($EventParams as $ParamName => $ParamValue)
459 $EventParams[$ParamName] = $Name;
463 $EventParams[$ParamName] = $OldValue;
467 $EventParams[$ParamName] = $NewValue;
473 $GLOBALS[
"AF"]->SignalEvent(
474 $this->SettingChangeEventName, $EventParams);
478 # return updated setting values to caller 489 # get base form field name 490 $FieldType = $this->FieldParams[$FieldName][
"Type"];
492 ($FieldType != self::FTYPE_PRIVILEGES));
494 # get fallback value for field (in case no value from form) 495 if (isset($this->FieldValues[$FieldName]))
497 $Value = $this->FieldValues[$FieldName];
499 elseif (isset($this->FieldParams[$FieldName][
"Value"]))
501 $Value = self::LoadValue($FieldType,
502 $this->FieldParams[$FieldName][
"Value"]);
504 elseif (isset($this->FieldParams[$FieldName][
"Default"]))
506 $Value = self::LoadValue($FieldType,
507 $this->FieldParams[$FieldName][
"Default"]);
511 $Value = self::LoadValue($FieldType, NULL);
516 case self::FTYPE_FILE:
517 case self::FTYPE_IMAGE:
518 # get name of image ID form field 519 $FileIdFieldName = $FormFieldName.
"_ID";
521 # use an updated value for this field if available 522 if (isset($this->HiddenFields[$FileIdFieldName]))
524 $Value = $this->HiddenFields[$FileIdFieldName];
526 # else use a value from form if available 527 elseif (isset($_POST[$FileIdFieldName]))
529 $Value = $_POST[$FileIdFieldName];
532 # add in any previously-set extra values 533 if (isset($this->ExtraValues[$FileIdFieldName])
534 && count($this->ExtraValues[$FileIdFieldName]))
536 if (!is_array($Value))
538 $Value = array($Value);
540 $Value = array_merge($Value,
541 $this->ExtraValues[$FileIdFieldName]);
545 case self::FTYPE_SEARCHPARAMS:
546 # use incoming form value if available 547 if (isset($_POST[$FormFieldName]))
549 # use incoming form value 551 $Value = $SPEditor->GetValuesFromFormData();
555 case self::FTYPE_PRIVILEGES:
556 # use incoming form value if available 557 $Schemas = GetArrayValue(
558 $this->FieldParams[$FieldName],
"Schemas");
559 $MFields = GetArrayValue(
560 $this->FieldParams[$FieldName],
"MetadataFields", array());
562 $PSet = $PEditor->GetPrivilegeSetFromForm($FormFieldName);
565 # use incoming form value 571 # use incoming form value if available 572 if (isset($_POST[$FormFieldName]))
574 # use incoming form value 575 $Value = $_POST[$FormFieldName];
580 # return value found to caller 589 # for each form field 590 foreach ($this->FieldParams as $FieldName =>
$FieldParams)
592 # move on to next field if this field does not allow uploads 599 # move on to next field if this field does not have an uploaded file 601 if (!isset($_FILES[$FormFieldName][
"name"]))
605 $UploadedFileName = $_FILES[$FormFieldName][
"name"];
606 if (!strlen($UploadedFileName))
611 # create temp copy of file with correct name 612 $TmpFile =
"tmp/".$UploadedFileName;
613 $CopyResult = copy($_FILES[$FormFieldName][
"tmp_name"], $TmpFile);
617 case self::FTYPE_FILE:
618 # create new file object from uploaded file 621 # check for errors during file object creation 622 if (!is_object($File))
628 .$UploadedFileName.
" was empty" 629 .
" (zero length).", $FieldName);
633 $this->
LogError(
"Error encountered with" 635 .$UploadedFileName.
" (" 636 .$File.
").", $FieldName);
643 # add file ID to extra values 644 $this->ExtraValues[$FormFieldName.
"_ID"][] = $File->Id();
648 case self::FTYPE_IMAGE:
649 # create new image object from uploaded file 658 # check for errors during image object creation 659 if ($Image->Status() !=
AI_OKAY)
661 switch ($Image->Status())
664 $this->
LogError(
"Unknown format for image file " 665 .$UploadedFileName.
".", $FieldName);
669 $this->
LogError(
"Unsupported format for image file " 670 .$UploadedFileName.
" (" 671 .$Image->Format().
").", $FieldName);
675 $this->
LogError(
"Error encountered when" 676 .
" processing uploaded image file " 677 .$UploadedFileName.
".", $FieldName);
684 # set image object alternate text 685 $Image->AltText($_POST[$FormFieldName.
"_AltText_NEW"]);
687 # add image ID to extra values 688 $this->ExtraValues[$FormFieldName.
"_ID"][] = $Image->Id();
700 # if image ID to delete was supplied 702 $IncomingValue = GetFormValue($DeleteFieldName);
703 if (is_numeric($IncomingValue)
704 || (is_array($IncomingValue) && count($IncomingValue)))
706 # retrieve ID of image 707 $ImageId = is_array($IncomingValue)
708 ? array_shift($IncomingValue)
711 # add ID to deleted images list 712 if (is_numeric($ImageId))
714 $this->DeletedImages[] = $ImageId;
718 # if file ID to delete was supplied 720 $IncomingValue = GetFormValue($DeleteFieldName);
721 if (is_numeric($IncomingValue)
722 || (is_array($IncomingValue) && count($IncomingValue)))
724 # retrieve ID of file 725 $FileId = is_array($IncomingValue)
726 ? array_shift($IncomingValue)
729 # add ID to deleted files list 730 if (is_numeric($FileId))
732 $this->DeletedFiles[] = $FileId;
750 $this->SettingChangeEventName = $EventName;
751 $this->SettingChangeEventParams = $EventParams;
762 # didn't change if they are identical 763 if ($OldValue === $NewValue)
768 # need special cases from this point because PHP returns some odd results 769 # when performing loose equality comparisons: 770 # http://php.net/manual/en/types.comparisons.php#types.comparisions-loose 772 # consider NULL and an empty string to be the same. this is in case a field 773 # is currently set to NULL and receives an empty value from the form. 774 # $_POST values are always strings 775 if ((is_null($OldValue) && is_string($NewValue) && !strlen($NewValue))
776 || (is_null($NewValue) && is_string($OldValue) && !strlen($OldValue)))
781 # if they both appear to be numbers and are equal 782 if (is_numeric($OldValue) && is_numeric($NewValue) && $OldValue == $NewValue)
788 if (($OldValue === TRUE && ($NewValue === 1 || $NewValue ===
"1"))
789 || ($NewValue === TRUE && ($OldValue === 1 || $OldValue ===
"1")))
795 if (($OldValue === FALSE && ($NewValue === 0 || $NewValue ===
"0"))
796 || ($NewValue === FALSE && ($OldValue === 0 || $OldValue ===
"0")))
802 if (is_array($OldValue) && is_array($NewValue))
804 # they certainly changed if the counts are different 805 if (count($OldValue) != count($NewValue))
810 # the algorithm for associative arrays is slightly different from 811 # sequential ones. the values for associative arrays must match the keys 812 if (count(array_filter(array_keys($OldValue),
"is_string")))
814 foreach ($OldValue as $Key => $Value)
816 # it changed if the keys don't match 817 if (!array_key_exists($Key, $NewValue))
822 # the arrays changed if a value changed 823 if (self::DidValueChange($Value, $NewValue[$Key]))
830 # sequential values don't have to have the same keys, just the same 834 # sort them so all the values match up if they're equal 838 foreach ($OldValue as $Key => $Value)
840 # the arrays changed if a value changed 841 if (self::DidValueChange($Value, $NewValue[$Key]))
848 # the arrays are equal 866 case self::FTYPE_FILE:
867 case self::FTYPE_IMAGE:
868 $Value = ($Data === NULL) ? array() : $Data;
871 case self::FTYPE_PRIVILEGES:
876 case self::FTYPE_SEARCHPARAMS:
906 if (trim($Value) ==
"") {
continue; }
907 if (filter_var($Value, FILTER_VALIDATE_EMAIL) === FALSE)
909 return "The value for <i>".$this->FieldParams[$FieldName][
"Label"]
910 .
"</i> does not appear to be a valid email address.";
933 if (trim($Value) ==
"") {
continue; }
934 if (filter_var($Value, FILTER_VALIDATE_URL) === FALSE)
936 return "The value for <i>".$this->FieldParams[$FieldName][
"Label"]
937 .
"</i> does not appear to be a valid URL.";
961 if (trim($Value) ==
"") {
continue; }
962 if (gethostbyname($Value) === $Value)
964 return "The value for <i>".$this->FieldParams[$FieldName][
"Label"]
965 .
"</i> does not appear to be a valid host name.";
972 # ---- PRIVATE INTERFACE ------------------------------------------------- 1006 return ($IncludePrefix ?
"F_" :
"")
1007 .($this->UniqueKey ? $this->UniqueKey.
"_" :
"")
1008 .preg_replace(
"/[^a-zA-Z0-9]/",
"", $FieldName);
1017 if (count($this->HiddenFields))
1019 foreach ($this->HiddenFields as $FieldName => $Value)
1021 if (is_array($Value))
1023 foreach ($Value as $EachValue)
1025 $Html .=
'<input type="hidden" name="'.$FieldName
1026 .
'[]" value="'.htmlspecialchars($EachValue).
'">';
1031 $Html .=
'<input type="hidden" name="'.$FieldName
1032 .
'[]" id="'.$FieldName.
'" value="' 1033 .htmlspecialchars($Value).
'">';
const FILESTAT_ZEROLENGTH
Set of parameters used to perform a search.
static Create($SourceFile, $DesiredFileName=NULL)
Create a new File object using an existing file.
User interface element for editing PrivilegeSets.
Set of privileges used to access resource information or other parts of the system.
CWIS-specific user factory class.
Encapsulates a full-size, preview, and thumbnail image.
Class to create a user interface for editing SearchParameterSets.
const AI_UNSUPPORTEDFORMAT