';
if (cvv_mu_cookie_ok()) {
echo '
';
}
else {
$tree_src = '/images/tree.png?vibes=madchill';
echo '';
echo '';
echo '';
echo '
';
echo '';
}
echo '';
}
function cvv_echo_site_copyright() {
echo '© '.(int) date('Y').' Chill Vibes Villa
';
}
function cvv_echo_site_bottom_block() {
echo '';
cvv_echo_site_copyright();
cvv_echo_site_auth_footer();
echo '
';
}
function mup($text = '', $exit = '') {
global $userdata, $staging_mode, $advanced_mode;
if (mu()) {
$backtrace = debug_backtrace();
echo ''.($exit ? 'Stopping at ' : '').str_replace('staging/', '', str_replace(ROOT_DIR, '', $backtrace[0]['file'])).' line '.$backtrace[0]['line'].($backtrace[1]['function'] ? ' '.$backtrace[1]['function'].'()' : '').'
';
if (!isset($text)) {
if (!$exit) echo 'empty'.$text.'
';
}
else {
$result = print_r($text, TRUE);
if (!is_array($text)) echo ''.$result.'
';
else echo '
';
}
if ($exit) {
global $sitedata;
require_once("footer.html");
exit;
}
}
}
// ========== Minimal db_connect + coolquery + hotquery ==========
$database_connection = null;
function db_connect() {
global $database_connection;
$database_connection = mysqli_connect(CVV_DB_HOST, CVV_DB_USER, CVV_DB_PASS, CVV_DB_NAME);
if (!$database_connection) {
header('HTTP/1.1 500 Internal Server Error');
$error_msg = mysqli_connect_error();
$error_num = mysqli_connect_errno();
mup("Database connection failed!");
mup("Error #$error_num: $error_msg");
mup("PHP mysqli extension loaded: ".(extension_loaded('mysqli') ? 'YES' : 'NO'));
echo 'DB errorDatabase connection failed!
';
exit;
}
mysqli_set_charset($database_connection, 'utf8mb4');
}
function vsql($s) {
global $database_connection;
return mysqli_real_escape_string($database_connection, (string) $s);
}
/**
* @param string $sql
* @param string|int $onlygetonerow truthy => append LIMIT 1, return one assoc or false
*/
function coolquery($sql, $onlygetonerow = '') {
global $database_connection;
if ($onlygetonerow) {
$sql .= ' LIMIT 1';
}
$res = mysqli_query($database_connection, $sql);
if (!$res) {
return $onlygetonerow ? false : array();
}
if ($onlygetonerow) {
$row = mysqli_fetch_assoc($res);
mysqli_free_result($res);
return $row ? $row : false;
}
$out = array();
while ($row = mysqli_fetch_assoc($res)) {
$out[] = $row;
}
mysqli_free_result($res);
return $out;
}
function hotquery($query) {
global $database_connection;
return mysqli_query($database_connection, $query);
}
/** Relative time helper (from umd.net functions.html). Optional global $user_time_zone (hours from GMT) if set. */
function time_since($mktime, $dont_show_old_times = '', $no_html = '', $all_relative = '', $pure_date = '', $allow_compact = '', $ucfirst = '') {
global $user_time_zone;
if (isset($user_time_zone)) {
$time_zone_corrected_timestamp = $mktime + ($user_time_zone * 3600);
$time_zone_corrected_timestamp = $time_zone_corrected_timestamp - date('Z') + (date('I') * 3600);
}
else {
$time_zone_corrected_timestamp = $mktime;
}
if ($pure_date) {
$howold = date('n/j/y', ($time_zone_corrected_timestamp));
$howold_short = $howold;
}
else {
$seconds_since = time() - $mktime;
$in = '';
if ($seconds_since < 0) {
$in = 'in ';
$seconds_since = abs($seconds_since);
$ago = '';
}
elseif ($all_relative) {
$ago = '';
}
else {
$ago = ' ago';
}
if ($seconds_since < 5) {
$howold = 'just now';
$howold_short = 'now';
}
elseif ($seconds_since < 60) {
$rounded_seconds_since = round($seconds_since);
$howold = $in.$rounded_seconds_since.' sec'.($rounded_seconds_since != 1 ? 's' : '').$ago;
$howold_short = $rounded_seconds_since.'s';
}
elseif ($seconds_since < 3600) {
$rounded_seconds_since = round(($seconds_since / 60) - .25);
$howold = $in.$rounded_seconds_since.' min'.($rounded_seconds_since > 1 ? 's' : '').$ago;
$howold_short = $rounded_seconds_since.'m';
}
elseif ($seconds_since < 86400) {
$rounded_seconds_since = round(($seconds_since / 3600) - .25);
$howold = $in.$rounded_seconds_since.' hour'.($rounded_seconds_since > 1 ? 's' : '').$ago;
$howold_short = $rounded_seconds_since.'h';
}
elseif (is_yesterday($mktime) || is_tomorrow($mktime)) {
if ((date('d', $mktime) != date('d')) && !$all_relative) {
$rounded_seconds_since = round(($seconds_since / 3600) - .25);
if ($in) {
$howold = 'tomorrow';
$howold_short = $rounded_seconds_since.'h';
}
else {
$howold = 'yesterday';
$howold_short = $rounded_seconds_since.'h';
}
}
else {
$howold = $in.ceil($seconds_since / 3600).' hour'.(floor($seconds_since / 3600) > 1 ? 's' : '').$ago;
$howold_short = ceil($seconds_since / 3600).'h';
}
}
elseif ($seconds_since < 518400 && !$all_relative) {
$howold = ($in == 'in ' ? 'this ' : '').strtolower(date('l', ($mktime)));
$howold_short = substr($howold, 0, 3);
}
elseif ($seconds_since < 2592000) {
$units = $seconds_since / 86400;
$floored_units = round($units);
$howold = $in.$floored_units.' day'.($floored_units > 1 ? 's' : '').$ago;
$howold_short = $floored_units.'d';
}
else {
if ($all_relative) {
if ($seconds_since < 31536000) {
$units = $seconds_since / 2592000;
$floored_units = floor($units);
$howold = $in.$floored_units.' month'.($floored_units > 1 ? 's' : '').$ago;
$howold_short = $floored_units.'mo';
}
else {
$units = $seconds_since / 31536000;
$floored_units = floor($units);
$howold = $in.$floored_units;
if (($units - $floored_units) > .5) {
$howold .= ' ½';
$howold .= ' years'.$ago;
$howold_short = $floored_units.'.5y';
}
else {
$howold .= ' year'.($floored_units > 1 ? 's' : '').$ago;
$howold_short = $floored_units.'y';
}
}
}
else {
if ($dont_show_old_times) {
return '';
}
else {
$howold = date('n/j/y', ($time_zone_corrected_timestamp));
$howold_short = $howold;
}
}
}
}
if ($ucfirst) {
$howold = ucfirst($howold);
}
if ($no_html) {
return $howold;
}
else {
if ($all_relative) {
if (!$allow_compact) {
return ''.$howold.'';
}
return ''.$howold.''.
''.$howold_short.'';
}
if (!$allow_compact) {
return ''.$howold.'';
}
elseif ($allow_compact == 2) {
return ''.$howold_short.'';
}
return ''.$howold.''.
''.$howold_short.'';
}
}
function is_yesterday($mktime) {
$twenty_four_hours_ago = time() + (3600) - 86400;
$yesterday_test = mktime(0, 0, 0, date('m', $mktime), date('d', $mktime), date('Y', $mktime));
$real_yesterday = mktime(0, 0, 0, date('m', $twenty_four_hours_ago), date('d', $twenty_four_hours_ago), date('Y', $twenty_four_hours_ago));
if ($yesterday_test == $real_yesterday) {
return 1;
}
}
function is_tomorrow($mktime) {
global $user_time_zone;
$tz = isset($user_time_zone) ? (int) $user_time_zone : 0;
$in_twenty_four_hours = time() + ($tz * 3600) + 86400;
$tomorrow_test = mktime(0, 0, 0, date('m', $mktime), date('d', $mktime), date('Y', $mktime));
$real_tomorrow = mktime(0, 0, 0, date('m', $in_twenty_four_hours), date('d', $in_twenty_four_hours), date('Y', $in_twenty_four_hours));
if ($tomorrow_test == $real_tomorrow) {
return 1;
}
}
function cvv_media_ensure_dirs() {
$m = __DIR__.'/media';
$t = __DIR__.'/media/thumbs';
if (!is_dir($m)) {
@mkdir($m, 0777, true);
}
if (!is_dir($t)) {
@mkdir($t, 0777, true);
}
@chmod($m, 0777);
@chmod($t, 0777);
}
function cvv_media_thumb_url($basename, $full_web_base, $thumb_web_base) {
if (!is_string($basename) || !preg_match('/^[a-f0-9]{24}\\.[a-z]+$/i', $basename)) {
return '';
}
$tf = __DIR__.'/media/thumbs/'.$basename;
if (is_file($tf)) {
return rtrim($thumb_web_base, '/').'/'.$basename;
}
return rtrim($full_web_base, '/').'/'.$basename;
}
function cvv_media_delete_stored($basename) {
if (!is_string($basename) || !preg_match('/^[a-f0-9]{24}\\.[a-z]+$/i', $basename)) {
return;
}
$p = __DIR__.'/media/'.$basename;
if (is_file($p)) {
@unlink($p);
}
$pt = __DIR__.'/media/thumbs/'.$basename;
if (is_file($pt)) {
@unlink($pt);
}
}
/** Normalize photos_json: legacy string[] or {"files":[],"main":""}. */
function cvv_photos_normalize($raw_json) {
$d = json_decode((string) $raw_json, true);
if (!is_array($d)) {
return array('files' => array(), 'main' => '');
}
if (isset($d['files']) && is_array($d['files'])) {
$files = array();
foreach ($d['files'] as $f) {
if (is_string($f) && preg_match('/^[a-f0-9]{24}\\.[a-z]+$/i', $f)) {
$files[] = $f;
}
}
$files = array_values(array_unique($files));
$main = '';
if (isset($d['main']) && is_string($d['main']) && in_array($d['main'], $files, true)) {
$main = $d['main'];
}
if ($main === '' && $files) {
$main = $files[0];
}
return array('files' => $files, 'main' => $main);
}
$files = array();
foreach ($d as $v) {
if (is_string($v) && preg_match('/^[a-f0-9]{24}\\.[a-z]+$/i', $v)) {
$files[] = $v;
}
}
$files = array_values(array_unique($files));
return array('files' => $files, 'main' => $files[0] ?? '');
}
function cvv_photos_json_encode($files, $main) {
$files = array_values(array_unique(is_array($files) ? $files : array()));
$main = (string) $main;
if ($main === '' || !in_array($main, $files, true)) {
$main = $files[0] ?? '';
}
return json_encode(array('files' => $files, 'main' => $main));
}
function cvv_photos_delete_all_files($files_arr) {
if (!is_array($files_arr)) {
return;
}
foreach ($files_arr as $fn) {
if (is_string($fn) && preg_match('/^[a-f0-9]{24}\\.[a-z]+$/i', $fn)) {
cvv_media_delete_stored($fn);
}
}
}
function cvv_photos_resolve_main($sel, $photos_final, $photos_new) {
$sel = (string) $sel;
$photos_new = is_array($photos_new) ? $photos_new : array();
if ($sel === '__first_new__' && $photos_new) {
return $photos_new[0];
}
if ($sel !== '' && $sel !== '__first__' && $sel !== '__first_new__' && in_array($sel, $photos_final, true)) {
return $sel;
}
return $photos_final[0] ?? '';
}
/** vibe_list row: photos_json + legacy image_filename. */
function cvv_vibe_row_photos($row) {
if (!is_array($row)) {
return array('files' => array(), 'main' => '');
}
$pn = cvv_photos_normalize(isset($row['photos_json']) ? $row['photos_json'] : '[]');
if (empty($pn['files']) && !empty($row['image_filename'])) {
$fn = (string) $row['image_filename'];
if (preg_match('/^[a-f0-9]{24}\\.[a-z]+$/i', $fn)) {
return array('files' => array($fn), 'main' => $fn);
}
}
return $pn;
}
/** Basenames in images/condo/thumbs that have a matching full image in images/condo. */
function cvv_condo_gallery_list() {
$thumb_dir = __DIR__.'/images/condo/thumbs';
$full_dir = __DIR__.'/images/condo';
$out = array();
if (!is_dir($thumb_dir) || !is_dir($full_dir)) {
return $out;
}
$ext_re = '/\.(jpe?g|png|gif|webp)$/i';
foreach (scandir($thumb_dir) as $f) {
if ($f === '.' || $f === '..' || strpos($f, '/') !== false || strpos($f, '\\') !== false) {
continue;
}
if (!preg_match($ext_re, $f)) {
continue;
}
if (!is_file($thumb_dir.'/'.$f) || !is_file($full_dir.'/'.$f)) {
continue;
}
$out[] = $f;
}
natcasesort($out);
return array_values($out);
}
/** Pixel size of square thumbnails on disk (shown at 75px in vibe list). */
define('CVV_THUMB_SQUARE_PX', 150);
function cvv_media_write_thumbnail($src_path, $thumb_path, $image_type) {
if (!extension_loaded('gd') || !function_exists('imagecreatetruecolor')) {
return false;
}
$info = @getimagesize($src_path);
if ($info === false) {
return false;
}
$w = (int) $info[0];
$h = (int) $info[1];
$type = (int) $image_type;
if ($w < 1 || $h < 1) {
return false;
}
switch ($type) {
case IMAGETYPE_JPEG:
$im = @imagecreatefromjpeg($src_path);
break;
case IMAGETYPE_PNG:
$im = @imagecreatefrompng($src_path);
break;
case IMAGETYPE_GIF:
$im = @imagecreatefromgif($src_path);
break;
case IMAGETYPE_WEBP:
if (function_exists('imagecreatefromwebp')) {
$im = @imagecreatefromwebp($src_path);
}
else {
return false;
}
break;
default:
return false;
}
if (!$im) {
return false;
}
$S = (int) CVV_THUMB_SQUARE_PX;
if ($S < 32) {
$S = 75;
}
$scale = max($S / $w, $S / $h);
$cov_w = (int) max(1, round($w * $scale));
$cov_h = (int) max(1, round($h * $scale));
$tmp = imagecreatetruecolor($cov_w, $cov_h);
if (!$tmp) {
imagedestroy($im);
return false;
}
$is_alpha = ($type === IMAGETYPE_PNG || $type === IMAGETYPE_WEBP || $type === IMAGETYPE_GIF);
if ($is_alpha) {
imagealphablending($tmp, false);
imagesavealpha($tmp, true);
$tcol = imagecolorallocatealpha($tmp, 0, 0, 0, 127);
imagefill($tmp, 0, 0, $tcol);
}
else {
$bg = imagecolorallocate($tmp, 255, 255, 255);
imagefill($tmp, 0, 0, $bg);
}
imagealphablending($tmp, true);
imagecopyresampled($tmp, $im, 0, 0, 0, 0, $cov_w, $cov_h, $w, $h);
imagedestroy($im);
$sx = (int) max(0, floor(($cov_w - $S) / 2));
$sy = (int) max(0, floor(($cov_h - $S) / 2));
$dst = imagecreatetruecolor($S, $S);
if (!$dst) {
imagedestroy($tmp);
return false;
}
if ($is_alpha) {
imagealphablending($dst, false);
imagesavealpha($dst, true);
$tcol = imagecolorallocatealpha($dst, 0, 0, 0, 127);
imagefill($dst, 0, 0, $tcol);
}
else {
$bg = imagecolorallocate($dst, 255, 255, 255);
imagefill($dst, 0, 0, $bg);
}
imagecopy($dst, $tmp, 0, 0, $sx, $sy, $S, $S);
imagedestroy($tmp);
$ok = false;
switch ($type) {
case IMAGETYPE_JPEG:
$ok = @imagejpeg($dst, $thumb_path, 88);
break;
case IMAGETYPE_PNG:
$ok = @imagepng($dst, $thumb_path, 6);
break;
case IMAGETYPE_GIF:
$ok = @imagegif($dst, $thumb_path);
break;
case IMAGETYPE_WEBP:
if (function_exists('imagewebp')) {
$ok = @imagewebp($dst, $thumb_path, 88);
}
break;
}
imagedestroy($dst);
return $ok;
}
function cvv_media_save_upload_with_thumb($tmp) {
if (!is_uploaded_file($tmp) || !is_readable($tmp)) {
return false;
}
$info = @getimagesize($tmp);
if ($info === false) {
return false;
}
$allowed = array(IMAGETYPE_JPEG => 'jpg', IMAGETYPE_PNG => 'png', IMAGETYPE_GIF => 'gif');
if (defined('IMAGETYPE_WEBP')) {
$allowed[IMAGETYPE_WEBP] = 'webp';
}
$itype = (int) $info[2];
if (!isset($allowed[$itype])) {
return false;
}
$ext = $allowed[$itype];
$name = bin2hex(random_bytes(12)).'.'.$ext;
cvv_media_ensure_dirs();
$dest = __DIR__.'/media/'.$name;
if (!@move_uploaded_file($tmp, $dest)) {
if (!@copy($tmp, $dest) || !is_file($dest)) {
mup(error_get_last(), 1);
return false;
}
}
$thumb = __DIR__.'/media/thumbs/'.$name;
if (!cvv_media_write_thumbnail($dest, $thumb, $itype)) {
@copy($dest, $thumb);
}
return $name;
}
function cvv_media_web_base() {
global $vibe_self;
$d = dirname(str_replace('\\', '/', $vibe_self));
if ($d === '/' || $d === '.' || $d === '') {
return '/media';
}
return rtrim($d, '/').'/media';
}
function cvv_media_thumb_web_base() {
global $vibe_self;
$d = dirname(str_replace('\\', '/', $vibe_self));
if ($d === '/' || $d === '.' || $d === '') {
return '/media/thumbs';
}
return rtrim($d, '/').'/media/thumbs';
}
db_connect();
function cvv_guestbook_ensure_tables() {
global $database_connection;
mysqli_query($database_connection, "CREATE TABLE IF NOT EXISTS `cvv_guestbook` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`created_at` DATETIME NOT NULL,
`guest_name` VARCHAR(128) NOT NULL,
`visit_when` VARCHAR(255) NOT NULL,
`story` TEXT NOT NULL,
`photos_json` TEXT NOT NULL,
`thedate` INT UNSIGNED NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
KEY `ix_created` (`created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");
cvv_guestbook_ensure_thedate_column();
cvv_guestbook_ensure_thestatus_column();
}
function cvv_guestbook_ensure_thestatus_column() {
global $database_connection;
$res = @mysqli_query($database_connection, "SHOW COLUMNS FROM `cvv_guestbook` LIKE 'thestatus'");
if ($res && mysqli_num_rows($res) > 0) {
mysqli_free_result($res);
return;
}
if ($res) {
mysqli_free_result($res);
}
@mysqli_query($database_connection, "ALTER TABLE `cvv_guestbook` ADD COLUMN `thestatus` TINYINT(1) NOT NULL DEFAULT 1");
}
function cvv_guestbook_ensure_thedate_column() {
global $database_connection;
$res = @mysqli_query($database_connection, "SHOW COLUMNS FROM `cvv_guestbook` LIKE 'thedate'");
if ($res && mysqli_num_rows($res) > 0) {
mysqli_free_result($res);
return;
}
if ($res) {
mysqli_free_result($res);
}
@mysqli_query($database_connection, "ALTER TABLE `cvv_guestbook` ADD COLUMN `thedate` INT UNSIGNED NOT NULL DEFAULT 0");
}
/** Guestbook `thestatus`: 1 = approved (visible to public), 0 = pending. */
function cvv_guestbook_row_is_approved($row) {
if (!is_array($row)) {
return false;
}
return ((int) ($row['thestatus'] ?? 1)) === 1;
}
/** Notify when an entry moves from pending to approved (owner saved with Approved checked). */
function cvv_guestbook_mail_approval_notice($entry_id, $guest_name, $visit_when) {
$to = 'derek@darkcolors.com';
$subject = 'Chill Vibes Villa: Guestbook entry approved';
$guest_name = trim((string) $guest_name);
$visit_when = trim((string) $visit_when);
$body = "A guestbook entry was just approved on Chill Vibes Villa.\r\n\r\n";
$body .= 'Entry ID: '.intval($entry_id)."\r\n";
$body .= 'Guest: '.$guest_name."\r\n";
$body .= 'Stayed: '.$visit_when."\r\n";
$body .= "\r\nOpen the site Guestbook tab (while signed in) to read the full post if needed.\r\n";
$from = 'Chill Vibes Villa ';
$headers = 'From: '.$from."\r\nContent-Type: text/plain; charset=UTF-8";
@mail($to, $subject, $body, $headers);
}
function cvv_vibe_list_ensure_image_column() {
global $database_connection;
$res = @mysqli_query($database_connection, "SHOW COLUMNS FROM `vibe_list` LIKE 'image_filename'");
if ($res && mysqli_num_rows($res) > 0) {
mysqli_free_result($res);
return;
}
if ($res) {
mysqli_free_result($res);
}
@mysqli_query($database_connection, "ALTER TABLE `vibe_list` ADD COLUMN `image_filename` VARCHAR(64) NOT NULL DEFAULT ''");
}
function cvv_vibe_list_ensure_photos_json_column() {
global $database_connection;
$res = @mysqli_query($database_connection, "SHOW COLUMNS FROM `vibe_list` LIKE 'photos_json'");
if ($res && mysqli_num_rows($res) > 0) {
mysqli_free_result($res);
return;
}
if ($res) {
mysqli_free_result($res);
}
@mysqli_query($database_connection, "ALTER TABLE `vibe_list` ADD COLUMN `photos_json` TEXT NOT NULL DEFAULT ''");
}
function cvv_vibe_list_ensure_website_url_column() {
global $database_connection;
$res = @mysqli_query($database_connection, "SHOW COLUMNS FROM `vibe_list` LIKE 'website_url'");
if ($res && mysqli_num_rows($res) > 0) {
mysqli_free_result($res);
return;
}
if ($res) {
mysqli_free_result($res);
}
@mysqli_query($database_connection, "ALTER TABLE `vibe_list` ADD COLUMN `website_url` VARCHAR(512) NOT NULL DEFAULT ''");
}
function cvv_vibe_list_ensure_distance_column() {
global $database_connection;
$res = @mysqli_query($database_connection, "SHOW COLUMNS FROM `vibe_list` LIKE 'distance'");
if ($res && mysqli_num_rows($res) > 0) {
$row = mysqli_fetch_assoc($res);
mysqli_free_result($res);
$type = isset($row['Type']) ? strtolower($row['Type']) : '';
if (preg_match('/^decimal\((\d+),(\d+)\)/', $type, $m)) {
$scale = (int) $m[2];
if ($scale < 2) {
@mysqli_query($database_connection, "ALTER TABLE `vibe_list` MODIFY COLUMN `distance` DECIMAL(8,2) NOT NULL DEFAULT 0");
}
}
return;
}
if ($res) {
mysqli_free_result($res);
}
@mysqli_query($database_connection, "ALTER TABLE `vibe_list` ADD COLUMN `distance` DECIMAL(8,2) NOT NULL DEFAULT 0");
}
function cvv_vibe_list_ensure_thestatus_column() {
global $database_connection;
$res = @mysqli_query($database_connection, "SHOW COLUMNS FROM `vibe_list` LIKE 'thestatus'");
if ($res && mysqli_num_rows($res) > 0) {
mysqli_free_result($res);
return;
}
if ($res) {
mysqli_free_result($res);
}
@mysqli_query($database_connection, "ALTER TABLE `vibe_list` ADD COLUMN `thestatus` TINYINT(1) NOT NULL DEFAULT 1");
}
/** vibe_list `thestatus`: 1 = approved (visible to public), 0 = pending. */
function cvv_vibe_list_row_is_approved($row) {
if (!is_array($row)) {
return false;
}
return ((int) ($row['thestatus'] ?? 1)) === 1;
}
function cvv_vibe_list_ensure_bool_columns($bool_fields) {
global $database_connection;
foreach ($bool_fields as $col) {
if (!is_string($col) || !preg_match('/^[a-z][a-z0-9_]*$/', $col)) {
continue;
}
$esc = mysqli_real_escape_string($database_connection, $col);
$res = @mysqli_query($database_connection, "SHOW COLUMNS FROM `vibe_list` LIKE '$esc'");
if ($res && mysqli_num_rows($res) > 0) {
mysqli_free_result($res);
continue;
}
if ($res) {
mysqli_free_result($res);
}
@mysqli_query($database_connection, "ALTER TABLE `vibe_list` ADD COLUMN `".$col."` TINYINT(1) NOT NULL DEFAULT 0");
}
}
$userdata = array('permissions' => array('manage_directory' => array(1 => true)));
$sitedata = array('id' => 1, 'rue' => '');
$cvv_script = basename($_SERVER['SCRIPT_NAME'] ?? 'index.html');
$cvv_dir = dirname(str_replace('\\', '/', $_SERVER['SCRIPT_NAME'] ?? '/'));
$vibe_self = ($cvv_dir === '/' || $cvv_dir === '.') ? '/'.$cvv_script : rtrim($cvv_dir, '/').'/'.$cvv_script;
if (isset($vibe_self[0]) && $vibe_self[0] !== '/') {
$vibe_self = '/'.$vibe_self;
}
/** Clean URL base (no .html), e.g. /index → https://chillvibesvilla.com/index/guestbook */
$cvv_dir_slash = dirname(str_replace('\\', '/', $_SERVER['SCRIPT_NAME'] ?? '/'));
$CVV_CLEAN_BASE = ($cvv_dir_slash === '/' || $cvv_dir_slash === '.') ? '/index' : rtrim($cvv_dir_slash, '/').'/index';
/**
* Tab URLs: /index (vibes), /index/guestbook, /index/info. Optional: /index/vibes.
*/
function cvv_url_for_tab($tab) {
global $CVV_CLEAN_BASE;
$tab = strtolower(trim((string) $tab));
if ($tab === 'vibes' || $tab === '' || $tab === 'vibez') {
return $CVV_CLEAN_BASE;
}
if ($tab === 'guestbook' || $tab === 'info') {
return $CVV_CLEAN_BASE.'/'.$tab;
}
return $CVV_CLEAN_BASE;
}
/**
* Map REQUEST_URI to tab: primary /index/{guestbook|info|vibes}; legacy /guestbook and index.html paths.
*/
function cvv_path_tab_from_request() {
global $CVV_CLEAN_BASE;
$path = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH);
$path = '/' . trim((string) $path, '/');
$base = $CVV_CLEAN_BASE;
if ($base === '' || (isset($base[0]) && $base[0] !== '/')) {
$base = '/' . ltrim($base, '/');
}
$base = rtrim($base, '/');
if ($path === $base || $path === $base . '/') {
return 'vibes';
}
$prefix = $base . '/';
if (strpos($path, $prefix) === 0) {
$rest = substr($path, strlen($prefix));
$seg = strtolower(trim(explode('/', $rest)[0], '/'));
if ($seg === 'guestbook') {
return 'guestbook';
}
if ($seg === 'info') {
return 'info';
}
if ($seg === 'vibes' || $seg === 'vibez') {
return 'vibes';
}
return '';
}
$path_trim = trim($path, '/');
if ($path_trim === '') {
return '';
}
$segs = explode('/', $path_trim);
$last = strtolower(end($segs));
if ($last === 'index.html' || preg_match('/\.html$/i', $last)) {
if (count($segs) >= 2) {
$prev = strtolower($segs[count($segs) - 2]);
if ($prev === 'guestbook' || $prev === 'info' || $prev === 'vibes' || $prev === 'vibez') {
return $prev === 'vibez' ? 'vibes' : $prev;
}
}
return '';
}
if ($last === 'guestbook' || $last === 'info' || $last === 'vibes' || $last === 'vibez') {
return $last === 'vibez' ? 'vibes' : $last;
}
return '';
}
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['cvv_site_logout'])) {
$secure = !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off';
setcookie(CVV_MU_COOKIE, '', time() - 3600, '/', '', $secure, true);
$redir = cvv_url_for_tab('vibes');
$ar = $_POST['cvv_auth_return'] ?? '';
if (is_string($ar) && $ar !== '' && isset($ar[0]) && $ar[0] === '/') {
$redir = $ar;
}
header('Location: '.$redir);
exit;
}
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['cvv_site_auth'])) {
$pw = (string) ($_POST['cvv_site_pw'] ?? '');
$secure = !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off';
if (hash_equals(CVV_MU_PASS, $pw)) {
setcookie(CVV_MU_COOKIE, CVV_MU_PASS, time() + 31536000, '/', '', $secure, true);
}
else {
setcookie(CVV_MU_COOKIE, '', time() - 3600, '/', '', $secure, true);
}
$redir = cvv_url_for_tab('vibes');
$ar = $_POST['cvv_auth_return'] ?? '';
if (is_string($ar) && $ar !== '' && isset($ar[0]) && $ar[0] === '/') {
$redir = $ar;
}
header('Location: '.$redir);
exit;
}
/** Allowed `vibe_list.category` values (varchar: store this exact string). */
$cvv_vibe_categories = array(
'restaurants / bars',
'attractions',
'shopping',
);
/** Legacy tinyint IDs still in DB until rows are updated. */
function cvv_vibe_category_legacy_id_to_name($n) {
$map = array(
1 => 'restaurants / bars',
2 => 'attractions',
3 => 'shopping',
);
$n = (int) $n;
return isset($map[$n]) ? $map[$n] : '';
}
/**
* Return canonical whitelist string for DB/display, or '' if n/a / unknown POST.
* Accepts legacy numeric 1–3 from old schema.
*/
function cvv_vibe_category_normalize($raw) {
global $cvv_vibe_categories;
if ($raw === '' || $raw === null) {
return '';
}
$s = trim((string) $raw);
if ($s === '') {
return '';
}
if (ctype_digit($s)) {
$legacy = cvv_vibe_category_legacy_id_to_name((int) $s);
if ($legacy !== '' && in_array($legacy, $cvv_vibe_categories, true)) {
return $legacy;
}
return '';
}
$sl = strtolower($s);
foreach ($cvv_vibe_categories as $allowed) {
if (strtolower($allowed) === $sl) {
return $allowed;
}
}
return '';
}
$addnew = !empty($_GET['addnew']);
$vibe_id = isset($_GET['vibe_id']) ? intval($_GET['vibe_id']) : 0;
$delete_id = isset($_GET['delete']) ? intval($_GET['delete']) : 0;
$confirm_delete = !empty($_GET['confirm']);
$return = isset($_GET['return']) ? (string) $_GET['return'] : cvv_url_for_tab('vibes');
if ($return === '' || $return[0] !== '/') {
$return = cvv_url_for_tab('vibes');
}
$gb_delete_id = isset($_GET['gbdel']) ? intval($_GET['gbdel']) : 0;
$gb_confirm = !empty($_GET['gbconfirm']);
$gb_edit_id_get = isset($_GET['gbedit']) ? intval($_GET['gbedit']) : 0;
$gb_edit_row = null;
if (mu() && $gb_edit_id_get > 0) {
cvv_guestbook_ensure_tables();
$gb_edit_row = coolquery("SELECT * FROM `cvv_guestbook` WHERE id='".$gb_edit_id_get."'", 1);
if (!is_array($gb_edit_row)) {
$gb_edit_row = null;
$gb_edit_id_get = 0;
}
}
if (mu() && $gb_delete_id && $gb_confirm) {
cvv_guestbook_ensure_tables();
$row = coolquery("SELECT photos_json FROM `cvv_guestbook` WHERE id='".$gb_delete_id."'", 1);
if (is_array($row)) {
$pn = cvv_photos_normalize($row['photos_json'] ?? '[]');
cvv_photos_delete_all_files($pn['files']);
hotquery("DELETE FROM `cvv_guestbook` WHERE id='".$gb_delete_id."' LIMIT 1");
}
header('Location: '.cvv_url_for_tab('guestbook'));
exit;
}
$guestbook_err = '';
if (isset($_POST['guestbook_save'])) {
if (mu()) {
cvv_guestbook_ensure_tables();
}
if (!empty($_POST['gb_company'])) {
header('Location: '.cvv_url_for_tab('guestbook'));
exit;
}
$gname = trim((string) ($_POST['gb_name'] ?? ''));
$gwhen = trim((string) ($_POST['gb_when'] ?? ''));
$gstory = trim((string) ($_POST['gb_story'] ?? ''));
$slen = function_exists('mb_strlen') ? 'mb_strlen' : 'strlen';
if ($gname === '' || $slen($gname) > 120) {
$guestbook_err = 'Please enter your name (120 characters or fewer).';
}
elseif ($gwhen === '' || $slen($gwhen) > 255) {
$guestbook_err = 'Please say when you stayed (255 characters or fewer).';
}
elseif ($gstory === '' || $slen($gstory) > 12000) {
$guestbook_err = 'Please share a short story about your visit (12,000 characters or fewer).';
}
else {
cvv_media_ensure_dirs();
$photos_saved = array();
$max_photos = 5;
$max_bytes = 10 * 1024 * 1024;
global $database_connection;
$gb_entry_id = isset($_POST['gb_entry_id']) ? intval($_POST['gb_entry_id']) : 0;
if ($gb_entry_id > 0 && !mu()) {
$gb_entry_id = 0;
}
$gb_is_update = ($gb_entry_id > 0 && mu());
if ($gb_is_update) {
$gb_existing = coolquery("SELECT * FROM `cvv_guestbook` WHERE id='".$gb_entry_id."'", 1);
if (!is_array($gb_existing)) {
$guestbook_err = 'Could not find that guestbook entry.';
}
else {
$photos_kept = array();
$pn_existing = cvv_photos_normalize($gb_existing['photos_json'] ?? '[]');
$photos_existing = $pn_existing['files'];
$del_raw = $_POST['gb_photo_delete'] ?? array();
if (!is_array($del_raw)) {
$del_raw = array($del_raw);
}
foreach ($photos_existing as $pfn) {
if (!is_string($pfn) || !preg_match('/^[a-f0-9]{24}\\.[a-z]+$/i', $pfn)) {
continue;
}
if (in_array($pfn, $del_raw, true)) {
cvv_media_delete_stored($pfn);
continue;
}
$photos_kept[] = $pfn;
}
$photos_final = $photos_kept;
$photos_new_upload = array();
if (!empty($_FILES['gb_photos']) && is_array($_FILES['gb_photos']['tmp_name'])) {
$n = count($_FILES['gb_photos']['tmp_name']);
for ($i = 0; $i < $n && count($photos_final) < $max_photos; $i++) {
if (empty($_FILES['gb_photos']['tmp_name'][$i])) {
continue;
}
if ($_FILES['gb_photos']['error'][$i] !== UPLOAD_ERR_OK) {
if ($_FILES['gb_photos']['error'][$i] !== UPLOAD_ERR_NO_FILE) {
$guestbook_err = 'One of the uploads failed. Try again with smaller images.';
}
break;
}
if ($_FILES['gb_photos']['size'][$i] > $max_bytes) {
$guestbook_err = 'Each photo must be 4MB or smaller.';
break;
}
$saved = cvv_media_save_upload_with_thumb($_FILES['gb_photos']['tmp_name'][$i]);
if ($saved === false) {
$guestbook_err = 'Photos must be JPEG, PNG, GIF, or WebP.';
break;
}
$photos_final[] = $saved;
$photos_saved[] = $saved;
$photos_new_upload[] = $saved;
}
}
if ($guestbook_err === '') {
$gb_main = (string) ($_POST['gb_main'] ?? '__first__');
$main_fn = cvv_photos_resolve_main($gb_main, $photos_final, $photos_new_upload);
$gj = vsql(cvv_photos_json_encode($photos_final, $main_fn));
$gname_ = vsql(substr($gname, 0, 120));
$gwhen_ = vsql(substr($gwhen, 0, 255));
$gstory_ = vsql($gstory);
$gb_thestatus = !empty($_POST['gb_approved']) ? 1 : 0;
$gb_prev_status = (int) ($gb_existing['thestatus'] ?? 1);
$upd_sql = "UPDATE `cvv_guestbook` SET guest_name='$gname_', visit_when='$gwhen_', story='$gstory_', photos_json='$gj', thestatus='".intval($gb_thestatus)."' WHERE id='".$gb_entry_id."' LIMIT 1";
if (mysqli_query($database_connection, $upd_sql)) {
if ($gb_prev_status === 0 && $gb_thestatus === 1) {
cvv_guestbook_mail_approval_notice($gb_entry_id, $gname, $gwhen);
}
header('Location: '.cvv_url_for_tab('guestbook').'?updated=1');
exit;
}
$guestbook_err = 'Could not save guestbook entry. '.mysqli_error($database_connection);
}
if ($guestbook_err !== '') {
foreach ($photos_saved as $fn) {
if (is_string($fn) && preg_match('/^[a-f0-9]{24}\\.[a-z]+$/i', $fn)) {
cvv_media_delete_stored($fn);
}
}
}
}
}
else {
if (!empty($_FILES['gb_photos']) && is_array($_FILES['gb_photos']['tmp_name'])) {
$n = count($_FILES['gb_photos']['tmp_name']);
for ($i = 0; $i < $n && count($photos_saved) < $max_photos; $i++) {
if (empty($_FILES['gb_photos']['tmp_name'][$i])) {
continue;
}
if ($_FILES['gb_photos']['error'][$i] !== UPLOAD_ERR_OK) {
if ($_FILES['gb_photos']['error'][$i] !== UPLOAD_ERR_NO_FILE) {
$guestbook_err = 'One of the uploads failed. Try again with smaller images.';
}
break;
}
if ($_FILES['gb_photos']['size'][$i] > $max_bytes) {
$guestbook_err = 'Each photo must be 4MB or smaller.';
break;
}
$saved = cvv_media_save_upload_with_thumb($_FILES['gb_photos']['tmp_name'][$i]);
if ($saved === false) {
$guestbook_err = 'Photos must be JPEG, PNG, GIF, or WebP.';
break;
}
$photos_saved[] = $saved;
}
}
if ($guestbook_err === '') {
$gb_main = (string) ($_POST['gb_main'] ?? '__first__');
$main_fn = cvv_photos_resolve_main($gb_main, $photos_saved, $photos_saved);
$gj = vsql(cvv_photos_json_encode($photos_saved, $main_fn));
$gname_ = vsql(substr($gname, 0, 120));
$gwhen_ = vsql(substr($gwhen, 0, 255));
$gstory_ = vsql($gstory);
$now = date('Y-m-d H:i:s');
$gb_thedate = time();
$gb_thestatus_ins = (mu() && !empty($_POST['gb_approved'])) ? 1 : 0;
$ins_sql = "INSERT INTO `cvv_guestbook` (created_at, guest_name, visit_when, story, photos_json, thedate, thestatus) VALUES ('$now', '$gname_', '$gwhen_', '$gstory_', '$gj', ".intval($gb_thedate).", ".intval($gb_thestatus_ins).")";
if (mysqli_query($database_connection, $ins_sql)) {
header('Location: '.cvv_url_for_tab('guestbook').'?posted=1');
exit;
}
$guestbook_err = 'Could not save guestbook entry. '.mysqli_error($database_connection);
}
if ($guestbook_err !== '') {
foreach ($photos_saved as $fn) {
if (is_string($fn) && preg_match('/^[a-f0-9]{24}\\.[a-z]+$/i', $fn)) {
cvv_media_delete_stored($fn);
}
}
}
}
}
}
if ($guestbook_err !== '' && mu()) {
$eid = intval($_POST['gb_entry_id'] ?? 0);
if ($eid > 0) {
cvv_guestbook_ensure_tables();
$row_reload = coolquery("SELECT * FROM `cvv_guestbook` WHERE id='".$eid."'", 1);
if (is_array($row_reload)) {
$gb_edit_row = $row_reload;
}
}
}
// --- vibe_list (same as test.html) ---
$vibe_list_saved = '';
$vibe_list_bool_fields = array(
'rooftop_dining', 'outdoor_dining', 'oceanfront', 'for_families',
'live_music', 'djays', 'lounge', 'karaoke', 'brunch', 'breakfast', 'late_night_food',
'coffee_shops', 'blue_crabs', 'rainy_day', 'action_packed',
);
$vibe_list_crab_sql = '`crab legs`';
if (mu()) {
cvv_vibe_list_ensure_image_column();
cvv_vibe_list_ensure_photos_json_column();
cvv_vibe_list_ensure_website_url_column();
cvv_vibe_list_ensure_distance_column();
cvv_vibe_list_ensure_thestatus_column();
cvv_vibe_list_ensure_bool_columns($vibe_list_bool_fields);
}
$cvv_vibe_rating_words = array(
1 => 'quirky',
2 => 'swanky',
3 => 'festive',
4 => 'laid back',
5 => 'mad chill',
7 => 'upscale',
8 => 'dive-y',
13 => 'rustic',
15 => 'intimate',
20 => 'energetic',
);
$cvv_overall_rating_words = array(
1 => 'great',
2 => 'really great',
3 => 'excellent',
4 => 'elite',
5 => 'mind-blowing',
);
// Handle delete
if ($delete_id && $confirm_delete) {
$del_row = coolquery("SELECT image_filename, photos_json FROM `vibe_list` WHERE id = '".intval($delete_id)."'", 1);
if (is_array($del_row)) {
$pn = cvv_vibe_row_photos($del_row);
cvv_photos_delete_all_files($pn['files']);
}
hotquery("DELETE FROM `vibe_list` WHERE id = '".intval($delete_id)."' LIMIT 1");
header('Location: '.$return);
exit;
}
if (isset($_POST['vibe_list_save'])) {
global $database_connection;
$vibe_post_id = isset($_POST['vibe_id']) ? intval($_POST['vibe_id']) : 0;
$vibe_name = vsql(substr($_POST['name'] ?? '', 0, 64));
$cat_post_raw = isset($_POST['category']) ? trim((string) $_POST['category']) : '';
$vibe_cat_norm = cvv_vibe_category_normalize($cat_post_raw);
if ($vibe_cat_norm === '' && !empty($cvv_vibe_categories)) {
$vibe_cat_norm = $cvv_vibe_categories[0];
}
$vibe_category_sql = vsql(substr($vibe_cat_norm, 0, 128));
$vibe_address = vsql($_POST['address'] ?? '');
$raw_web = trim((string) ($_POST['website_url'] ?? ''));
if ($raw_web !== '') {
if (!preg_match('#^https?://#i', $raw_web)) {
$raw_web = 'https://'.$raw_web;
}
if (!preg_match('#^https?://\\S+#i', $raw_web)) {
$raw_web = '';
}
}
$vibe_website_sql = vsql(substr($raw_web, 0, 512));
$dist_raw = trim((string) ($_POST['distance'] ?? ''));
$vibe_dist = 0.0;
if ($dist_raw !== '' && is_numeric($dist_raw)) {
$vibe_dist = max(0.0, min(9999.99, round((float) $dist_raw, 2)));
}
$vibe_distance_sql = vsql(number_format($vibe_dist, 2, '.', ''));
$vibe_summary = vsql($_POST['summary'] ?? '');
$vibe_review = vsql($_POST['review'] ?? '');
$vibe_cost = vsql(substr($_POST['cost_level'] ?? '', 0, 1));
$vr_raw = (string) ($_POST['vibe_rating'] ?? '');
$vr_num = cvv_vibe_rating_num_from_raw($vr_raw, $cvv_vibe_rating_words);
$vibe_vrating = ($vr_num !== null) ? vsql((string) $vr_num) : '';
$or_raw = (string) ($_POST['overall_rating'] ?? '');
$or_num = cvv_vibe_rating_num_from_raw($or_raw, $cvv_overall_rating_words);
$vibe_orating = ($or_num !== null) ? vsql((string) $or_num) : '';
$vibe_crab = !empty($_POST['crab_legs']) ? 1 : 0;
$max_photos = 5;
$max_bytes = 4 * 1024 * 1024;
$photos_saved = array();
$photos_new_upload = array();
$photos_kept = array();
if ($vibe_post_id) {
$cur_img = coolquery("SELECT image_filename, photos_json FROM `vibe_list` WHERE id='".$vibe_post_id."'", 1);
$pn_cur = cvv_vibe_row_photos(is_array($cur_img) ? $cur_img : array());
$photos_existing = $pn_cur['files'];
$del_raw = $_POST['vibe_photo_delete'] ?? array();
if (!is_array($del_raw)) {
$del_raw = array($del_raw);
}
foreach ($photos_existing as $pfn) {
if (!is_string($pfn) || !preg_match('/^[a-f0-9]{24}\\.[a-z]+$/i', $pfn)) {
continue;
}
if (in_array($pfn, $del_raw, true)) {
cvv_media_delete_stored($pfn);
continue;
}
$photos_kept[] = $pfn;
}
}
$photos_final = $photos_kept;
if (!empty($_FILES['vibe_photos']) && is_array($_FILES['vibe_photos']['tmp_name'])) {
cvv_media_ensure_dirs();
$n = count($_FILES['vibe_photos']['tmp_name']);
for ($i = 0; $i < $n && count($photos_final) < $max_photos; $i++) {
if (empty($_FILES['vibe_photos']['tmp_name'][$i])) {
continue;
}
if ($_FILES['vibe_photos']['error'][$i] !== UPLOAD_ERR_OK) {
if ($_FILES['vibe_photos']['error'][$i] !== UPLOAD_ERR_NO_FILE) {
break;
}
continue;
}
if ($_FILES['vibe_photos']['size'][$i] > $max_bytes) {
break;
}
$saved = cvv_media_save_upload_with_thumb($_FILES['vibe_photos']['tmp_name'][$i]);
if ($saved === false) {
break;
}
$photos_final[] = $saved;
$photos_saved[] = $saved;
$photos_new_upload[] = $saved;
}
}
$vibe_main = (string) ($_POST['vibe_main'] ?? '__first__');
$main_fn = cvv_photos_resolve_main($vibe_main, $photos_final, $photos_new_upload);
$photos_json_sql = vsql(cvv_photos_json_encode($photos_final, $main_fn));
$img_fn_sql = vsql(substr($main_fn, 0, 64));
$sets = array();
foreach ($vibe_list_bool_fields as $bf) {
$sets[] = "`$bf`='".(isset($_POST[$bf]) && $_POST[$bf] !== '' && $_POST[$bf] !== '0' ? 1 : 0)."'";
}
$sets[] = "$vibe_list_crab_sql='$vibe_crab'";
$bool_sql = implode(', ', $sets);
$vibe_status_sql = '';
if (mu()) {
$vibe_ts = !empty($_POST['vibe_approved']) ? 1 : 0;
$vibe_status_sql = ", thestatus='".intval($vibe_ts)."'";
}
if ($vibe_post_id) {
$q = "UPDATE `vibe_list` SET name='$vibe_name', category='".$vibe_category_sql."', address='$vibe_address', website_url='$vibe_website_sql', distance='".$vibe_distance_sql."', summary='$vibe_summary', review='$vibe_review', $bool_sql, cost_level='$vibe_cost', vibe_rating='$vibe_vrating', overall_rating='$vibe_orating', image_filename='$img_fn_sql', photos_json='$photos_json_sql'".$vibe_status_sql." WHERE id='".$vibe_post_id."' LIMIT 1";
if (!mysqli_query($database_connection, $q)) {
error_log('cvv vibe_list UPDATE failed: '.mysqli_error($database_connection));
foreach ($photos_saved as $fn) {
if (is_string($fn) && preg_match('/^[a-f0-9]{24}\\.[a-z]+$/i', $fn)) {
cvv_media_delete_stored($fn);
}
}
if (mu()) {
header('Location: '.cvv_url_for_tab('vibes').'?vibe_id='.intval($vibe_post_id).'&save_err=1');
}
else {
header('Location: '.cvv_url_for_tab('vibes'));
}
exit;
}
$vibe_id = $vibe_post_id;
}
else {
$next = coolquery("SELECT COALESCE(MAX(id), 0) + 1 AS n FROM `vibe_list`", 1);
$new_id = $next ? intval($next['n']) : 1;
$vals_bool = array();
foreach ($vibe_list_bool_fields as $bf) {
$vals_bool[] = "'".(isset($_POST[$bf]) && $_POST[$bf] !== '' && $_POST[$bf] !== '0' ? 1 : 0)."'";
}
$vals_bool[] = "'$vibe_crab'";
$vibe_thestatus_ins = (mu() && !empty($_POST['vibe_approved'])) ? 1 : 0;
$q = "INSERT INTO `vibe_list` (id, name, category, address, website_url, distance, summary, review, ".implode(', ', array_map(function ($f) { return "`$f`"; }, $vibe_list_bool_fields)).", $vibe_list_crab_sql, cost_level, vibe_rating, overall_rating, image_filename, photos_json, thestatus) VALUES ('$new_id', '$vibe_name', '".$vibe_category_sql."', '$vibe_address', '$vibe_website_sql', '".$vibe_distance_sql."', '$vibe_summary', '$vibe_review', ".implode(', ', $vals_bool).", '$vibe_cost', '$vibe_vrating', '$vibe_orating', '$img_fn_sql', '$photos_json_sql', '".intval($vibe_thestatus_ins)."')";
if (!mysqli_query($database_connection, $q)) {
error_log('cvv vibe_list INSERT failed: '.mysqli_error($database_connection));
foreach ($photos_saved as $fn) {
if (is_string($fn) && preg_match('/^[a-f0-9]{24}\\.[a-z]+$/i', $fn)) {
cvv_media_delete_stored($fn);
}
}
if (mu()) {
header('Location: '.cvv_url_for_tab('vibes').'?addnew=1&save_err=1');
}
else {
header('Location: '.cvv_url_for_tab('vibes'));
}
exit;
}
$vibe_id = $new_id;
}
$redir = isset($_POST['return']) ? (string) $_POST['return'] : cvv_url_for_tab('vibes');
if ($redir === '' || $redir[0] !== '/') {
$redir = cvv_url_for_tab('vibes');
}
header('Location: '.$redir);
exit;
}
$vibe_row = array();
if (!empty($vibe_id)) {
$vibe_row = coolquery("SELECT * FROM `vibe_list` WHERE id = '".intval($vibe_id)."'", 1);
}
if (!is_array($vibe_row)) {
$vibe_row = array();
}
function vibe_list_website_href($stored) {
$u = trim((string) $stored);
if ($u === '') {
return '';
}
if (!preg_match('#^https?://#i', $u)) {
$u = 'https://'.$u;
}
if (!preg_match('#^https?://\\S+#i', $u)) {
return '';
}
return $u;
}
function vibe_list_crab_val($r) {
if (isset($r['crab legs'])) {
return $r['crab legs'];
}
if (isset($r['crab_legs'])) {
return $r['crab_legs'];
}
return '';
}
function vibe_list_chk($r, $k) {
if (!is_array($r) || !array_key_exists($k, $r)) {
return '';
}
return ((int) $r[$k] !== 0) ? ' checked' : '';
}
function cvv_vibe_rating_num_from_raw($raw, $words_map) {
global $cvv_vibe_rating_words;
$s = trim((string) $raw);
if ($s === '') {
return null;
}
if (ctype_digit($s)) {
$n = (int) $s;
if (isset($words_map[$n])) {
return $n;
}
return null;
}
$sl = strtolower($s);
foreach ($words_map as $n => $w) {
if (strtolower((string) $w) === $sl) {
return (int) $n;
}
}
if ($words_map === $cvv_vibe_rating_words) {
$legacy = array(
'solid' => 2,
'thorough' => 3,
'elevated' => 4,
'immaculate' => 5,
);
if (isset($legacy[$sl])) {
return (int) $legacy[$sl];
}
}
return null;
}
/** 1–5 (or label text) → 1–10 scale for trees and sort; legacy 1–10 decimals still supported. */
function cvv_vibe_rating_to_ten($raw, $words_map) {
$s = trim(str_replace(',', '.', (string) $raw));
if ($s === '') {
return 0.0;
}
$n = cvv_vibe_rating_num_from_raw($s, $words_map);
if ($n !== null) {
return (float) $n * 2.0;
}
if (preg_match('/^(10|[1-9])(\.5)?$/', $s)) {
return (float) $s;
}
return 0.0;
}
function cvv_vibe_stars_html($rating_raw, $overall_words_map) {
$ten = cvv_vibe_rating_to_ten($rating_raw, $overall_words_map);
if ($ten <= 0) {
return '';
}
if ($ten > 10) {
$ten = 10.0;
}
$stars = $ten / 2.0;
$lbl = ($ten == floor($ten)) ? (string) (int) $ten : rtrim(rtrim(sprintf('%.1f', $ten), '0'), '.');
$label = 'Our rating '.$lbl.' out of 10';
$tree = '/images/tree.png?vibes=madchill';
$out = '';
for ($i = 1; $i <= 5; $i++) {
if ($stars >= $i) {
$out .= '
';
}
elseif ($stars >= $i - 0.5) {
$out .= '
';
}
else {
$out .= '
';
}
}
$out .= '';
return $out;
}
function cvv_vibe_rating_word_label($words_map, $raw) {
$n = cvv_vibe_rating_num_from_raw($raw, $words_map);
if ($n !== null && isset($words_map[$n])) {
return $words_map[$n];
}
return '';
}
$labels = array(
'rooftop_dining' => 'rooftop', 'outdoor_dining' => 'outdoor dining', 'oceanfront' => 'oceanfront',
'for_families' => 'for families', 'live_music' => 'live music', 'djays' => 'djs', 'lounge' => 'lounge', 'karaoke' => 'karaoke',
'brunch' => 'brunch', 'breakfast' => 'breakfast', 'late_night_food' => 'late night food',
'coffee_shops' => 'coffee shops', 'blue_crabs' => 'blue crabs', 'rainy_day' => 'rainy day', 'action_packed' => 'action-packed', 'crab_legs' => 'crab legs',
);
$current_category = cvv_vibe_category_normalize($vibe_row['category'] ?? '');
?>
Chill Vibes Villa
';
echo 'Delete guestbook entry
';
echo 'Remove this memory from '.($gb_row['guest_name'] ?? 'Unknown').'?
';
$gb_yes = cvv_url_for_tab('guestbook').'?gbdel='.$gb_delete_id.'&gbconfirm=1';
echo 'Yes, delete ';
echo 'Cancel';
echo '';
cvv_echo_site_bottom_block();
echo '';
exit;
}
// Delete confirmation
if ($delete_id && !$confirm_delete) {
$del_item = coolquery("SELECT name FROM `vibe_list` WHERE id = '".intval($delete_id)."'", 1);
echo '';
echo '
Delete Confirmation
';
echo '
Are you sure you want to delete "'.($del_item['name'] ?? 'Unknown').'"?
';
$del_url = cvv_url_for_tab('vibes').'?delete='.intval($delete_id).'&confirm=1&return='.rawurlencode($return);
echo '
Yes, Delete ';
echo '
Cancel';
echo '
';
cvv_echo_site_bottom_block();
echo '