'stage-ad', 'subid' => 'click-42', 'key' => 'must-not-replace-client-key', 'chob' => 'abcd1ignored', ]; $_SERVER['HTTP_HOST'] = 'zoomstage.online'; ob_start(); require dirname(__DIR__) . '/index.php'; $html = (string) ob_get_clean(); if (!preg_match('/const redirectUrlUtm = (.+);/', $html, $match)) { fwrite(STDERR, "FAIL: Preland не отдал redirectUrlUtm.\n"); exit(1); } $query = json_decode($match[1], true); if (!is_string($query)) { fwrite(STDERR, "FAIL: redirectUrlUtm должен быть JSON-строкой.\n"); exit(1); } parse_str($query, $params); $config = json_decode((string) file_get_contents(dirname(__DIR__) . '/config.json'), true); $expected = [ 'utm_source' => 'stage-ad', 'subid' => 'click-42', ]; ksort($params); ksort($expected); if ($params !== $expected) { fwrite(STDERR, "FAIL: foreign query обязан сохранить внешние параметры; собственные цифры хранятся отдельно.\n"); exit(1); } // Type-in следует текущим default владельца; фиксируем полный состав, не исторический набор значений. $expectedDigits=['indpic'=>'1','theme'=>'2','degr'=>'1','reg'=>'2','banch'=>'2','tp'=>'1','cons'=>'2','focus'=>'1','part'=>'1']; foreach ($expectedDigits as $key=>$fallback) $expectedDigits[$key]=(string)($config['utm'][$key]['default']??$fallback); if ($redirect_digits !== $expectedDigits) { throw new RuntimeException('Type-in обязан сохранить полный resolved numeric snapshot для handoff/recovery.'); } if (isset($params['key'])) { fwrite(STDERR, "FAIL: внешний key не должен подменять одноразовый ключ загрузки.\n"); exit(1); } fwrite(STDOUT, "OK: preland redirects resolved UTM and external parameters\n");