184 lines
6.7 KiB
PHP
184 lines
6.7 KiB
PHP
<?php
|
||
/*
|
||
* EasyStream – JW Player Branding Migration
|
||
* Safely updates serialized JW Player config in `db_fileplayers` to remove legacy ViewShark branding.
|
||
* Usage: php f_scripts/migrations/update_jw_branding.php
|
||
*/
|
||
|
||
define('_ISVALID', true);
|
||
|
||
// Bootstrap core to reuse DB + config
|
||
require_once __DIR__ . '/../../f_core/config.core.php';
|
||
|
||
/**
|
||
* Unserialize safely (no objects), returning array or null
|
||
*/
|
||
function safe_unserialize($str)
|
||
{
|
||
if (!is_string($str) || $str === '') {
|
||
return null;
|
||
}
|
||
// PHP >= 7 allows allowed_classes => false
|
||
$data = @unserialize($str, ['allowed_classes' => false]);
|
||
if ($data === false || !is_array($data)) {
|
||
// Try without options for older compatibility
|
||
$data = @unserialize($str);
|
||
if (!is_array($data)) {
|
||
// Some environments may deliver escaped content from DB; try un-escaping
|
||
$clean = stripslashes($str);
|
||
$data = @unserialize($clean, ['allowed_classes' => false]);
|
||
if ($data === false || !is_array($data)) {
|
||
$data = @unserialize($clean);
|
||
if (!is_array($data)) {
|
||
// Last resort: stripcslashes
|
||
$clean2 = stripcslashes($str);
|
||
$data = @unserialize($clean2, ['allowed_classes' => false]);
|
||
if ($data === false || !is_array($data)) {
|
||
$data = @unserialize($clean2);
|
||
if (!is_array($data)) {
|
||
return null;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return $data;
|
||
}
|
||
|
||
/**
|
||
* Apply branding changes to JW config array
|
||
*/
|
||
function apply_branding(array $cfg, string $siteName, string $siteUrl): array
|
||
{
|
||
$changed = false;
|
||
|
||
$replacements = [
|
||
// Remove external logo file by default; admin can set later from UI
|
||
'jw_logo_file' => '',
|
||
// Point links to local site if available
|
||
'jw_logo_link' => $siteUrl,
|
||
// Update right-click text/link
|
||
'jw_rc_text' => 'Powered by ' . ($siteName ?: 'EasyStream'),
|
||
'jw_rc_link' => $siteUrl,
|
||
];
|
||
|
||
foreach ($replacements as $key => $value) {
|
||
if (array_key_exists($key, $cfg) && $cfg[$key] !== $value) {
|
||
$cfg[$key] = $value;
|
||
$changed = true;
|
||
}
|
||
}
|
||
|
||
// If jw_share_enabled is set, ensure no external domains are hardcoded in share link defaults
|
||
if (isset($cfg['jw_share_link']) && is_string($cfg['jw_share_link'])) {
|
||
// Replace known legacy domains if present
|
||
$legacy = ['viewsharkdemo.com', 'viewshark.com'];
|
||
foreach ($legacy as $dom) {
|
||
if (stripos($cfg['jw_share_link'], $dom) !== false) {
|
||
$cfg['jw_share_link'] = '';
|
||
$changed = true;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
$cfg['__changed__'] = $changed; // marker for caller
|
||
return $cfg;
|
||
}
|
||
|
||
try {
|
||
global $db, $cfg; // from config.core.php
|
||
|
||
if (!isset($db)) {
|
||
throw new Exception('Database connection not initialized.');
|
||
}
|
||
|
||
$siteName = $cfg['site_name'] ?? 'EasyStream';
|
||
$siteUrl = $cfg['site_url'] ?? '';
|
||
|
||
$targets = ['jw_local', 'jw_embed'];
|
||
$updated = 0;
|
||
|
||
foreach ($targets as $name) {
|
||
$rs = $db->Execute("SELECT `db_id`, `db_config` FROM `db_fileplayers` WHERE `db_name` = ? LIMIT 1", [$name]);
|
||
if ($rs && !$rs->EOF) {
|
||
$dbId = (int)$rs->fields['db_id'];
|
||
$raw = $rs->fields['db_config'];
|
||
$arr = safe_unserialize($raw);
|
||
|
||
if (is_array($arr)) {
|
||
$arr = apply_branding($arr, $siteName, $siteUrl);
|
||
$changed = !empty($arr['__changed__']);
|
||
unset($arr['__changed__']);
|
||
|
||
if ($changed) {
|
||
$serialized = serialize($arr);
|
||
$ok = $db->Execute("UPDATE `db_fileplayers` SET `db_config` = ? WHERE `db_id` = ?", [$serialized, $dbId]);
|
||
if ($ok) {
|
||
echo "Updated branding for {$name} (db_id={$dbId})\n";
|
||
$updated++;
|
||
} else {
|
||
echo "Failed to update {$name} (db_id={$dbId}): " . $db->ErrorMsg() . "\n";
|
||
}
|
||
} else {
|
||
echo "No changes needed for {$name}\n";
|
||
}
|
||
} else {
|
||
// Fallback: attempt in-place serialized string rewriting for known keys
|
||
$orig = (string)$raw;
|
||
$updatedSerialized = $orig;
|
||
|
||
$kv = [
|
||
'jw_logo_file' => '',
|
||
'jw_logo_link' => $siteUrl,
|
||
'jw_rc_text' => 'Powered by ' . ($siteName ?: 'EasyStream'),
|
||
'jw_rc_link' => $siteUrl,
|
||
];
|
||
|
||
$didChange = false;
|
||
foreach ($kv as $k => $v) {
|
||
$escapedKey = preg_quote($k, '/');
|
||
$replacement = function ($m) use ($v) {
|
||
$len = strlen($v);
|
||
$safe = str_replace('"', '"', $v); // value is plain; ensure quotes are safe
|
||
return $m[1] . 's:' . $len . ':"' . $safe . '";';
|
||
};
|
||
$pattern = '/(s:\d+:"' . $escapedKey . '";s:)\d+:("[\s\S]*?");/';
|
||
$new = preg_replace_callback($pattern, $replacement, $updatedSerialized, 1, $count);
|
||
if ($count > 0 && is_string($new)) {
|
||
$updatedSerialized = $new;
|
||
$didChange = true;
|
||
}
|
||
}
|
||
|
||
if ($didChange) {
|
||
$ok = $db->Execute("UPDATE `db_fileplayers` SET `db_config` = ? WHERE `db_id` = ?", [$updatedSerialized, $dbId]);
|
||
if ($ok) {
|
||
echo "Updated branding (fallback) for {$name} (db_id={$dbId})\n";
|
||
$updated++;
|
||
} else {
|
||
echo "Failed fallback update {$name} (db_id={$dbId}): " . $db->ErrorMsg() . "\n";
|
||
}
|
||
} else {
|
||
$snippet = substr((string)$raw, 0, 160);
|
||
echo "Could not unserialize config for {$name}; snippet: " . str_replace(["\n","\r"], ['\\n',''], $snippet) . "\n";
|
||
}
|
||
}
|
||
} else {
|
||
echo "No db_fileplayers row found for {$name}; skipping.\n";
|
||
}
|
||
}
|
||
|
||
echo "Done. Updated {$updated} row(s).\n";
|
||
exit(0);
|
||
} catch (Throwable $e) {
|
||
// Best-effort logging
|
||
if (class_exists('VLogger')) {
|
||
$logger = VLogger::getInstance();
|
||
$logger->log(VLogger::ERROR, 'JW branding migration failed', ['error' => $e->getMessage()]);
|
||
}
|
||
fwrite(STDERR, 'Error: ' . $e->getMessage() . "\n");
|
||
exit(1);
|
||
}
|