$value) { $fieldName = substr($value, 2, strlen($value) - 3); $fieldValue = null; if (isset($fieldValues[$fieldName])) { $targetFieldValue = isset($fieldValues[$fieldName]['value']) ? $fieldValues[$fieldName]['value'] : $fieldValues[$fieldName]; if ('array' === gettype($targetFieldValue) || 'object' === gettype($targetFieldValue)) { foreach (self::stripMetaSubfields((array) $targetFieldValue) as $singleTargetVal) { if (isset($fieldValue)) { if (is_numeric($fieldValue) && is_numeric($singleTargetVal)) { $fieldValue = $fieldValue + $singleTargetVal; } else { $fieldValue = "$fieldValue, $singleTargetVal"; } } else { $fieldValue = $singleTargetVal; } } // $fieldValue = wp_json_encode($targetFieldValue); } else { $fieldValue = strval($targetFieldValue); } // Neutralize shortcodes in low-trust submitted values before they are merged into a if ($stripShortcodesFromValues && is_string($fieldValue)) { $fieldValue = strip_shortcodes($fieldValue); } $stringToReplaceField = str_replace($value, $fieldValue, $stringToReplaceField); } else { $stringToReplaceField = str_replace($value, '', $stringToReplaceField); } } // check if the string is a function like : "${_bf_calc(${b27-5}*10)}" // TO DO: Implement the function properly // if (self::isFunction($stringToReplaceField)) { // $functionName = self::getFunctionName($stringToReplaceField); // switch ($functionName) { // case '_bf_calc': // return self::getFunctionParameter($stringToReplaceField); // case '_bf_count': // return self::getCountValue($stringToReplaceField); // default: // return 0; // } // } return $stringToReplaceField; } public static function replaceBackBtnWithPrevPageUrl($stringToReplaceField) { $prevPageUrl = isset($_SERVER['HTTP_REFERER']) ? esc_url_raw(wp_unslash($_SERVER['HTTP_REFERER'])) : home_url(); preg_match_all('/\$?\{back_to_view\}/', $stringToReplaceField, $matches); $matched = $matches[0]; if (empty($matched) || !$prevPageUrl) { return $stringToReplaceField; } foreach ($matched as $m) { $stringToReplaceField = str_replace($m, $prevPageUrl, $stringToReplaceField); } return $stringToReplaceField; } /** * Summary of getCountValue - get the count value from the function string "${_bf_count(item-1, item-2)}" => 2 * * @param string $functionString * @return int */ private static function getCountValue(string $functionString): int { $options = self::getFunctionParameter($functionString); $option = explode(',', $options); return count($option); } /** * Summary of getFunctionParameter - get the function parameter from the function string "${_bf_calc(2*10)}" => 2*10 * * @param string $functionString * @return string */ private static function getFunctionParameter(string $functionString): string { $regexPattern = '/\(([^)]*)\)/'; preg_match($regexPattern, $functionString, $matches); return $matches[1]; } /** * Summary of isFunction - check if the string is a function "${_bf_calc(${b27-5}*10)}" or not "${_bf_date}" * * @param string $functionString * @return bool true if the string is a function else false */ private static function isFunction(string $functionString): bool { $regexPattern = '/\([^)]*\)/'; return preg_match($regexPattern, $functionString); } /** * Summary of getFunctionName - get the function name from the function string "${_bf_calc(${b27-5}*10)}" => _bf_calc * * @param string $functionString * @return string */ private static function getFunctionName(string $functionString): string { $regexPattern = '/\b([a-zA-Z_][a-zA-Z0-9_]*)\(/'; preg_match($regexPattern, $functionString, $matches); return $matches[1]; } public static function validateMailArry($emailAddresses, $fieldValues) { if (!is_array($emailAddresses)) { return [FieldValueHandler::replaceFieldWithValue($emailAddresses, $fieldValues)]; } foreach ($emailAddresses as $key => $email) { if (!is_email($email)) { $email = FieldValueHandler::replaceFieldWithValue($email, $fieldValues); if (is_email($email)) { $emailAddresses[$key] = $email; } } } return $emailAddresses; } public static function replaceSmartTagWithValue($contentWithSmartTag) { $fieldPattern = '/(\${_[^{]*?)(?=\})}/'; $matchPattern = preg_match_all($fieldPattern, $contentWithSmartTag, $matchedField); if (!$matchPattern) { return $contentWithSmartTag; } $ajaxRequest = false; // Read-only action name check for routing; CSRF verified upstream in the form submission flow via verifySubmissionNonce(). if (isset($_REQUEST['action']) && 'bitforms_trigger_workflow' === sanitize_text_field(wp_unslash($_REQUEST['action']))) { $ajaxRequest = true; } foreach (array_unique($matchedField[0]) as $value) { $fieldName = trim(substr($value, 2, strlen($value) - 3)); $matches = preg_match('/\("*([^\)]+"*)\)/', $value, $matchCustomFormat); $customValue = ''; if ($matches) { $removeQuote = ["'", '"']; $customValue = str_replace($removeQuote, '', $matchCustomFormat[1]); $fieldName = str_replace($matchCustomFormat[0], '', $fieldName); } $tagFieldValues = SmartTags::getSmartTagValue($fieldName, $ajaxRequest, $customValue); $contentWithSmartTag = str_replace($value, $tagFieldValues, $contentWithSmartTag); } return $contentWithSmartTag; } public static function isEmpty($val) { if (empty($val) && !in_array($val, ['0', 0, 0.0], true)) { return true; } return false; } public static function formatFieldValueForMail($fields, $fieldValues = []) { $formattedFldValues = $fieldValues; $file_upload_types = Helpers::$file_upload_types; $repeated_array_type_data_fields = Helpers::$repeated_array_type_data_fields; foreach ($fields as $fldKey => $fldData) { if (in_array($fldData->typ, $file_upload_types)) { continue; } if (is_array($fieldValues) && array_key_exists($fldKey, $fieldValues)) { $value = $fieldValues[$fldKey]; // if (is_array($value)) { // $formattedFldValues[$fldKey] = htmlspecialchars(implode(', ', $value)); // } else { // $formattedFldValues[$fldKey] = htmlspecialchars($value); // } // TODO: this code are temporary commented, need to change and remove the comment // if (is_array($value)) { // $arrValue = ''; // foreach ($value as $v) { // if (is_array($v)) { // foreach ($v as $k1 => $v1) { // if (array_key_exists($k1, $repeaterFieldKey)) { // $oldValue = $repeaterFieldKey[$k1]; // if (is_array($v1) && in_array($fields->{$k1}->typ, $repeated_array_type_data_fields)) { // $newValues = '[' . implode(', ', $v1) . '] '; // if (!preg_match('/\[.*\]/', $oldValue)) { // $oldValue = '[' . $oldValue . '] '; // } // } else { // $newValues = $v1; // } // $repeaterFieldKey[$k1] = $oldValue . ', ' . $newValues; // } else { // if (!empty($v1) && is_array($v1)) { // $repeaterFieldKey[$k1] = htmlspecialchars(implode(', ', $v1)); // } else { // $repeaterFieldKey[$k1] = htmlspecialchars($v1); // } // } // } // } else { // $arrValue .= $v . ', '; // } // } // $formattedFldValues[$fldKey] = htmlspecialchars(rtrim($arrValue, ', ')); // $arrValue = ''; // } else { // $formattedFldValues[$fldKey] = htmlspecialchars($value); // } if ('textarea' === $fldData->typ) { $formattedFldValues[$fldKey] = nl2br(htmlspecialchars($value)); } if ('date' === $fldData->typ && !empty($value)) { $formattedFldValues[$fldKey] = date_i18n(get_option('date_format'), strtotime(htmlspecialchars($value))); } } } $merge_values = array_merge($fieldValues, $formattedFldValues); // $merge_values = array_merge($merge_values, $repeaterFieldKey); return $merge_values; } public static function changeHrefPathInHTMLString($html_body, $path) { if (empty($html_body) || empty($path)) { return $html_body; } return preg_replace_callback( '/]*href=[\'"]([^\'"]+)[\'"][^>]*>/i', function ($matches) use ($path) { $href = $matches[1]; if (filter_var($href, FILTER_VALIDATE_URL)) { return $matches[0]; } if (preg_match('/^(mailto:|tel:|javascript:|#)/i', $href)) { return $matches[0]; } if (preg_match('/\$?\{back_to_view\}/', $matches[0])) { return $matches[0]; } $fullPath = rtrim($path, '/') . '/' . ltrim($href, '/'); return str_replace( $href, htmlspecialchars($fullPath, ENT_QUOTES), $matches[0] ); }, $html_body ); } public static function changeImagePathInHTMLString($html_body, $path) { if (empty($html_body) || empty($path)) { return $html_body; } $allowedMimeTypes = [ 'jpg' => ['image/jpeg', 'image/pjpeg'], 'jpeg' => ['image/jpeg', 'image/pjpeg'], 'png' => ['image/png'], 'svg' => ['image/svg+xml'] ]; return preg_replace_callback( '/]*src=[\'"]([^\'"]*)[\'"][^>]*>/i', function ($matches) use ($path, $allowedMimeTypes) { $src = $matches[1]; // Already-embedded inline images (cid:) must be left untouched. if (0 === stripos($src, 'cid:')) { return $matches[0]; } if (filter_var($src, FILTER_VALIDATE_URL)) { return $matches[0]; } if (!trim($src)) { return ''; } $fullPath = rtrim($path, '/') . '/' . ltrim($src, '/'); $extension = strtolower(pathinfo($fullPath, PATHINFO_EXTENSION)); if (!preg_match('/^(http|https):\/\//', $fullPath)) { if (!file_exists($fullPath) || !isset($allowedMimeTypes[$extension])) { Log::debug_log([ 'status' => 'error', 'code' => 'file_not_found', 'message' => "File not found or unsupported file type: $fullPath", ]); return ''; } else { Log::debug_log([ 'status' => 'success', 'code' => 'file_found', 'message' => "File Found => location: {$fullPath}" ]); } $mimeType = mime_content_type($fullPath); if (!in_array($mimeType, $allowedMimeTypes[$extension], true)) { Log::debug_log([ 'status' => 'error', 'code' => 'unsupported_file_type', 'message' => "Unsupported file type: $mimeType for file: $fullPath", ]); return ''; } } return str_replace($src, htmlspecialchars($fullPath, ENT_QUOTES), $matches[0]); }, $html_body ); } public static function sortValueBasedOnLayout($formId, $fieldValues) { $formManager = FormManager::getInstance($formId); $layout = $formManager->getFormLayout(); $formLayout = $formManager->getFlatenFormLayout(); // returns all layouts (lg, md, sm) $fieldKeyOrderbasedOnLayout = array_map(function ($fld) { return $fld->i; }, $formLayout->lg); $ordered = []; foreach ($fieldKeyOrderbasedOnLayout as $key) { if (array_key_exists($key, $fieldValues)) { $ordered[$key] = $fieldValues[$key]; } } foreach ($fieldValues as $k=>$v) { if (!array_key_exists($k, $fieldKeyOrderbasedOnLayout)) { $ordered[$k] = $fieldValues[$k]; } } return $ordered; } public static function replaceValueOfBf_all_data($stringToReplaceField, $fieldValues, $formId) { // $pattern = '/\$\{bf_all_data\}/'; // Corrected escaping $pattern = '/\$\{bf_all_data(?:\.onlyValues)?\}/'; // Corrected escaping preg_match_all($pattern, $stringToReplaceField, $matches); $matchesArray = $matches[0] ?? []; if (count($matchesArray) > 0) { $formManager = FormManager::getInstance($formId); $formFields = $formManager->getFields(); $orderedFormFields = $formManager->getFieldsBasedOnLayout(); // ordered form fields based on layout(lg) order foreach ($matchesArray as $match) { switch ($match) { case '${bf_all_data}': $fieldValues = self::bindFormData($orderedFormFields, $fieldValues, $formId); $table = self::generateTable($fieldValues, $orderedFormFields); $stringToReplaceField = str_replace('${bf_all_data}', $table, $stringToReplaceField); break; case '${bf_all_data.onlyValues}': $fieldValues = self::bindFormData($orderedFormFields, $fieldValues, $formId, true); $table = self::generateTable($fieldValues, $orderedFormFields); $stringToReplaceField = str_replace('${bf_all_data.onlyValues}', $table, $stringToReplaceField); break; default: Log::debug_log([ 'status' => 'error', 'code' => 'unknown_placeholder', 'message' => "Unknown placeholder: $match", ]); break; } } } return $stringToReplaceField; } /** * Ensures an tag with a style attribute exists in the input. * * Behavior: * - If the input is just an image filename (e.g., "1.png"), returns a complete tag with the default style. * - If the input is HTML with tags: * - If any has a style, returns the HTML as-is. * - If exists without style, adds the default style to the first one found. * - If no tag or image file is found, returns the input unchanged. * * @param string $input Image filename or HTML string. * @param string $defaultStyle Optional. The CSS style to apply if missing. Default: 'max-width: 100%; height: auto;'. * * @return string Modified HTML string with styled tag if needed. */ private static function ensureImgWithStyle($input, $defaultStyle = 'max-width: 100%; height: auto;') { $imgTagWithStylePattern = '/]*\bstyle\s*=\s*["\'][^"\']*["\'][^>]*>/i'; $imgTagPattern = '/]*>/i'; $filePattern = '/\.(jpg|jpeg|png|gif|webp)$/i'; if (preg_match($filePattern, trim($input)) && !preg_match('/'; } if (preg_match($imgTagWithStylePattern, $input)) { // already has style, return as is return $input; } elseif (preg_match($imgTagPattern, $input, $match)) { // without style, add style $updatedImg = preg_replace('//i', '', $match[0]); return str_replace($match[0], $updatedImg, $input); } else { // No tag found, return input return $input; } } private static function orderRepeaterData($repeaterFldKey, $repeaterData, $formId) { if (!$formId) { return $repeaterData; } $formManager = FormManager::getInstance($formId); $nestedLayout = $formManager->getFormNestedLayout(); $repeaterLayout = $nestedLayout->{$repeaterFldKey}->lg; $orderedFldKey = array_map(function ($fld) { return $fld->i; }, $repeaterLayout); $orderedRepeaterData = []; foreach ($repeaterData as $rptr) { $orderedFlds = []; foreach ($orderedFldKey as $k) { if (array_key_exists($k, $rptr)) { $orderedFlds[$k] = $rptr[$k]; } } foreach ($rptr as $ky => $v) { if (!array_key_exists($ky, $orderedFldKey)) { $orderedFlds[$ky] = $v; } } $orderedRepeaterData[] = $orderedFlds; } return $orderedRepeaterData; } private static function bindFormData($formFields, $formData, $formId, $isOnlyValues = false) { $entryID = isset($formData['entry_id']) ? $formData['entry_id'] : null; return array_reduce(array_keys($formFields), function ($filteredData, $key) use ($formFields, $formData, $isOnlyValues, $formId) { $field = $formFields[$key]; $fieldNewData = $filteredData; $ignoreFields = ['button', 'recaptcha', 'html', 'divider', 'spacer', 'section', 'turnstile', 'hcaptcha', 'image']; $arrayValueFldType = ['check', 'select', 'image-select']; if (in_array($field['type'], $ignoreFields)) { return $fieldNewData; } // Skip processing for hidden or empty fields only when $isOnlyValues is true if ($isOnlyValues) { // Check if the value is strictly an empty string or null, but allow 0 if (!isset($formData[$key]) || '' === $formData[$key] || null === $formData[$key]) { return $fieldNewData; } if (isset($field['valid']['hide']) && $field['valid']['hide']) { return $fieldNewData; } } if (isset($formData[$key]) && !array_key_exists('parentFieldKey', $field)) { if ('repeater' === $field['type']) { $repeater_data = is_string($formData[$key]) ? json_decode($formData[$key], true) : $formData[$key]; // ordering repeater field according to nested repeater layout $repeater_data = self::orderRepeaterData($key, $repeater_data, $formId); if ($isOnlyValues) { $repeater_data = array_filter($repeater_data, function ($sub) { return array_filter($sub, fn ($value) => '' !== $value); }); } $fieldNewData[$key] = $repeater_data; } elseif ('signature' === $field['type']) { if ('signature-failed.png' !== $formData[$key]) { $file_path = strpos($formData[$key], '/') ? $formData[$key] : $formData[$key]; $newPath = $file_path; $fieldNewData[$key] = self::ensureImgWithStyle($newPath, 'max-width: 100%; height: auto;'); } } elseif (in_array($field['type'], $arrayValueFldType)) { $v = is_string($formData[$key]) ? json_decode($formData[$key], true) : $formData[$key]; $fieldNewData[$key] = $v && is_array($v) ? implode(', ', $v) : $formData[$key]; } else { $fieldNewData[$key] = $formData[$key]; } } return $fieldNewData; }, []); } private static function generateTable($fieldValues, $formFields) { if (empty($fieldValues)) { Log::debug_log([ 'status' => 'error', 'code' => 'no_fields_found', 'type' => 'bf_all_data', 'message' => 'No fields found for bf_all_data', 'fields' => $fieldValues, 'formFields' => $formFields, ]); return '

No data available.

'; } $table = ""; foreach ($fieldValues as $fk => $value) { $value = self::decodeIfJson($value); $fieldName = self::getLabel($formFields, $fk) ?? $fk; $fieldType = $formFields[$fk]['type']; $table .= "'; } $table .= '
{$fieldName} "; if (is_array($value)) { if ('repeater' === $fieldType) { $table .= ""; $table .= ''; foreach (array_keys($value[0]) as $subKey) { $subLabel = self::getLabel($formFields, $subKey) ?? $subKey; $table .= "'; } $table .= ''; foreach ($value as $row) { $table .= ''; foreach ($row as $subKey => $subValue) { $subFieldType = self::getFldType($subKey, $formFields); if (is_array($subValue)) { if (self::isCompositeFieldType($subFieldType)) { $subValue = self::joinCompositeFieldValue($subValue, $subFieldType); } else { $subValue = self::unorderedAnchorListMarkup($subValue); } // $subValue = implode(', ', array_map(function ($v) { // if (self::isFileTypeValue($v)) { // return self::anchorMarkup($v); // // if (self::isImageTypeValue($v)) { // // return "{$v}"; // // } else { // // return "{$v}"; // // } // } else { // return $v; // } // }, $subValue)); } else { if (self::isFileTypeValue($subValue)) { if ('signature' === $subFieldType) { if ('signature-failed.png' === $subValue) { $subValue = ''; } else { $subValue = "{$subValue}"; } } } else { $subValue = $subValue; } } $table .= "'; } $table .= ''; } $table .= '
" . $subLabel . '
" . $subValue . '
'; } elseif ('file-up' === $fieldType || 'advanced-file-up' === $fieldType) { if (is_array($value)) { $table .= self::unorderedAnchorListMarkup($value); } } elseif (self::isCompositeFieldType($fieldType)) { $table .= self::joinCompositeFieldValue($value, $fieldType); } elseif ('signature' === $fieldType) { if ('signature-failed.png' === $subValue) { $table .= ''; } else { $table .= self::imgMarkup($value); } } } else { $table .= $value; } $table .= '
'; return $table; } private static function unorderedAnchorListMarkup($list) { $ul = "
    "; foreach ($list as $v) { $ul .= '
  • ' . self::anchorMarkup($v) . '
  • '; } $ul .= '
'; return $ul; } private static function imgMarkup($filename) { return "{$filename}"; } private static function anchorMarkup($filename) { return "{$filename}"; } public static function replaceRepeaterFieldValue($stringToReplaceField, $fieldValues, $formID) { if (!is_string($stringToReplaceField) || empty($stringToReplaceField)) { return $stringToReplaceField; // Return as-is if nothing to replace } $formManager = FormManager::getInstance($formID); $formFields = $formManager->getFieldsBasedOnLayout(); // ordered form fields based on layout(lg) order // Find all placeholders like ${field_key} example: ${b27-5} preg_match_all('/\$\{(b\d+-\d+)\}/', $stringToReplaceField, $matches); if (empty($matches[1])) { return $stringToReplaceField; } // Clean field data // $dataCleaning = self::removeEmptyValues($fieldValues); $flatFieldData = self::restructureRepeaterData($fieldValues, $formManager); // generate table for repeater fields foreach ($matches[1] as $fk) { $repeaterFieldKey = $fk; $fieldType = isset($formFields[$repeaterFieldKey]['type']) && !empty($formFields[$repeaterFieldKey]['type']) ? $formFields[$repeaterFieldKey]['type'] : null; if ('repeater' === $fieldType) { $repeaterMarkup = self::repeaterFieldTable($fieldValues[$repeaterFieldKey] ?? [], $formFields, $repeaterFieldKey); $stringToReplaceField = str_replace('${' . $fk . '}', $repeaterMarkup, $stringToReplaceField); } else { if ('signature' === $fieldType) { $stringToReplaceField = self::replaceImgTagForRepeatedSignature($stringToReplaceField, $flatFieldData[$repeaterFieldKey], $repeaterFieldKey); } $repeaterFieldData = self::safeFlatString( $flatFieldData[$repeaterFieldKey] ?? '', $fieldType, $repeaterFieldKey, $flatFieldData, $formFields ); $stringToReplaceField = str_replace('${' . $fk . '}', $repeaterFieldData, $stringToReplaceField); } } return $stringToReplaceField; } private static function replaceImgTagForRepeatedSignature($stringToReplaceField, $repeaterValue, $fldKey) { $data = self::decodeIfJson($repeaterValue); if (!is_string($stringToReplaceField) || empty($stringToReplaceField) || empty($fldKey)) { return $stringToReplaceField; } $pattern = '/]*src=[\'"]([^\'"]*' . preg_quote($fldKey, '/') . '[^\'"]*)[\'"][^>]*>/i'; if (!preg_match($pattern, $stringToReplaceField)) { return $stringToReplaceField; } $values = []; $appendValue = function ($value) use (&$values) { if (is_array($value)) { foreach ($value as $item) { if (is_string($item) && '' !== trim($item) && 'signature-failed.png' !== $item) { $values[] = $item; } } return; } if (is_string($value) && '' !== trim($value) && 'signature-failed.png' !== $value) { $values[] = $value; } }; $appendValue($data); if (empty($values)) { return preg_replace($pattern, '', $stringToReplaceField); } return preg_replace_callback($pattern, function ($matches) use ($values) { $imgTags = array_map(function ($value) use ($matches) { $src = htmlspecialchars($value, ENT_QUOTES); $alt = htmlspecialchars($value, ENT_QUOTES); $tag = $matches[0]; $tag = preg_replace('/\bsrc\s*=\s*([\'"])(.*?)\1/i', 'src="' . $src . '"', $tag); if (preg_match('/\balt\s*=\s*([\'"])(.*?)\1/i', $tag)) { $tag = preg_replace('/\balt\s*=\s*([\'"])(.*?)\1/i', 'alt="' . $alt . '"', $tag); } else { $tag = preg_replace('/ $topValue) { if ($formManagerInstance->isRepeaterField($topKey)) { $topValue = self::decodeIfJson($topValue); //assigning the converted value to repeater field $result[$topKey] = $topValue; // topvalue here is repeater field value; // entryIndex repeater field key , entry == repeater field value foreach ($topValue as $entryIndex => $entry) { if (!is_array($entry)) { continue; } foreach ($entry as $subKey => $subValue) { if (!isset($result[$subKey]) || !is_array($result[$subKey])) { $result[$subKey] = []; } // Handle nested arrays within entries $result[$subKey][$entryIndex] = $subValue; } } } } return $result; } /** * Return decoded data if incoming data is stringified and if it's a plain string (e.g "John Doe") it returns the plain string * * @param mixed $data * @return mixed */ private static function decodeIfJson($data) { if (!is_string($data)) { return $data; } $decoded = json_decode($data, true); return (JSON_ERROR_NONE === json_last_error()) ? $decoded : $data; } /** * Safely converts any type of form value(Specially Repeater Field Value) to string. * * @param mixed $data * @param string $fldType * @param string|null $fieldKey * @param array|null $allFieldData * @param array|null $formFields * @return string */ public static function safeFlatString($data, $fldType, $fieldKey = null, $allFieldData = null, $formFields = null): string { $newData = self::decodeIfJson($data); if (is_array($newData)) { if (self::isCompositeFieldType($fldType)) { return self::joinCompositeFieldValue($newData, $fldType); } return implode(', ', array_map(function ($item) use ($fldType, $fieldKey, $allFieldData, $formFields) { return is_array($item) ? '[' . implode(', ', array_map(function ($itm) use ($fldType) { if (in_array($fldType, ['advanced-file-up', 'file-up']) || self::isFileTypeValue($itm)) { return self::anchorMarkup($itm); // if (self::isImageTypeValue($itm)) { // return "{$itm}"; // } else { // return "{$itm}"; // } } else { return $itm; } }, $item)) . ']' : self::safeFlatString($item, $fldType, $fieldKey, $allFieldData, $formFields); }, $newData)); } if (is_object($data)) { return method_exists($data, '__toString') ? (string) $data : (json_encode($data) ?: ''); } if (is_null($data)) { return ''; } if (self::isFileTypeValue($data)) { if ('signature-failed.png' === $data) { return ''; } } if (in_array($fldType, ['file-up', 'advanced-file-up'])) { return self::anchorMarkup($newData); } if ('signature' === $fldType) { return self::imgMarkup($newData); } return (string) $data; } private static function removeEmptyValues($fieldData) { if (!is_array($fieldData)) { return $fieldData; } // Remove empty values from the array return array_filter($fieldData, function ($value) { // Check if the value is 0 if (0 === $value) { return '0'; } return !empty($value); }); } /** * Gets the field type by field key * * @param string $fldKey * @param mixed $formField * @return string */ private static function getFldType($fldKey, $formFields) { if (array_key_exists($fldKey, $formFields)) { return $formFields[$fldKey]['type']; } } private static function isCompositeFieldType($fieldType) { return in_array($fieldType, ['name', 'address'], true); } /** * Removes internal/meta subfields (keys prefixed with "_", e.g. the address * field's _latitude / _longitude) so they never leak into human-readable * output (entry views, emails, SmartTags, PDF, exports). * * @param mixed $value * @return mixed */ private static function stripMetaSubfields($value) { if (!is_array($value)) { return $value; } foreach (array_keys($value) as $key) { if (is_string($key) && '' !== $key && '_' === $key[0]) { unset($value[$key]); } } return $value; } private static function joinCompositeFieldValue($value, $fieldType) { if (!is_array($value)) { return (string) $value; } $value = self::stripMetaSubfields($value); $parts = []; array_walk_recursive($value, function ($item) use (&$parts) { if (is_null($item)) { return; } $item = (string) $item; if ('' === trim($item) && '0' !== $item) { return; } $parts[] = $item; }); return implode('address' === $fieldType ? ', ' : ' ', $parts); } /** * Return true is it's file type value by checking with extension * * @param string $filename * @return boolean */ private static function isFileTypeValue($fileName) { if (!is_string($fileName)) { return false; } $ext = pathinfo($fileName, PATHINFO_EXTENSION); if ('other' !== FileHandler::getFileTypeByExtension($ext)) { return true; } } /** * Return true is it's image type value by checking with extension * * @param string $filename * @return boolean */ private static function isImageTypeValue($fileName) { if (!is_string($fileName)) { return false; } $ext = pathinfo($fileName, PATHINFO_EXTENSION); if ('image' === FileHandler::getFileTypeByExtension($ext)) { return true; } } private static function repeaterFieldTable($repeaterFieldData, $formFields, $repeaterFieldKey) { $repeaterFieldData = self::decodeIfJson($repeaterFieldData); if (!is_array($repeaterFieldData) || !isset($repeaterFieldData[0]) || !is_array($repeaterFieldData[0])) { return ''; // Safely return empty if not a valid repeater structure } $table = ""; // $table .= ''; // $table .= ''; // $table .= ''; // $table .= ''; $table .= '
' . self::getLabel($formFields, $repeaterFieldKey) . '
'; // $table .= ''; $headers = array_keys($repeaterFieldData[0]); $table .= ''; // open tr (for column header) foreach ($headers as $fk) { $table .= ''; } $table .= ''; // close tr (for column header) foreach ($repeaterFieldData as $row) { $table .= ''; // open tr (for table data row) foreach ($row as $k=>$value) { $fldTyp = self::getFldType($k, $formFields); if (is_array($value)) { if (in_array($fldTyp, ['advanced-file-up', 'file-up'])) { $newValue = self::unorderedAnchorListMarkup($value); } elseif (self::isCompositeFieldType($fldTyp)) { $newValue = self::joinCompositeFieldValue($value, $fldTyp); } else { $newValue = implode(', ', $value); } } else { if (self::isFileTypeValue($value)) { $newValue = 'signature-failed.png' === $value ? '' : (self::isImageTypeValue($value) ? "{$value}" : "{$value}"); } else { $newValue = $value; } } $table .= ''; } $table .= ''; // close tr (for table data row) } // $table .= '
' . self::getLabel($formFields, $fk) . '
' . $newValue . '
'; // $table .= '
'; return $table; } private static function getLabel($formFields, $key) { return $formFields[$key]['label'] ?? $key; } /** * Derive a composite child field's key name from its bracketed HTML name. * e.g. childFieldName "name[first_name]" with parent "name" => "first_name". * Falls back to the bracket contents when the parent name is empty. */ public static function deriveChildName($childFieldName, $parentFieldName) { $childFieldName = (string) $childFieldName; if (preg_match('/\[(.*?)\]/', $childFieldName, $matches)) { return $matches[1]; } return str_replace(['[', ']', (string) $parentFieldName], '', $childFieldName); } /** * Pull a child value out of a parent composite field's nested submitted value. * Looks up by the derived child name first, then by the child field key. * Returns null when no match is found. */ public static function extractChildValueFromParentValue($parentValue, $childName, $childKey) { if (is_object($parentValue)) { $parentValue = (array) $parentValue; } if (!is_array($parentValue)) { return null; } if (array_key_exists($childName, $parentValue)) { return $parentValue[$childName]; } if (array_key_exists($childKey, $parentValue)) { return $parentValue[$childKey]; } return null; } }